Skip to content

Commit f814d24

Browse files
committed
Add multipart/form-data file upload and cookie management features
This commit introduces two major features for Transport PHP: ## Feature 1: Multipart/Form-Data File Upload - Add `Part` class for representing multipart form components - Add `MultipartStreamBuilder` for RFC 7578 compliant multipart streams - Add `withMultipart()`, `withFile()`, and `withMultipartBuilder()` methods to RequestBuilder - Support for mixed text fields and file uploads in single request - Automatic content-type detection based on file extensions - Custom boundaries, filenames, and content-types support - PSR-7 StreamInterface compliance for memory-efficient operations ## Feature 2: Cookie Management - Add `Cookie` class with RFC 6265 compliance - Add `CookieJar` for cookie storage with domain/path matching - Add `CookieMiddleware` for automatic cookie handling - Add `withCookies()` and `withCookieJar()` methods to TransportBuilder - Support for session and persistent cookies - Automatic cookie expiration handling - Cookie export/import for persistence - Secure/HttpOnly/SameSite attribute support - Proper domain and path matching algorithms ## Testing & Quality - Add comprehensive test suite (55+ new tests, 330 total passing) - Add practical examples (file-upload.php, cookie-session.php) - Update README with feature documentation and usage examples - PSR-12 code style compliance - Full type safety with PHP 8.1+ strict types ## Breaking Changes None - fully backward compatible with existing code. Closes #24 (if applicable)
1 parent 8ded390 commit f814d24

12 files changed

Lines changed: 2721 additions & 0 deletions

File tree

README.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ A modern, PSR-compliant HTTP client for PHP with middleware architecture, advanc
2020
-**JSON Helpers** - Parse JSON with proper error handling and dot-notation access
2121
-**Custom Exceptions** - Detailed error context implementing PSR standards
2222
-**Easy to Swap HTTP Clients** - Switch between Guzzle, Symfony, or any PSR-18 client
23+
-**File Upload & Multipart** - RFC 7578 compliant multipart/form-data with file upload support
24+
-**Cookie Management** - RFC 6265 compliant automatic cookie handling with session support
2325

2426
## Requirements
2527

@@ -242,6 +244,107 @@ $transport = TransportBuilder::make()
242244
echo ClientFactory::getDetectedClientName(); // e.g., "Symfony\Component\HttpClient\Psr18Client"
243245
```
244246

247+
### File Upload & Multipart Requests
248+
249+
```php
250+
// Simple file upload
251+
$response = $transport->post('/upload')
252+
->withFile(
253+
name: 'document',
254+
path: '/path/to/file.pdf',
255+
filename: 'report.pdf',
256+
additionalFields: ['title' => 'Monthly Report']
257+
)
258+
->send();
259+
260+
// Multiple files with form data
261+
$response = $transport->post('/upload')
262+
->withMultipart([
263+
// Text fields
264+
['name' => 'title', 'contents' => 'My Upload'],
265+
['name' => 'description', 'contents' => 'File description'],
266+
267+
// File uploads
268+
[
269+
'name' => 'avatar',
270+
'contents' => file_get_contents('photo.jpg'),
271+
'filename' => 'avatar.jpg',
272+
'content-type' => 'image/jpeg'
273+
],
274+
[
275+
'name' => 'document',
276+
'contents' => fopen('/path/to/file.pdf', 'r'),
277+
'filename' => 'document.pdf'
278+
]
279+
])
280+
->send();
281+
282+
// Advanced: Using MultipartStreamBuilder
283+
use Farzai\Transport\Multipart\MultipartStreamBuilder;
284+
285+
$builder = new MultipartStreamBuilder();
286+
$builder->addField('username', 'john_doe')
287+
->addFile('avatar', '/path/to/avatar.jpg', 'profile.jpg')
288+
->addFileContents('data', $jsonData, 'data.json', 'application/json');
289+
290+
$response = $transport->post('/api/upload')
291+
->withMultipartBuilder($builder)
292+
->send();
293+
```
294+
295+
### Cookie Management
296+
297+
```php
298+
// Automatic cookie handling
299+
$transport = TransportBuilder::make()
300+
->withBaseUri('https://api.example.com')
301+
->withCookies() // Enable automatic cookie management
302+
->build();
303+
304+
// Login - cookies are automatically stored
305+
$transport->post('/login')
306+
->withJson(['username' => 'user', 'password' => 'pass'])
307+
->send();
308+
309+
// Subsequent requests automatically include cookies
310+
$response = $transport->get('/profile')->send();
311+
312+
// Advanced: Manual cookie management
313+
use Farzai\Transport\Cookie\CookieJar;
314+
use Farzai\Transport\Cookie\Cookie;
315+
316+
$cookieJar = new CookieJar();
317+
318+
// Add cookies manually
319+
$cookieJar->setCookie(new Cookie(
320+
name: 'session_id',
321+
value: 'abc123',
322+
expiresAt: time() + 3600,
323+
domain: 'example.com',
324+
path: '/',
325+
secure: true,
326+
httpOnly: true
327+
));
328+
329+
$transport = TransportBuilder::make()
330+
->withCookieJar($cookieJar)
331+
->build();
332+
333+
// Inspect cookies
334+
echo "Cookies: {$cookieJar->count()}\n";
335+
foreach ($cookieJar->getAllCookies() as $cookie) {
336+
echo "{$cookie->getName()}: {$cookie->getValue()}\n";
337+
}
338+
339+
// Export/Import cookies for persistence
340+
$data = $cookieJar->toArray();
341+
file_put_contents('cookies.json', json_encode($data));
342+
343+
// Later...
344+
$newJar = new CookieJar();
345+
$newJar->fromArray(json_decode(file_get_contents('cookies.json'), true));
346+
```
347+
245348
### Error Handling
246349

247350
```php
@@ -346,6 +449,8 @@ $response = ResponseBuilder::create()
346449
- [Custom HTTP Clients](examples/custom-client.php)
347450
- [Advanced Retry Logic](examples/advanced-retry.php)
348451
- [Custom Middleware](examples/middleware-example.php)
452+
- [File Upload](examples/file-upload.php)
453+
- [Cookie Session Management](examples/cookie-session.php)
349454

350455
## Architecture
351456

0 commit comments

Comments
 (0)