source: trunk/phpgwapi/inc/class.http.inc.php @ 7730

Revision 7730, 15.3 KB checked in by marcieli, 11 years ago (diff)

Ticket #3236 - Correcoes de seguranca com base no segundo relatorio emitido.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1<?php
2  /**************************************************************************\
3  * eGroupWare API - HTTP protocol class                                     *
4  * http://www.egroupware.org/api                                            *
5  * ------------------------------------------------------------------------ *
6  * This is not part of eGroupWare, but is used by eGroupWare.               *
7  * ------------------------------------------------------------------------ *
8  * This program is free software; you can redistribute it and/or modify it  *
9  * under the terms of the GNU General Public License as published by the    *
10  * Free Software Foundation; either version 2 of the License, or (at your   *
11  * option) any later version.                                               *
12  \**************************************************************************/
13
14
15        class http
16        {
17                var $host_name = '';
18                var $host_port = 80;
19                var $proxy_host_name = '';
20                var $proxy_host_port = 80;
21
22                var $request_method = 'GET';
23                var $user_agent = 'Manuel Lemos HTTP class test script';
24                var $request_uri = '';
25                var $protocol_version = '1.0';
26                var $debug = 0;
27                var $support_cookies = 1;
28                var $cookies = array();
29
30                /* private variables - DO NOT ACCESS */
31
32                var $state = 'Disconnected';
33                var $connection = 0;
34                var $content_length = 0;
35                var $read_length = 0;
36                var $request_host = '';
37                var $months = array(
38                        'Jan' => '01',
39                        'Feb' => '02',
40                        'Mar' => '03',
41                        'Apr' => '04',
42                        'May' => '05',
43                        'Jun' => '06',
44                        'Jul' => '07',
45                        'Aug' => '08',
46                        'Sep' => '09',
47                        'Oct' => '10',
48                        'Nov' => '11',
49                        'Dec' => '12'
50                );
51
52                /* Private methods - DO NOT CALL */
53
54                function OutputDebug($message)
55                {
56                        echo $message,"\n";
57                }
58
59                function GetLine()
60                {
61                        for($line='';;)
62                        {
63                                if(feof($this->connection) || !($part=fgets($this->connection,100)))
64                                {
65                                        return(0);
66                                }
67                                $line.=$part;
68                                $length=strlen($line);
69                                if($length>=2 && substr($line,$length-2,2)=="\r\n")
70                                {
71                                        $line=substr($line,0,$length-2);
72                                        if($this->debug)
73                                        {
74                                                $this->OutputDebug("< $line");
75                                        }
76                                        return($line);
77                                }
78                        }
79                }
80
81                function PutLine($line)
82                {
83                        if($this->debug)
84                        {
85                                $this->OutputDebug("> $line");
86                        }
87                        return(fputs($this->connection,"$line\r\n"));
88                }
89
90                function PutData($data)
91                {
92                        if($this->debug)
93                        {
94                                $this->OutputDebug("> $data");
95                        }
96                        return(fputs($this->connection,$data));
97                }
98
99                function Readbytes($length)
100                {
101                        if($this->debug)
102                        {
103                                if(($bytes=fread($this->connection,$length))!="")
104                                {
105                                        $this->OutputDebug("< $bytes");
106                                }
107                                return($bytes);
108                        }
109                        else
110                        {
111                                return(fread($this->connection,$length));
112                        }
113                }
114
115                function EndOfInput()
116                {
117                        return(feof($this->connection));
118                }
119
120                function Connect($host_name,$host_port)
121                {
122                        if($this->debug)
123                        {
124                                $this->OutputDebug("Connecting to $host_name...");
125                        }
126                        if(($this->connection=fsockopen($host_name,$host_port,&$error))==0)
127                        {
128                                switch($error)
129                                {
130                                        case -3:
131                                                return('-3 socket could not be created');
132                                        case -4:
133                                                return('-4 dns lookup on hostname "'.$host_name.'" failed');
134                                        case -5:
135                                                return('-5 connection refused or timed out');
136                                        case -6:
137                                                return('-6 fdopen() call failed');
138                                        case -7:
139                                                return('-7 setvbuf() call failed');
140                                        default:
141                                                return($error.' could not connect to the host "'.$host_name.'"');
142                                }
143                        }
144                        else
145                        {
146                                if($this->debug)
147                                {
148                                        $this->OutputDebug("Connected to $host_name");
149                                }
150                                $this->state='Connected';
151                                return("");
152                        }
153                }
154
155                function Disconnect()
156                {
157                        if($this->debug)
158                        {
159                                $this->OutputDebug('Disconnected from '.$this->host_name);
160                        }
161                        fclose($this->connection);
162                        return('');
163                }
164
165                /* Public methods */
166
167                function Open($arguments)
168                {
169                        if($this->state!='Disconnected')
170                        {
171                                return('1 already connected');
172                        }
173                        if(IsSet($arguments['HostName']))
174                        {
175                                $this->host_name=$arguments['HostName'];
176                        }
177                        if(IsSet($arguments['HostPort']))
178                        {
179                                $this->host_port=$arguments['HostPort'];
180                        }
181                        if(IsSet($arguments['ProxyHostName']))
182                        {
183                                $this->proxy_host_name=$arguments['ProxyHostName'];
184                        }
185                        if(IsSet($arguments['ProxyHostPort']))
186                        {
187                                $this->proxy_host_port=$arguments['ProxyHostPort'];
188                        }
189                        if(strlen($this->proxy_host_name)==0)
190                        {
191                                if(strlen($this->host_name)==0)
192                                {
193                                        return('2 it was not specified a valid hostname');
194                                }
195                                $host_name = $this->host_name;
196                                $host_port = $this->host_port;
197                        }
198                        else
199                        {
200                                $host_name = $this->proxy_host_name;
201                                $host_port = $this->proxy_host_port;
202                        }
203                        $error = $this->Connect($host_name,$host_port);
204                        if(strlen($error)==0)
205                        {
206                                $this->state = 'Connected';
207                        }
208                        return($error);
209                }
210
211                function Close()
212                {
213                        if($this->state == 'Disconnected')
214                        {
215                                return('1 already disconnected');
216                        }
217                        $error = $this->Disconnect();
218                        if(strlen($error) == 0)
219                        {
220                                $this->state = 'Disconnected';
221                        }
222                        return($error);
223                }
224
225                function SendRequest($arguments)
226                {
227                        switch($this->state)
228                        {
229                                case 'Disconnected':
230                                        return('1 connection was not yet established');
231                                case 'Connected':
232                                        break;
233                                default:
234                                        return('2 can not send request in the current connection state');
235                        }
236                        if(IsSet($arguments['RequestMethod']))
237                        {
238                                $this->request_method = $arguments['RequestMethod'];
239                        }
240                        if(IsSet($arguments['User-Agent']))
241                        {
242                                $this->user_agent = $arguments['User-Agent'];
243                        }
244                        if(strlen($this->request_method) == 0)
245                        {
246                                return('3 it was not specified a valid request method');
247                        }
248                        if(IsSet($arguments['RequestURI']))
249                        {
250                                $this->request_uri = $arguments['RequestURI'];
251                        }
252                        if(strlen($this->request_uri) == 0 || substr($this->request_uri,0,1) != '/')
253                        {
254                                return('4 it was not specified a valid request URI');
255                        }
256                        $request_body = '';
257                        $headers=(IsSet($arguments['Headers']) ? $arguments['Headers'] : array());
258                        if($this->request_method == 'POST')
259                        {
260                                if(IsSet($arguments['PostValues']))
261                                {
262                                        $values = $arguments['PostValues'];
263                                        if(!@is_array($values))
264                                        {
265                                                return('5 it was not specified a valid POST method values array');
266                                        }
267                    $values_count = count($values);
268                                        for($request_body = '',Reset($values),$value=0;$value<$values_count;Next($values),$value++)
269                                        {
270                                                if($value>0)
271                                                {
272                                                        $request_body .= '&';
273                                                }
274                                                $request_body.=Key($values).'='.UrlEncode($values[Key($values)]);
275                                        }
276                                        $headers['Content-type'] = 'application/x-www-form-urlencoded';
277                                }
278                        }
279                        if(strlen($this->proxy_host_name) == 0)
280                        {
281                                $request_uri = $this->request_uri;
282                        }
283                        else
284                        {
285                                $request_uri = 'http://'.$this->host_name.($this->host_port==80 ? '' : ':'.$this->host_port).$this->request_uri;
286                        }
287                        if(($success = $this->PutLine($this->request_method.' '.$request_uri.' HTTP/'.$this->protocol_version)))
288                        {
289                                if(($body_length = strlen($request_body)))
290                                {
291                                        $headers['Content-length'] = $body_length;
292                                }
293                $headers_count = count($headers);
294                                for($host_set=0,Reset($headers),$header=0;$header<$headers_count;Next($headers),$header++)
295                                {
296                                        $header_name  = Key($headers);
297                                        $header_value = $headers[$header_name];
298                                        if(@is_array($header_value))
299                                        {
300                        $header_value_count = count($header_value);
301                                                for(Reset($header_value),$value=0;$value<$header_value_count;Next($header_value),$value++)
302                                                {
303                                                        if(!$success = $this->PutLine("$header_name: ".$header_value[Key($header_value)]))
304                                                        {
305                                                                break 2;
306                                                        }
307                                                }
308                                        }
309                                        else
310                                        {
311                                                if(!$success = $this->PutLine("$header_name: $header_value"))
312                                                {
313                                                        break;
314                                                }
315                                        }
316                                        if(strtolower(Key($headers)) == 'host')
317                                        {
318                                                $this->request_host = strtolower($header_value);
319                                                $host_set = 1;
320                                        }
321                                }
322                                if($success)
323                                {
324                                        if(!$host_set)
325                                        {
326                                                $success = $this->PutLine('Host: '.$this->host_name);
327                                                $this->request_host = strtolower($this->host_name);
328                                        }
329                                        if(count($this->cookies) && IsSet($this->cookies[0]))
330                                        {
331                                                $now = gmdate('Y-m-d H-i-s');
332                        $cookies_count = count($this->cookies[0]);
333                                                for($cookies = array(),$domain=0,Reset($this->cookies[0]);$domain<$cookies_count;Next($this->cookies[0]),$domain++)
334                                                {
335                                                        $domain_pattern = Key($this->cookies[0]);
336                                                        $match = strlen($this->request_host)-strlen($domain_pattern);
337                                                        if($match >= 0 &&
338                                                                !strcmp($domain_pattern,substr($this->request_host,$match)) &&
339                                                                ($match == 0 || $domain_pattern[0] == '.' || $this->request_host[$match-1] == '.'))
340                                                        {
341                                $cookies_count_domain_pattern = count($this->cookies[0][$domain_pattern]);
342                                                                for(Reset($this->cookies[0][$domain_pattern]),$path_part=0;$path_part<$cookies_count_domain_pattern;Next($this->cookies[0][$domain_pattern]),$path_part++)
343                                                                {
344                                                                        $path = Key($this->cookies[0][$domain_pattern]);
345                                                                        if(strlen($this->request_uri) >= strlen($path) && substr($this->request_uri,0,strlen($path)) == $path)
346                                                                        {
347                                        $cookies_count_path = count($this->cookies[0][$domain_pattern][$path]);
348                                                                                for(Reset($this->cookies[0][$domain_pattern][$path]),$cookie = 0;$cookie<$cookies_count_path;Next($this->cookies[0][$domain_pattern][$path]),$cookie++)
349                                                                                {
350                                                                                        $cookie_name = Key($this->cookies[0][$domain_pattern][$path]);
351                                                                                        $expires     = $this->cookies[0][$domain_pattern][$path][$cookie_name]['expires'];
352                                                                                        if($expires == '' || strcmp($now,$expires)<0)
353                                                                                        {
354                                                                                                $cookies[$cookie_name] = $this->cookies[0][$domain_pattern][$path][$cookie_name];
355                                                                                        }
356                                                                                }
357                                                                        }
358                                                                }
359                                                        }
360                                                }
361                        $cookies_count = count($cookies);
362                                                for(Reset($cookies),$cookie=0;$cookie<$cookies_count;Next($cookies),$cookie++)
363                                                {
364                                                        $cookie_name = Key($cookies);
365                                                        if(!($success = $this->PutLine('Cookie: '.UrlEncode($cookie_name).'='.$cookies[$cookie_name]['value'].';')))
366                                                        {
367                                                                break;
368                                                        }
369                                                }
370                                        }
371                                        if($success)
372                                        {
373                                                if($success)
374                                                {
375                                                        $success = $this->PutLine('');
376                                                        if($body_length && $success)
377                                                        {
378                                                                $success = $this->PutData($request_body);
379                                                        }
380                                                }
381                                        }
382                                }
383                        }
384                        if(!$success)
385                        {
386                                return('5 could not send the HTTP request');
387                        }
388                        $this->state = 'RequestSent';
389                        return('');
390                }
391
392                function ReadReplyHeaders(&$headers)
393                {
394                        switch($this->state)
395                        {
396                                case 'Disconnected':
397                                        return('1 connection was not yet established');
398                                case 'Connected':
399                                        return('2 request was not sent');
400                                case 'RequestSent':
401                                        break;
402                                default:
403                                        return('3 can not get request headers in the current connection state');
404                        }
405                        $headers = array();
406                        $this->content_length = $this->read_length = 0;
407                        $this->content_length_set = 0;
408                        for(;;)
409                        {
410                                $line = $this->GetLine();
411                                if(!is_string($line))
412                                {
413                                        return('4 could not read request reply');
414                                }
415                                if($line == '')
416                                {
417                                        $this->state = 'GotReplyHeaders';
418                                        return('');
419                                }
420                                $header_name  = strtolower(strtok($line,':'));
421                                $header_value = Trim(Chop(strtok("\r\n")));
422                                if(IsSet($headers[$header_name]))
423                                {
424                                        if(is_string($headers[$header_name]))
425                                        {
426                                                $headers[$header_name] = array($headers[$header_name]);
427                                        }
428                                        $headers[$header_name][] = $header_value;
429                                }
430                                else
431                                {
432                                        $headers[$header_name] = $header_value;
433                                }
434                                switch($header_name)
435                                {
436                                        case 'content-length':
437                                        $this->content_length = (int)$headers[$header_name];
438                                        $this->content_length_set = 1;
439                                        break;
440                                        case 'set-cookie':
441                                        if($this->support_cookies)
442                                        {
443                                                $cookie_name  = trim(strtok($headers[$header_name],'='));
444                                                $cookie_value = strtok(';');
445                                                $domain = $this->request_host;
446                                                $path = '/';
447                                                $expires = '';
448                                                $secure = 0;
449                                                while(($name=strtolower(trim(strtok('=')))) != '')
450                                                {
451                                                        $value=UrlDecode(strtok(';'));
452                                                        switch($name)
453                                                        {
454                                                                case 'domain':
455                                                                        if($value == '' || !strpos($value,'.',$value[0] == '.'))
456                                                                        {
457                                                                                break;
458                                                                        }
459                                                                        $domain = strtolower($value);
460                                                                        break;
461                                                                case 'path':
462                                                                        if($value != '' && $value[0] == '/')
463                                                                        {
464                                                                                $path = $value;
465                                                                        }
466                                                                        break;
467                                                                case 'expires':
468                                                                        if(preg_match('/^((Mon|Monday|Tue|Tuesday|Wed|Wednesday|Thu|Thursday|Fri|Friday|Sat|Saturday|Sun|Sunday), )?([0-9]{2})\\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\-([0-9]{2,4}) ([0-9]{2})\\:([0-9]{2})\\:([0-9]{2}) GMT$/',$value,$matches))
469                                                                        {
470                                                                                $year = (int)$matches[5];
471                                                                                if($year<1900)
472                                                                                {
473                                                                                        $year += ($year<70 ? 2000 : 1900);
474                                                                                }
475                                                                                $expires = "$year-".$this->months[$matches[4]].'-'.$matches[3].' '.$matches[6].':'.$matches[7].':'.$matches[8];
476                                                                        }
477                                                                        break;
478                                                                case 'secure':
479                                                                        $secure = 1;
480                                                                        break;
481                                                        }
482                                                }
483                                                $this->cookies[$secure][$domain][$path][$cookie_name] = array(
484                                                        'name'    => $cookie_name,
485                                                        'value'   => $cookie_value,
486                                                        'domain'  => $domain,
487                                                        'path'    => $path,
488                                                        'expires' => $expires,
489                                                        'secure'  => $secure
490                                                );
491                                        }
492                                }
493                        }
494                }
495
496                function ReadReplyBody(&$body,$length)
497                {
498                        switch($this->state)
499                        {
500                                case 'Disconnected':
501                                        return('1 connection was not yet established');
502                                case 'Connected':
503                                        return('2 request was not sent');
504                                case 'RequestSent':
505                                        if(($error = $this->ReadReplyHeaders(&$headers)) != '')
506                                        {
507                                                return($error);
508                                        }
509                                        break;
510                                case 'GotReplyHeaders':
511                                        break;
512                                default:
513                                        return('3 can not get request headers in the current connection state');
514                        }
515                        $body = '';
516                        if($this->content_length_set)
517                        {
518                                $length = min($this->content_length-$this->read_length,$length);
519                        }
520                        if($length>0 && !$this->EndOfInput() && ($body = $this->ReadBytes($length)) == '')
521                        {
522                                return('4 could not get the request reply body');
523                        }
524                        return('');
525                }
526
527                function GetPersistentCookies(&$cookies)
528                {
529                        $now = gmdate('Y-m-d H-i-s');
530                        $cookies = array();
531            $cookies_count = count($this->cookies);
532                        for($secure_cookies = 0,Reset($this->cookies);$secure_cookies<$cookies_count;Next($this->cookies),$secure_cookies++)
533                        {
534                                $secure = Key($this->cookies);
535                $cookies_count_secure = count($this->cookies[$secure]);
536                                for($domain = 0,Reset($this->cookies[$secure]);$domain<$cookies_count_secure;Next($this->cookies[$secure]),$domain++)
537                                {
538                                        $domain_pattern = Key($this->cookies[$secure]);
539                    $cookies_count_domain_pattern = count($this->cookies[$secure][$domain_pattern]);
540                                        for(Reset($this->cookies[$secure][$domain_pattern]),$path_part=0;$path_part<$cookies_count_domain_pattern;Next($this->cookies[$secure][$domain_pattern]),$path_part++)
541                                        {
542                                                $path=Key($this->cookies[$secure][$domain_pattern]);
543                        $cookies_count_path = count($this->cookies[$secure][$domain_pattern][$path]);
544                                                for(Reset($this->cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<$cookies_count_path;Next($this->cookies[$secure][$domain_pattern][$path]),$cookie++)
545                                                {
546                                                        $cookie_name = Key($this->cookies[$secure][$domain_pattern][$path]);
547                                                        $expires     = $this->cookies[$secure][$domain_pattern][$path][$cookie_name]['expires'];
548                                                        if($expires != '' && strcmp($now,$expires)<0)
549                                                        {
550                                                                $cookies[$secure][$domain_pattern][$path][$cookie_name] = $this->cookies[$secure][$domain_pattern][$path][$cookie_name];
551                                                        }
552                                                }
553                                        }
554                                }
555                        }
556                }
557        }
Note: See TracBrowser for help on using the repository browser.