1
+ <?php
2
+
3
+ namespace CurlDownloader ;
4
+
5
+ class HeaderHandler
6
+ {
7
+ protected $ headers = array ();
8
+
9
+ /** @var callable */
10
+ protected $ callback ;
11
+
12
+ // Thanks Drupal!
13
+ // const REQUEST_HEADER_FILENAME_REGEX = '@\\bfilename(?<star>\\*?)=\\"(?<filename>.+)\\"@';
14
+ const REQUEST_HEADER_FILENAME_REGEX = '/filename\s*=\s*[" \']*(?<filename>[^" \']+)/ ' ;
15
+
16
+ public function callback ()
17
+ {
18
+ $ oThis = $ this ;
19
+
20
+ $ headers = array ();
21
+ $ first_line_sent = false ;
22
+
23
+ return function ($ ch , $ data ) use ($ oThis , &$ first_line_sent , &$ headers ) {
24
+ $ line = trim ($ data );
25
+
26
+ if ($ first_line_sent == false ) {
27
+ $ first_line_sent = true ;
28
+ } elseif ($ line === '' ) {
29
+ $ oThis ->sendHeaders ();
30
+ } else {
31
+
32
+ $ parts = explode (': ' , $ line , 2 );
33
+
34
+ // Despite that headers may be retrieved case-insensitively, the original case MUST be preserved by the implementation
35
+ // Non-conforming HTTP applications may depend on a certain case,
36
+ // so it is useful for a user to be able to dictate the case of the HTTP headers when creating a request or response.
37
+
38
+ // TODO:
39
+ // Multiple message-header fields with the same field-name may be present in a message
40
+ // if and only if the entire field-value for that header field is defined as a comma-separated list
41
+ $ oThis ->headers [trim ($ parts [0 ])] = isset ($ parts [1 ]) ? trim ($ parts [1 ]) : null ;
42
+ }
43
+
44
+ return strlen ($ data );
45
+ };
46
+ }
47
+
48
+ protected function sendHeaders ()
49
+ {
50
+ if (is_callable ($ this ->callback )) {
51
+ call_user_func ($ this ->callback , $ this );
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @param callable $callback
57
+ */
58
+ public function onHeadersReceived ($ callback )
59
+ {
60
+ $ this ->callback = $ callback ;
61
+ }
62
+
63
+ // While header names are not case-sensitive, getHeaders() will preserve the exact case in which headers were originally specified.
64
+ public function getHeaders ()
65
+ {
66
+ return $ this ->headers ;
67
+ }
68
+
69
+ public function getContentDispositionFilename ()
70
+ {
71
+ $ normalized = array_change_key_case ($ this ->headers , CASE_LOWER );
72
+ $ header = isset ($ normalized ['content-disposition ' ]) ? $ normalized ['content-disposition ' ] : null ;
73
+
74
+ if ($ header && preg_match (static ::REQUEST_HEADER_FILENAME_REGEX , $ header , $ matches )) {
75
+ return $ matches ['filename ' ];
76
+ }
77
+
78
+ return null ;
79
+ }
80
+ }
0 commit comments