Subversion Repositories oidplus

Rev

Rev 277 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
171 daniel-mar 1
<?php
2
 
3
/*
386 daniel-mar 4
 * This file includes:
5
 *
6
 * 1. PHP HTTP protocol client: HTTP client to access Web site pages
171 daniel-mar 7
 *    by Manuel Lemos
8
 *    http://www.phpclasses.org/httpclient
9
 *    License: BSD License
10
 *
386 daniel-mar 11
 *    http.php
12
 *        @(#) $Header: /opt2/ena/metal/http/http.php,v 1.94 2016/05/03 02:07:04 mlemos Exp $
13
 *        Modified by Daniel Marschall, ViaThinkSoft, Revision 2020-09-12
14
 *
15
 *
16
 * 2. Simple Authentication and Security Layer client
17
 *    (Included because of dependency)
18
 *    by Manuel Lemos
19
 *    http://www.phpclasses.org/sasl
20
 *    License: BSD License
21
 *
22
 *    sasl.php
23
 *        @(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $
24
 *    basic_sasl_client.php
25
 *        @(#) $Id: basic_sasl_client.php,v 1.1 2004/11/17 08:01:23 mlemos Exp $
26
 *    cram_md5_sasl_client.php
27
 *        @(#) $Id: cram_md5_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
28
 *    digest_sasl_client.php
29
 *        @(#) $Id: digest_sasl_client.php,v 1.1 2005/10/27 05:24:15 mlemos Exp $
30
 *    login_sasl_client.php
31
 *        @(#) $Id: login_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
32
 *    ntlm_sasl_client.php
33
 *        @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
34
 *    plain_sasl_client.php
35
 *        @(#) $Id: plain_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
36
 */
37
 
38
// =============================================================================
39
 
40
/*
41
 * basic_sasl_client.php
42
 *
43
 * @(#) $Id: basic_sasl_client.php,v 1.1 2004/11/17 08:01:23 mlemos Exp $
44
 *
45
 */
46
 
47
define("SASL_BASIC_STATE_START",    0);
48
define("SASL_BASIC_STATE_DONE",     1);
49
 
50
class basic_sasl_client_class
51
{
52
        var $credentials=array();
53
        var $state=SASL_BASIC_STATE_START;
54
 
55
        Function Initialize(&$client)
56
        {
57
                return(1);
58
        }
59
 
60
        Function Start(&$client, &$message, &$interactions)
61
        {
62
                if($this->state!=SASL_BASIC_STATE_START)
63
                {
64
                        $client->error="Basic authentication state is not at the start";
65
                        return(SASL_FAIL);
66
                }
67
                $this->credentials=array(
68
                        "user"=>"",
69
                        "password"=>""
70
                );
71
                $defaults=array(
72
                );
73
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
74
                if($status==SASL_CONTINUE)
75
                {
76
                        $message=$this->credentials["user"].":".$this->credentials["password"];
77
                        $this->state=SASL_BASIC_STATE_DONE;
78
                }
79
                else
80
                        Unset($message);
81
                return($status);
82
        }
83
 
84
        Function Step(&$client, $response, &$message, &$interactions)
85
        {
86
                switch($this->state)
87
                {
88
                        case SASL_BASIC_STATE_DONE:
89
                                $client->error="Basic authentication was finished without success";
90
                                return(SASL_FAIL);
91
                        default:
92
                                $client->error="invalid Basic authentication step state";
93
                                return(SASL_FAIL);
94
                }
95
                return(SASL_CONTINUE);
96
        }
97
};
98
 
99
// =============================================================================
100
 
101
/*
102
 * cram_md5_sasl_client.php
103
 *
104
 * @(#) $Id: cram_md5_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
105
 *
106
 */
107
 
108
define("SASL_CRAM_MD5_STATE_START",             0);
109
define("SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE", 1);
110
define("SASL_CRAM_MD5_STATE_DONE",              2);
111
 
112
class cram_md5_sasl_client_class
113
{
114
        var $credentials=array();
115
        var $state=SASL_CRAM_MD5_STATE_START;
116
 
117
        Function Initialize(&$client)
118
        {
119
                return(1);
120
        }
121
 
122
        Function HMACMD5($key,$text)
123
        {
124
                $key=(strlen($key)<64 ? str_pad($key,64,"\0") : substr($key,0,64));
125
                return(md5((str_repeat("\x5c", 64)^$key).pack("H32", md5((str_repeat("\x36", 64)^$key).$text))));
126
        }
127
 
128
        Function Start(&$client, &$message, &$interactions)
129
        {
130
                if($this->state!=SASL_CRAM_MD5_STATE_START)
131
                {
132
                        $client->error="CRAM-MD5 authentication state is not at the start";
133
                        return(SASL_FAIL);
134
                }
135
                $this->credentials=array(
136
                        "user"=>"",
137
                        "password"=>""
138
                );
139
                $defaults=array();
140
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
141
                if($status==SASL_CONTINUE)
142
                        $this->state=SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE;
143
                Unset($message);
144
                return($status);
145
        }
146
 
147
        Function Step(&$client, $response, &$message, &$interactions)
148
        {
149
                switch($this->state)
150
                {
151
                        case SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE:
152
                                $message=$this->credentials["user"]." ".$this->HMACMD5($this->credentials["password"], $response);
153
                                $this->state=SASL_CRAM_MD5_STATE_DONE;
154
                                break;
155
                        case SASL_CRAM_MD5_STATE_DONE:
156
                                $client->error="CRAM-MD5 authentication was finished without success";
157
                                return(SASL_FAIL);
158
                        default:
159
                                $client->error="invalid CRAM-MD5 authentication step state";
160
                                return(SASL_FAIL);
161
                }
162
                return(SASL_CONTINUE);
163
        }
164
};
165
 
166
// =============================================================================
167
 
168
/*
169
 * digest_sasl_client.php
170
 *
171
 * @(#) $Id: digest_sasl_client.php,v 1.1 2005/10/27 05:24:15 mlemos Exp $
172
 *
173
 */
174
 
175
define('SASL_DIGEST_STATE_START',             0);
176
define('SASL_DIGEST_STATE_RESPOND_CHALLENGE', 1);
177
define('SASL_DIGEST_STATE_DONE',              2);
178
 
179
class digest_sasl_client_class
180
{
181
        var $credentials=array();
182
        var $state=SASL_DIGEST_STATE_START;
183
 
184
        Function unq($string)
185
        {
186
                return(($string[0]=='"' && $string[strlen($string)-1]=='"') ? substr($string, 1, strlen($string)-2) : $string);
187
        }
188
 
189
        Function H($data)
190
        {
191
                return md5($data);
192
        }
193
 
194
        Function KD($secret, $data)
195
        {
196
                return $this->H($secret.':'.$data);
197
        }
198
 
199
        Function Initialize(&$client)
200
        {
201
                return(1);
202
        }
203
 
204
        Function Start(&$client, &$message, &$interactions)
205
        {
206
                if($this->state!=SASL_DIGEST_STATE_START)
207
                {
208
                        $client->error='Digest authentication state is not at the start';
209
                        return(SASL_FAIL);
210
                }
211
                $this->credentials=array(
212
                        'user'=>'',
213
                        'password'=>'',
214
                        'uri'=>'',
215
                        'method'=>'',
216
                        'session'=>''
217
                );
218
                $defaults=array();
219
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
220
                if($status==SASL_CONTINUE)
221
                        $this->state=SASL_DIGEST_STATE_RESPOND_CHALLENGE;
222
                Unset($message);
223
                return($status);
224
        }
225
 
226
        Function Step(&$client, $response, &$message, &$interactions)
227
        {
228
                switch($this->state)
229
                {
230
                        case SASL_DIGEST_STATE_RESPOND_CHALLENGE:
231
                                $values=explode(',',$response);
232
                                $parameters=array();
233
                                for($v=0; $v<count($values); $v++)
234
                                        $parameters[strtok(trim($values[$v]), '=')]=strtok('');
235
 
236
                                $message='username="'.$this->credentials['user'].'"';
237
                                if(!IsSet($parameters[$p='realm'])
238
                                && !IsSet($parameters[$p='nonce']))
239
                                {
240
                                        $client->error='Digest authentication parameter '.$p.' is missing from the server response';
241
                                        return(SASL_FAIL);
242
                                }
243
                                $message.=', realm='.$parameters['realm'];
244
                                $message.=', nonce='.$parameters['nonce'];
245
                                $message.=', uri="'.$this->credentials['uri'].'"';
246
                                if(IsSet($parameters['algorithm']))
247
                                {
248
                                        $algorithm=$this->unq($parameters['algorithm']);
249
                                        $message.=', algorithm='.$parameters['algorithm'];
250
                                }
251
                                else
252
                                        $algorithm='';
253
 
254
                                $realm=$this->unq($parameters['realm']);
255
                                $nonce=$this->unq($parameters['nonce']);
256
                                if(IsSet($parameters['qop']))
257
                                {
258
                                        switch($qop=$this->unq($parameters['qop']))
259
                                        {
260
                                                case "auth":
261
                                                        $cnonce=$this->credentials['session'];
262
                                                        break;
263
                                                default:
264
                                                        $client->error='Digest authentication quality of protection '.$qop.' is not yet supported';
265
                                                        return(SASL_FAIL);
266
                                        }
267
                                }
268
                                $nc_value='00000001';
269
                                if(IsSet($parameters['qop'])
270
                                && !strcmp($algorithm, 'MD5-sess'))
271
                                        $A1=$this->H($this->credentials['user'].':'. $realm.':'. $this->credentials['password']).':'.$nonce.':'.$cnonce;
272
                                else
273
                                        $A1=$this->credentials['user'].':'. $realm.':'. $this->credentials['password'];
274
                                $A2=$this->credentials['method'].':'.$this->credentials['uri'];
275
                                if(IsSet($parameters['qop']))
276
                                        $response=$this->KD($this->H($A1), $nonce.':'. $nc_value.':'. $cnonce.':'. $qop.':'. $this->H($A2));
277
                                else
278
                                        $response=$this->KD($this->H($A1), $nonce.':'. $this->H($A2));
279
                                $message.=', response="'.$response.'"';
280
                                if(IsSet($parameters['opaque']))
281
                                        $message.=', opaque='.$parameters['opaque'];
282
                                if(IsSet($parameters['qop']))
283
                                        $message.=', qop="'.$qop.'"';
284
                                $message.=', nc='.$nc_value;
285
                                if(IsSet($parameters['qop']))
286
                                        $message.=', cnonce="'.$cnonce.'"';
287
                                $client->encode_response=0;
288
                                $this->state=SASL_DIGEST_STATE_DONE;
289
                                break;
290
                        case SASL_DIGEST_STATE_DONE:
291
                                $client->error='Digest authentication was finished without success';
292
                                return(SASL_FAIL);
293
                        default:
294
                                $client->error='invalid Digest authentication step state';
295
                                return(SASL_FAIL);
296
                }
297
                return(SASL_CONTINUE);
298
        }
299
};
300
 
301
// =============================================================================
302
 
303
/*
304
 * login_sasl_client.php
305
 *
306
 * @(#) $Id: login_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
307
 *
308
 */
309
 
310
define("SASL_LOGIN_STATE_START",             0);
311
define("SASL_LOGIN_STATE_IDENTIFY_USER",     1);
312
define("SASL_LOGIN_STATE_IDENTIFY_PASSWORD", 2);
313
define("SASL_LOGIN_STATE_DONE",              3);
314
 
315
class login_sasl_client_class
316
{
317
        var $credentials=array();
318
        var $state=SASL_LOGIN_STATE_START;
319
 
320
        Function Initialize(&$client)
321
        {
322
                return(1);
323
        }
324
 
325
        Function Start(&$client, &$message, &$interactions)
326
        {
327
                if($this->state!=SASL_LOGIN_STATE_START)
328
                {
329
                        $client->error="LOGIN authentication state is not at the start";
330
                        return(SASL_FAIL);
331
                }
332
                $this->credentials=array(
333
                        "user"=>"",
334
                        "password"=>"",
335
                        "realm"=>""
336
                );
337
                $defaults=array(
338
                        "realm"=>""
339
                );
340
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
341
                if($status==SASL_CONTINUE)
342
                        $this->state=SASL_LOGIN_STATE_IDENTIFY_USER;
343
                Unset($message);
344
                return($status);
345
        }
346
 
347
        Function Step(&$client, $response, &$message, &$interactions)
348
        {
349
                switch($this->state)
350
                {
351
                        case SASL_LOGIN_STATE_IDENTIFY_USER:
352
                                $message=$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "");
353
                                $this->state=SASL_LOGIN_STATE_IDENTIFY_PASSWORD;
354
                                break;
355
                        case SASL_LOGIN_STATE_IDENTIFY_PASSWORD:
356
                                $message=$this->credentials["password"];
357
                                $this->state=SASL_LOGIN_STATE_DONE;
358
                                break;
359
                        case SASL_LOGIN_STATE_DONE:
360
                                $client->error="LOGIN authentication was finished without success";
361
                                break;
362
                        default:
363
                                $client->error="invalid LOGIN authentication step state";
364
                                return(SASL_FAIL);
365
                }
366
                return(SASL_CONTINUE);
367
        }
368
};
369
 
370
// =============================================================================
371
 
372
/*
373
 * ntlm_sasl_client.php
374
 *
375
 * @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
376
 *
377
 */
378
 
379
define("SASL_NTLM_STATE_START",             0);
380
define("SASL_NTLM_STATE_IDENTIFY_DOMAIN",   1);
381
define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2);
382
define("SASL_NTLM_STATE_DONE",              3);
383
 
384
class ntlm_sasl_client_class
385
{
386
        var $credentials=array();
387
        var $state=SASL_NTLM_STATE_START;
388
 
389
        Function Initialize(&$client)
390
        {
391
                if(!function_exists($function="mcrypt_encrypt")
392
                || !function_exists($function="mhash"))
393
                {
394
                        $extensions=array(
395
                                "mcrypt_encrypt"=>"mcrypt",
396
                                "mhash"=>"mhash"
397
                        );
398
                        $client->error="the extension ".$extensions[$function]." required by the NTLM SASL client class is not available in this PHP configuration";
399
                        return(0);
400
                }
401
                return(1);
402
        }
403
 
404
        Function ASCIIToUnicode($ascii)
405
        {
406
                for($unicode="",$a=0;$a<strlen($ascii);$a++)
407
                        $unicode.=substr($ascii,$a,1).chr(0);
408
                return($unicode);
409
        }
410
 
411
        Function TypeMsg1($domain,$workstation)
412
        {
413
                $domain_length=strlen($domain);
414
                $workstation_length=strlen($workstation);
415
                $workstation_offset=32;
416
                $domain_offset=$workstation_offset+$workstation_length;
417
                return(
418
                        "NTLMSSP\0".
419
                        "\x01\x00\x00\x00".
420
                        "\x07\x32\x00\x00".
421
                        pack("v",$domain_length).
422
                        pack("v",$domain_length).
423
                        pack("V",$domain_offset).
424
                        pack("v",$workstation_length).
425
                        pack("v",$workstation_length).
426
                        pack("V",$workstation_offset).
427
                        $workstation.
428
                        $domain
429
                );
430
        }
431
 
432
        Function NTLMResponse($challenge,$password)
433
        {
434
                $unicode=$this->ASCIIToUnicode($password);
435
                $md4=mhash(MHASH_MD4,$unicode);
436
                $padded=$md4.str_repeat(chr(0),21-strlen($md4));
437
                $iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB);
438
                $iv=mcrypt_create_iv($iv_size,MCRYPT_RAND);
439
                for($response="",$third=0;$third<21;$third+=7)
440
                {
441
                        for($packed="",$p=$third;$p<$third+7;$p++)
442
                                $packed.=str_pad(decbin(ord(substr($padded,$p,1))),8,"0",STR_PAD_LEFT);
443
                        for($key="",$p=0;$p<strlen($packed);$p+=7)
444
                        {
445
                                $s=substr($packed,$p,7);
446
                                $b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
447
                                $key.=chr(bindec($b));
448
                        }
449
                        $ciphertext=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv);
450
                        $response.=$ciphertext;
451
                }
452
                return $response;
453
        }
454
 
455
        Function TypeMsg3($ntlm_response,$user,$domain,$workstation)
456
        {
457
                $domain_unicode=$this->ASCIIToUnicode($domain);
458
                $domain_length=strlen($domain_unicode);
459
                $domain_offset=64;
460
                $user_unicode=$this->ASCIIToUnicode($user);
461
                $user_length=strlen($user_unicode);
462
                $user_offset=$domain_offset+$domain_length;
463
                $workstation_unicode=$this->ASCIIToUnicode($workstation);
464
                $workstation_length=strlen($workstation_unicode);
465
                $workstation_offset=$user_offset+$user_length;
466
                $lm="";
467
                $lm_length=strlen($lm);
468
                $lm_offset=$workstation_offset+$workstation_length;
469
                $ntlm=$ntlm_response;
470
                $ntlm_length=strlen($ntlm);
471
                $ntlm_offset=$lm_offset+$lm_length;
472
                $session="";
473
                $session_length=strlen($session);
474
                $session_offset=$ntlm_offset+$ntlm_length;
475
                return(
476
                        "NTLMSSP\0".
477
                        "\x03\x00\x00\x00".
478
                        pack("v",$lm_length).
479
                        pack("v",$lm_length).
480
                        pack("V",$lm_offset).
481
                        pack("v",$ntlm_length).
482
                        pack("v",$ntlm_length).
483
                        pack("V",$ntlm_offset).
484
                        pack("v",$domain_length).
485
                        pack("v",$domain_length).
486
                        pack("V",$domain_offset).
487
                        pack("v",$user_length).
488
                        pack("v",$user_length).
489
                        pack("V",$user_offset).
490
                        pack("v",$workstation_length).
491
                        pack("v",$workstation_length).
492
                        pack("V",$workstation_offset).
493
                        pack("v",$session_length).
494
                        pack("v",$session_length).
495
                        pack("V",$session_offset).
496
                        "\x01\x02\x00\x00".
497
                        $domain_unicode.
498
                        $user_unicode.
499
                        $workstation_unicode.
500
                        $lm.
501
                        $ntlm
502
                );
503
        }
504
 
505
        Function Start(&$client, &$message, &$interactions)
506
        {
507
                if($this->state!=SASL_NTLM_STATE_START)
508
                {
509
                        $client->error="NTLM authentication state is not at the start";
510
                        return(SASL_FAIL);
511
                }
512
                $this->credentials=array(
513
                        "user"=>"",
514
                        "password"=>"",
515
                        "realm"=>"",
516
                        "workstation"=>""
517
                );
518
                $defaults=array();
519
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
520
                if($status==SASL_CONTINUE)
521
                        $this->state=SASL_NTLM_STATE_IDENTIFY_DOMAIN;
522
                Unset($message);
523
                return($status);
524
        }
525
 
526
        Function Step(&$client, $response, &$message, &$interactions)
527
        {
528
                switch($this->state)
529
                {
530
                        case SASL_NTLM_STATE_IDENTIFY_DOMAIN:
531
                                $message=$this->TypeMsg1($this->credentials["realm"],$this->credentials["workstation"]);
532
                                $this->state=SASL_NTLM_STATE_RESPOND_CHALLENGE;
533
                                break;
534
                        case SASL_NTLM_STATE_RESPOND_CHALLENGE:
535
                                $ntlm_response=$this->NTLMResponse(substr($response,24,8),$this->credentials["password"]);
536
                                $message=$this->TypeMsg3($ntlm_response,$this->credentials["user"],$this->credentials["realm"],$this->credentials["workstation"]);
537
                                $this->state=SASL_NTLM_STATE_DONE;
538
                                break;
539
                        case SASL_NTLM_STATE_DONE:
540
                                $client->error="NTLM authentication was finished without success";
541
                                return(SASL_FAIL);
542
                        default:
543
                                $client->error="invalid NTLM authentication step state";
544
                                return(SASL_FAIL);
545
                }
546
                return(SASL_CONTINUE);
547
        }
548
};
549
 
550
// =============================================================================
551
 
552
/*
553
 * plain_sasl_client.php
554
 *
555
 * @(#) $Id: plain_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
556
 *
557
 */
558
 
559
define("SASL_PLAIN_STATE_START",    0);
560
define("SASL_PLAIN_STATE_IDENTIFY", 1);
561
define("SASL_PLAIN_STATE_DONE",     2);
562
 
563
define("SASL_PLAIN_DEFAULT_MODE",            0);
564
define("SASL_PLAIN_EXIM_MODE",               1);
565
define("SASL_PLAIN_EXIM_DOCUMENTATION_MODE", 2);
566
 
567
class plain_sasl_client_class
568
{
569
        var $credentials=array();
570
        var $state=SASL_PLAIN_STATE_START;
571
 
572
        Function Initialize(&$client)
573
        {
574
                return(1);
575
        }
576
 
577
        Function Start(&$client, &$message, &$interactions)
578
        {
579
                if($this->state!=SASL_PLAIN_STATE_START)
580
                {
581
                        $client->error="PLAIN authentication state is not at the start";
582
                        return(SASL_FAIL);
583
                }
584
                $this->credentials=array(
585
                        "user"=>"",
586
                        "password"=>"",
587
                        "realm"=>"",
588
                        "mode"=>""
589
                );
590
                $defaults=array(
591
                        "realm"=>"",
592
                        "mode"=>""
593
                );
594
                $status=$client->GetCredentials($this->credentials,$defaults,$interactions);
595
                if($status==SASL_CONTINUE)
596
                {
597
                        switch($this->credentials["mode"])
598
                        {
599
                                case SASL_PLAIN_EXIM_MODE:
600
                                        $message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
601
                                        break;
602
                                case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
603
                                        $message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
604
                                        break;
605
                                default:
606
                                        $message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
607
                                        break;
608
                        }
609
                        $this->state=SASL_PLAIN_STATE_DONE;
610
                }
611
                else
612
                        Unset($message);
613
                return($status);
614
        }
615
 
616
        Function Step(&$client, $response, &$message, &$interactions)
617
        {
618
                switch($this->state)
619
                {
620
/*
621
                        case SASL_PLAIN_STATE_IDENTIFY:
622
                                switch($this->credentials["mode"])
623
                                {
624
                                        case SASL_PLAIN_EXIM_MODE:
625
                                                $message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
626
                                                break;
627
                                        case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
628
                                                $message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
629
                                                break;
630
                                        default:
631
                                                $message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
632
                                                break;
633
                                }
634
                                var_dump($message);
635
                                $this->state=SASL_PLAIN_STATE_DONE;
636
                                break;
637
*/
638
                        case SASL_PLAIN_STATE_DONE:
639
                                $client->error="PLAIN authentication was finished without success";
640
                                return(SASL_FAIL);
641
                        default:
642
                                $client->error="invalid PLAIN authentication step state";
643
                                return(SASL_FAIL);
644
                }
645
                return(SASL_CONTINUE);
646
        }
647
};
648
 
649
// =============================================================================
650
 
651
/*
652
 * sasl.php
653
 *
654
 * @(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $
655
 *
656
 */
657
 
658
define("SASL_INTERACT", 2);
659
define("SASL_CONTINUE", 1);
660
define("SASL_OK",       0);
661
define("SASL_FAIL",    -1);
662
define("SASL_NOMECH",  -4);
663
 
664
class sasl_interact_class
665
{
666
    var $id;
667
    var $challenge;
668
    var $prompt;
669
    var $default_result;
670
    var $result;
671
};
672
 
673
class sasl_client_class
674
{
675
    /* Public variables */
676
 
677
    var $error='';
678
 
679
    var $mechanism='';
680
 
681
    var $encode_response=1;
682
 
683
    /* Private variables */
684
 
685
    var $driver;
686
    var $drivers=array(
687
        "Digest"   => array("digest_sasl_client_class"/*,   "digest_sasl_client.php"   */),
688
        "CRAM-MD5" => array("cram_md5_sasl_client_class"/*, "cram_md5_sasl_client.php" */),
689
        "LOGIN"    => array("login_sasl_client_class"/*,    "login_sasl_client.php"    */),
690
        "NTLM"     => array("ntlm_sasl_client_class"/*,     "ntlm_sasl_client.php"     */),
691
        "PLAIN"    => array("plain_sasl_client_class"/*,    "plain_sasl_client.php"    */),
692
        "Basic"    => array("basic_sasl_client_class"/*,    "basic_sasl_client.php"    */)
693
    );
694
    var $credentials=array();
695
 
696
    /* Public functions */
697
 
698
    Function SetCredential($key,$value)
699
    {
700
        $this->credentials[$key]=$value;
701
    }
702
 
703
    Function GetCredentials(&$credentials,$defaults,&$interactions)
704
    {
705
        Reset($credentials);
706
        $end=(GetType($key=Key($credentials))!="string");
707
        for(;!$end;)
708
        {
709
            if(!IsSet($this->credentials[$key]))
710
            {
711
                if(IsSet($defaults[$key]))
712
                    $credentials[$key]=$defaults[$key];
713
                    else
714
                    {
715
                        $this->error="the requested credential ".$key." is not defined";
716
                        return(SASL_NOMECH);
717
                    }
718
            }
719
            else
720
                $credentials[$key]=$this->credentials[$key];
721
                Next($credentials);
722
                $end=(GetType($key=Key($credentials))!="string");
723
        }
724
        return(SASL_CONTINUE);
725
    }
726
 
727
    Function Start($mechanisms, &$message, &$interactions)
728
    {
729
        if(strlen($this->error))
730
            return(SASL_FAIL);
731
        if(IsSet($this->driver))
732
            return($this->driver->Start($this,$message,$interactions));
733
        $no_mechanism_error="";
734
        for($m=0;$m<count($mechanisms);$m++)
735
        {
736
            $mechanism=$mechanisms[$m];
737
            if(IsSet($this->drivers[$mechanism]))
738
            {
739
                /*
740
                 * if(!class_exists($this->drivers[$mechanism][0]))
741
                 *      require(dirname(__FILE__)."/".$this->drivers[$mechanism][1]);
742
                 */
743
                $this->driver=new $this->drivers[$mechanism][0];
744
                if($this->driver->Initialize($this))
745
                {
746
                    $this->encode_response=1;
747
                    $status=$this->driver->Start($this,$message,$interactions);
748
                    switch($status)
749
                    {
750
                        case SASL_NOMECH:
751
                            Unset($this->driver);
752
                            if(strlen($no_mechanism_error)==0)
753
                                $no_mechanism_error=$this->error;
754
                                $this->error="";
755
                                break;
756
                        case SASL_CONTINUE:
757
                            $this->mechanism=$mechanism;
758
                            return($status);
759
                        default:
760
                            Unset($this->driver);
761
                            $this->error="";
762
                            return($status);
763
                    }
764
                }
765
                else
766
                {
767
                    Unset($this->driver);
768
                    if(strlen($no_mechanism_error)==0)
769
                        $no_mechanism_error=$this->error;
770
                        $this->error="";
771
                }
772
            }
773
        }
774
        $this->error=(strlen($no_mechanism_error) ? $no_mechanism_error : "it was not requested any of the authentication mechanisms that are supported");
775
        return(SASL_NOMECH);
776
    }
777
 
778
    Function Step($response, &$message, &$interactions)
779
    {
780
        if(strlen($this->error))
781
            return(SASL_FAIL);
782
            return($this->driver->Step($this,$response,$message,$interactions));
783
    }
784
 
785
};
786
 
787
// =============================================================================
788
 
789
 
790
/*
791
 * http.php
792
 *
171 daniel-mar 793
 * @(#) $Header: /opt2/ena/metal/http/http.php,v 1.94 2016/05/03 02:07:04 mlemos Exp $
794
 *
795
 */
796
 
251 daniel-mar 797
class http_class {
171 daniel-mar 798
 
269 daniel-mar 799
        /*public*/ const HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR =       -1;
800
        /*public*/ const HTTP_CLIENT_ERROR_NO_ERROR =                 0;
801
        /*public*/ const HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS =   1;
802
        /*public*/ const HTTP_CLIENT_ERROR_CANNOT_CONNECT =           2;
803
        /*public*/ const HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE =    3;
804
        /*public*/ const HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE = 4;
805
        /*public*/ const HTTP_CLIENT_ERROR_PROTOCOL_FAILURE =         5;
806
        /*public*/ const HTTP_CLIENT_ERROR_INVALID_PARAMETERS =       6;
171 daniel-mar 807
 
251 daniel-mar 808
        public $host_name="";
809
        public $host_port=0;
810
        public $proxy_host_name="";
811
        public $proxy_host_port=80;
812
        public $socks_host_name = '';
813
        public $socks_host_port = 1080;
814
        public $socks_version = '5';
171 daniel-mar 815
 
251 daniel-mar 816
        public $protocol="http";
817
        public $request_method="GET";
818
        public $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.94 $)';
819
        public $accept='';
820
        public $authentication_mechanism="";
821
        public $user;
822
        public $password;
823
        public $realm;
824
        public $workstation;
825
        public $proxy_authentication_mechanism="";
826
        public $proxy_user;
827
        public $proxy_password;
828
        public $proxy_realm;
829
        public $proxy_workstation;
830
        public $request_uri="";
831
        public $request="";
832
        public $request_headers=array();
833
        public $request_user;
834
        public $request_password;
835
        public $request_realm;
836
        public $request_workstation;
837
        public $proxy_request_user;
838
        public $proxy_request_password;
839
        public $proxy_request_realm;
840
        public $proxy_request_workstation;
841
        public $request_body="";
842
        public $request_arguments=array();
843
        public $protocol_version="1.1";
844
        public $timeout=0;
845
        public $data_timeout=0;
846
        public $debug=0;
847
        public $log_debug=0;
848
        public $debug_response_body=1;
849
        public $html_debug=0;
850
        public $support_cookies=1;
851
        public $cookies=array();
852
        public $error="";
853
        public $error_code = self::HTTP_CLIENT_ERROR_NO_ERROR;
854
        public $exclude_address="";
855
        public $follow_redirect=0;
856
        public $redirection_limit=5;
857
        public $response_status="";
858
        public $response_message="";
859
        public $file_buffer_length=8000;
860
        public $force_multipart_form_post=0;
861
        public $prefer_curl = 0;
862
        public $keep_alive = 1;
863
        public $sasl_authenticate = 1;
864
 
171 daniel-mar 865
        /* private variables - DO NOT ACCESS */
866
 
251 daniel-mar 867
        public $state="Disconnected";
868
        public $use_curl=0;
869
        public $connection=0;
870
        public $content_length=0;
871
        public $response="";
872
        public $read_response=0;
873
        public $read_length=0;
874
        public $request_host="";
875
        public $next_token="";
876
        public $redirection_level=0;
877
        public $chunked=0;
878
        public $remaining_chunk=0;
879
        public $last_chunk_read=0;
880
        public $months=array(
171 daniel-mar 881
                "Jan"=>"01",
882
                "Feb"=>"02",
883
                "Mar"=>"03",
884
                "Apr"=>"04",
885
                "May"=>"05",
886
                "Jun"=>"06",
887
                "Jul"=>"07",
888
                "Aug"=>"08",
889
                "Sep"=>"09",
890
                "Oct"=>"10",
891
                "Nov"=>"11",
892
                "Dec"=>"12");
251 daniel-mar 893
        public $session='';
894
        public $connection_close=0;
895
        public $force_close = 0;
896
        public $connected_host = '';
897
        public $connected_port = -1;
898
        public $connected_ssl = 0;
171 daniel-mar 899
 
900
        /* Private methods - DO NOT CALL */
901
 
902
        Function Tokenize($string,$separator="")
903
        {
904
                if(!strcmp($separator,""))
905
                {
906
                        $separator=$string;
907
                        $string=$this->next_token;
908
                }
909
                for($character=0;$character<strlen($separator);$character++)
910
                {
386 daniel-mar 911
                        $found = null;
171 daniel-mar 912
                        if(GetType($position=strpos($string,$separator[$character]))=="integer")
386 daniel-mar 913
                                $found=(!is_null($found) ? min($found,$position) : $position);
171 daniel-mar 914
                }
915
                if(IsSet($found))
916
                {
917
                        $this->next_token=substr($string,$found+1);
918
                        return(substr($string,0,$found));
919
                }
920
                else
921
                {
922
                        $this->next_token="";
923
                        return($string);
924
                }
925
        }
926
 
927
        Function CookieEncode($value, $name)
928
        {
929
                return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
930
        }
931
 
251 daniel-mar 932
        Function SetError($error, $error_code = self::HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
171 daniel-mar 933
        {
934
                $this->error_code = $error_code;
935
                return($this->error=$error);
936
        }
937
 
251 daniel-mar 938
        Function SetPHPError($error, &$php_error_message, $error_code = self::HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
171 daniel-mar 939
        {
940
                if(IsSet($php_error_message)
941
                && strlen($php_error_message))
942
                        $error.=": ".$php_error_message;
943
                return($this->SetError($error, $error_code));
944
        }
945
 
946
        Function SetDataAccessError($error,$check_connection=0)
947
        {
948
                $this->error=$error;
251 daniel-mar 949
                $this->error_code = self::HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
171 daniel-mar 950
                if(!$this->use_curl
951
                && function_exists("socket_get_status"))
952
                {
953
                        $status=socket_get_status($this->connection);
954
                        if($status["timed_out"])
955
                                $this->error.=": data access time out";
956
                        elseif($status["eof"])
957
                        {
958
                                if($check_connection)
959
                                        $this->error="";
960
                                else
961
                                        $this->error.=": the server disconnected";
962
                        }
963
                }
964
        }
965
 
966
        Function OutputDebug($message)
967
        {
968
                if($this->log_debug)
969
                {
970
                        if(strlen($this->log_file_name))
971
                                error_log($message."\n", 3, $this->log_file_name);
972
                        else
973
                                error_log($message);
974
                }
975
                else
976
                {
977
                        $message.="\n";
978
                        if($this->html_debug)
979
                                $message=str_replace("\n","<br />\n",HtmlEntities($message));
980
                        echo $message;
981
                        flush();
982
                }
983
        }
984
 
985
        Function GetLine()
986
        {
987
                for($line="";;)
988
                {
989
                        if($this->use_curl)
990
                        {
991
                                $eol=strpos($this->response,"\n",$this->read_response);
992
                                $data=($eol ? substr($this->response,$this->read_response,$eol+1-$this->read_response) : "");
993
                                $this->read_response+=strlen($data);
994
                        }
995
                        else
996
                        {
997
                                if(feof($this->connection))
998
                                {
999
                                        $this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
1000
                                        return(0);
1001
                                }
1002
                                $data=fgets($this->connection,100);
1003
                        }
1004
                        if(GetType($data)!="string"
1005
                        || strlen($data)==0)
1006
                        {
1007
                                $this->SetDataAccessError("it was not possible to read line from the HTTP server");
1008
                                return(0);
1009
                        }
1010
                        $line.=$data;
1011
                        $length=strlen($line);
1012
                        if($length
1013
                        && !strcmp(substr($line,$length-1,1),"\n"))
1014
                        {
1015
                                $length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
1016
                                $line=substr($line,0,$length);
1017
                                if($this->debug)
1018
                                        $this->OutputDebug("S $line");
1019
                                return($line);
1020
                        }
1021
                }
1022
        }
1023
 
1024
        Function PutLine($line)
1025
        {
1026
                if($this->debug)
1027
                        $this->OutputDebug("C $line");
1028
                if(!fputs($this->connection,$line."\r\n"))
1029
                {
1030
                        $this->SetDataAccessError("it was not possible to send a line to the HTTP server");
1031
                        return(0);
1032
                }
1033
                return(1);
1034
        }
1035
 
1036
        Function PutData($data)
1037
        {
1038
                if(strlen($data))
1039
                {
1040
                        if($this->debug)
1041
                                $this->OutputDebug('C '.$data);
1042
                        if(!fputs($this->connection,$data))
1043
                        {
1044
                                $this->SetDataAccessError("it was not possible to send data to the HTTP server");
1045
                                return(0);
1046
                        }
1047
                }
1048
                return(1);
1049
        }
1050
 
1051
        Function FlushData()
1052
        {
1053
                if(!fflush($this->connection))
1054
                {
1055
                        $this->SetDataAccessError("it was not possible to send data to the HTTP server");
1056
                        return(0);
1057
                }
1058
                return(1);
1059
        }
1060
 
1061
        Function ReadChunkSize()
1062
        {
1063
                if($this->remaining_chunk==0)
1064
                {
1065
                        $debug=$this->debug;
1066
                        if(!$this->debug_response_body)
1067
                                $this->debug=0;
1068
                        $line=$this->GetLine();
1069
                        $this->debug=$debug;
1070
                        if(GetType($line)!="string")
1071
                                return($this->SetError("could not read chunk start: ".$this->error, $this->error_code));
1072
                        $this->remaining_chunk=hexdec($line);
1073
                        if($this->remaining_chunk == 0)
1074
                        {
1075
                                if(!$this->debug_response_body)
1076
                                        $this->debug=0;
1077
                                $line=$this->GetLine();
1078
                                $this->debug=$debug;
1079
                                if(GetType($line)!="string")
1080
                                        return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
1081
                        }
1082
                }
1083
                return("");
1084
        }
1085
 
1086
        Function ReadBytes($length)
1087
        {
1088
                if($this->use_curl)
1089
                {
1090
                        $bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
1091
                        $this->read_response+=strlen($bytes);
1092
                        if($this->debug
1093
                        && $this->debug_response_body
1094
                        && strlen($bytes))
1095
                                $this->OutputDebug("S ".$bytes);
1096
                }
1097
                else
1098
                {
1099
                        if($this->chunked)
1100
                        {
1101
                                for($bytes="",$remaining=$length;$remaining;)
1102
                                {
1103
                                        if(strlen($this->ReadChunkSize()))
1104
                                                return("");
1105
                                        if($this->remaining_chunk==0)
1106
                                        {
1107
                                                $this->last_chunk_read=1;
1108
                                                break;
1109
                                        }
1110
                                        $ask=min($this->remaining_chunk,$remaining);
1111
                                        $chunk=@fread($this->connection,$ask);
1112
                                        $read=strlen($chunk);
1113
                                        if($read==0)
1114
                                        {
1115
                                                $this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
1116
                                                return("");
1117
                                        }
1118
                                        if($this->debug
1119
                                        && $this->debug_response_body)
1120
                                                $this->OutputDebug("S ".$chunk);
1121
                                        $bytes.=$chunk;
1122
                                        $this->remaining_chunk-=$read;
1123
                                        $remaining-=$read;
1124
                                        if($this->remaining_chunk==0)
1125
                                        {
1126
                                                if(feof($this->connection))
251 daniel-mar 1127
                                                        return($this->SetError("reached the end of data while reading the end of data chunk mark from the HTTP server", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 1128
                                                $data=@fread($this->connection,2);
1129
                                                if(strcmp($data,"\r\n"))
1130
                                                {
1131
                                                        $this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
1132
                                                        return("");
1133
                                                }
1134
                                        }
1135
                                }
1136
                        }
1137
                        else
1138
                        {
1139
                                $bytes=@fread($this->connection,$length);
1140
                                if(strlen($bytes))
1141
                                {
1142
                                        if($this->debug
1143
                                        && $this->debug_response_body)
1144
                                                $this->OutputDebug("S ".$bytes);
1145
                                }
1146
                                else
1147
                                        $this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
1148
                        }
1149
                }
1150
                return($bytes);
1151
        }
1152
 
1153
        Function EndOfInput()
1154
        {
1155
                if($this->use_curl)
1156
                        return($this->read_response>=strlen($this->response));
1157
                if($this->chunked)
1158
                        return($this->last_chunk_read);
1159
                if($this->content_length_set)
1160
                        return($this->content_length <= $this->read_length);
1161
                return(feof($this->connection));
1162
        }
1163
 
1164
        Function Resolve($domain, &$ip, $server_type)
1165
        {
1166
                if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
1167
                        $ip=$domain;
1168
                else
1169
                {
1170
                        if($this->debug)
1171
                                $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
1172
                        if(!strcmp($ip=@gethostbyname($domain),$domain))
1173
                                $ip="";
1174
                }
1175
                if(strlen($ip)==0
1176
                || (strlen($this->exclude_address)
1177
                && !strcmp(@gethostbyname($this->exclude_address),$ip)))
251 daniel-mar 1178
                        return($this->SetError("could not resolve the host domain \"".$domain."\"", self::HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
171 daniel-mar 1179
                return('');
1180
        }
1181
 
1182
        Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
1183
        {
1184
                $domain=$host_name;
1185
                $port = $host_port;
386 daniel-mar 1186
                $ip = '';
171 daniel-mar 1187
                if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
1188
                        return($error);
1189
                if(strlen($this->socks_host_name))
1190
                {
1191
                        switch($this->socks_version)
1192
                        {
1193
                                case '4':
1194
                                        $version = 4;
1195
                                        break;
1196
                                case '5':
1197
                                        $version = 5;
1198
                                        break;
1199
                                default:
1200
                                        return('it was not specified a supported SOCKS protocol version');
1201
                                        break;
1202
                        }
1203
                        $host_ip = $ip;
1204
                        $port = $this->socks_host_port;
1205
                        $host_server_type = $server_type;
1206
                        $server_type = 'SOCKS';
1207
                        if(strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type)))
1208
                                return($error);
1209
                }
1210
                if($this->debug)
1211
                        $this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
1212
                if($ssl)
1213
                        $ip="ssl://".$host_name;
386 daniel-mar 1214
                $errno = -1;
171 daniel-mar 1215
                if(($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0)
1216
                {
251 daniel-mar 1217
                        $error_code = self::HTTP_CLIENT_ERROR_CANNOT_CONNECT;
171 daniel-mar 1218
                        switch($errno)
1219
                        {
1220
                                case -3:
1221
                                        return($this->SetError("socket could not be created", $error_code));
1222
                                case -4:
1223
                                        return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
1224
                                case -5:
1225
                                        return($this->SetError("connection refused or timed out", $error_code));
1226
                                case -6:
1227
                                        return($this->SetError("fdopen() call failed", $error_code));
1228
                                case -7:
1229
                                        return($this->SetError("setvbuf() call failed", $error_code));
1230
                                default:
386 daniel-mar 1231
                                        $php_errormsg = '';
171 daniel-mar 1232
                                        return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
1233
                        }
1234
                }
1235
                else
1236
                {
1237
                        if($this->data_timeout
1238
                        && function_exists("socket_set_timeout"))
1239
                                socket_set_timeout($this->connection,$this->data_timeout,0);
1240
                        if(strlen($this->socks_host_name))
1241
                        {
1242
                                if($this->debug)
1243
                                        $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
1244
                                $send_error = 'it was not possible to send data to the SOCKS server';
1245
                                $receive_error = 'it was not possible to receive data from the SOCKS server';
1246
                                switch($version)
1247
                                {
1248
                                        case 4:
1249
                                                $command = 1;
1250
                                                $user = '';
1251
                                                if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
1252
                                                        $error = $this->SetDataAccessError($send_error);
1253
                                                else
1254
                                                {
1255
                                                        $response = fgets($this->connection, 9);
1256
                                                        if(strlen($response) != 8)
1257
                                                                $error = $this->SetDataAccessError($receive_error);
1258
                                                        else
1259
                                                        {
1260
                                                                $socks_errors = array(
1261
                                                                        "\x5a"=>'',
1262
                                                                        "\x5b"=>'request rejected',
1263
                                                                        "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
1264
                                                                        "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
1265
                                                                );
1266
                                                                $error_code = $response[1];
1267
                                                                $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
1268
                                                                if(strlen($error))
1269
                                                                        $error = 'SOCKS error: '.$error;
1270
                                                        }
1271
                                                }
1272
                                                break;
1273
                                        case 5:
1274
                                                if($this->debug)
1275
                                                        $this->OutputDebug('Negotiating the authentication method ...');
1276
                                                $methods = 1;
1277
                                                $method = 0;
1278
                                                if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
1279
                                                        $error = $this->SetDataAccessError($send_error);
1280
                                                else
1281
                                                {
1282
                                                        $response = fgets($this->connection, 3);
1283
                                                        if(strlen($response) != 2)
1284
                                                                $error = $this->SetDataAccessError($receive_error);
1285
                                                        elseif(Ord($response[1]) != $method)
1286
                                                                $error = 'the SOCKS server requires an authentication method that is not yet supported';
1287
                                                        else
1288
                                                        {
1289
                                                                if($this->debug)
1290
                                                                        $this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
1291
                                                                $command = 1;
1292
                                                                $address_type = 1;
1293
                                                                if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
1294
                                                                        $error = $this->SetDataAccessError($send_error);
1295
                                                                else
1296
                                                                {
1297
                                                                        $response = fgets($this->connection, 11);
1298
                                                                        if(strlen($response) != 10)
1299
                                                                                $error = $this->SetDataAccessError($receive_error);
1300
                                                                        else
1301
                                                                        {
1302
                                                                                $socks_errors = array(
1303
                                                                                        "\x00"=>'',
1304
                                                                                        "\x01"=>'general SOCKS server failure',
1305
                                                                                        "\x02"=>'connection not allowed by ruleset',
1306
                                                                                        "\x03"=>'Network unreachable',
1307
                                                                                        "\x04"=>'Host unreachable',
1308
                                                                                        "\x05"=>'Connection refused',
1309
                                                                                        "\x06"=>'TTL expired',
1310
                                                                                        "\x07"=>'Command not supported',
1311
                                                                                        "\x08"=>'Address type not supported'
1312
                                                                                );
1313
                                                                                $error_code = $response[1];
1314
                                                                                $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
1315
                                                                                if(strlen($error))
1316
                                                                                        $error = 'SOCKS error: '.$error;
1317
                                                                        }
1318
                                                                }
1319
                                                        }
1320
                                                }
1321
                                                break;
1322
                                        default:
1323
                                                $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
1324
                                                break;
1325
                                }
1326
                                if(strlen($error))
1327
                                {
1328
                                        fclose($this->connection);
1329
                                        return($error);
1330
                                }
1331
                        }
1332
                        if($this->debug)
1333
                                $this->OutputDebug("Connected to $host_name");
1334
                        if(strlen($this->proxy_host_name)
1335
                        && !strcmp(strtolower($this->protocol), 'https'))
1336
                        {
1337
                                if(function_exists('stream_socket_enable_crypto')
1338
                                && in_array('ssl', stream_get_transports()))
1339
                                        $this->state = "ConnectedToProxy";
1340
                                else
1341
                                {
1342
                                        $this->OutputDebug("It is not possible to start SSL after connecting to the proxy server. If the proxy refuses to forward the SSL request, you may need to upgrade to PHP 5.1 or later with OpenSSL support enabled.");
1343
                                        $this->state="Connected";
1344
                                }
1345
                        }
1346
                        else
1347
                                $this->state="Connected";
1348
                        return("");
1349
                }
1350
        }
1351
 
1352
        Function Disconnect()
1353
        {
1354
                if($this->debug)
1355
                        $this->OutputDebug("Disconnected from ".$this->connected_host);
1356
                if($this->use_curl)
1357
                {
1358
                        curl_close($this->connection);
1359
                        $this->response="";
1360
                }
1361
                else
1362
                        fclose($this->connection);
1363
                $this->state="Disconnected";
1364
                return("");
1365
        }
1366
 
1367
        /* Public methods */
1368
 
1369
        Function GetRequestArguments($url, &$arguments)
1370
        {
1371
                $this->error = '';
251 daniel-mar 1372
                $this->error_code = self::HTTP_CLIENT_ERROR_NO_ERROR;
171 daniel-mar 1373
                $arguments=array();
1374
                $url = str_replace(' ', '%20', $url);
1375
                $parameters=@parse_url($url);
1376
                if(!$parameters)
251 daniel-mar 1377
                        return($this->SetError("it was not specified a valid URL", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1378
                if(!IsSet($parameters["scheme"]))
251 daniel-mar 1379
                        return($this->SetError("it was not specified the protocol type argument", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1380
                switch(strtolower($parameters["scheme"]))
1381
                {
1382
                        case "http":
1383
                        case "https":
1384
                                $arguments["Protocol"]=$parameters["scheme"];
1385
                                break;
1386
                        default:
1387
                                return($parameters["scheme"]." connection scheme is not yet supported");
1388
                }
1389
                if(!IsSet($parameters["host"]))
251 daniel-mar 1390
                        return($this->SetError("it was not specified the connection host argument", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1391
                $arguments["HostName"]=$parameters["host"];
1392
                $arguments["Headers"]=array("Host"=>$parameters["host"].(IsSet($parameters["port"]) ? ":".$parameters["port"] : ""));
1393
                if(IsSet($parameters["user"]))
1394
                {
1395
                        $arguments["AuthUser"]=UrlDecode($parameters["user"]);
1396
                        if(!IsSet($parameters["pass"]))
1397
                                $arguments["AuthPassword"]="";
1398
                }
1399
                if(IsSet($parameters["pass"]))
1400
                {
1401
                        if(!IsSet($parameters["user"]))
1402
                                $arguments["AuthUser"]="";
1403
                        $arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
1404
                }
1405
                if(IsSet($parameters["port"]))
1406
                {
1407
                        if(strcmp($parameters["port"],strval(intval($parameters["port"]))))
251 daniel-mar 1408
                                return($this->SetError("it was not specified a valid connection host argument", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1409
                        $arguments["HostPort"]=intval($parameters["port"]);
1410
                }
1411
                else
1412
                        $arguments["HostPort"]=0;
1413
                $arguments["RequestURI"]=(IsSet($parameters["path"]) ? $parameters["path"] : "/").(IsSet($parameters["query"]) ? "?".$parameters["query"] : "");
1414
                if(strlen($this->user_agent))
1415
                        $arguments["Headers"]["User-Agent"]=$this->user_agent;
1416
                if(strlen($this->accept))
1417
                        $arguments["Headers"]["Accept"]=$this->accept;
1418
                return("");
1419
        }
1420
 
1421
        Function Open($arguments)
1422
        {
1423
                if(strlen($this->error))
1424
                        return($this->error);
251 daniel-mar 1425
                $error_code = self::HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
171 daniel-mar 1426
                if(IsSet($arguments["HostName"]))
1427
                        $this->host_name=$arguments["HostName"];
1428
                if(IsSet($arguments["HostPort"]))
1429
                        $this->host_port=$arguments["HostPort"];
1430
                if(IsSet($arguments["ProxyHostName"]))
1431
                        $this->proxy_host_name=$arguments["ProxyHostName"];
1432
                if(IsSet($arguments["ProxyHostPort"]))
1433
                        $this->proxy_host_port=$arguments["ProxyHostPort"];
1434
                if(IsSet($arguments["SOCKSHostName"]))
1435
                        $this->socks_host_name=$arguments["SOCKSHostName"];
1436
                if(IsSet($arguments["SOCKSHostPort"]))
1437
                        $this->socks_host_port=$arguments["SOCKSHostPort"];
1438
                if(IsSet($arguments["SOCKSVersion"]))
1439
                        $this->socks_version=$arguments["SOCKSVersion"];
1440
                if(IsSet($arguments["PreferCurl"]))
1441
                        $this->prefer_curl=$arguments["PreferCurl"];
1442
                if(IsSet($arguments["Protocol"]))
1443
                        $this->protocol=$arguments["Protocol"];
1444
                switch(strtolower($this->protocol))
1445
                {
1446
                        case "http":
1447
                                $default_port=80;
1448
                                break;
1449
                        case "https":
1450
                                $default_port=443;
1451
                                break;
1452
                        default:
251 daniel-mar 1453
                                return($this->SetError("it was not specified a valid connection protocol", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1454
                }
1455
                if(strlen($this->proxy_host_name)==0)
1456
                {
1457
                        if(strlen($this->host_name)==0)
251 daniel-mar 1458
                                return($this->SetError("it was not specified a valid hostname", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1459
                        $host_name=$this->host_name;
1460
                        $host_port=($this->host_port ? $this->host_port : $default_port);
1461
                        $server_type = 'HTTP';
1462
                }
1463
                else
1464
                {
1465
                        $host_name=$this->proxy_host_name;
1466
                        $host_port=$this->proxy_host_port;
1467
                        $server_type = 'HTTP proxy';
1468
                }
1469
                $ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
1470
                if($ssl
1471
                && strlen($this->socks_host_name))
251 daniel-mar 1472
                        return($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1473
                $this->use_curl=($ssl && $this->prefer_curl && function_exists("curl_init"));
1474
                switch($this->state)
1475
                {
1476
                        case 'Connected':
1477
                                if(!strcmp($host_name, $this->connected_host)
1478
                                && intval($host_port) == $this->connected_port
1479
                                && intval($ssl) == $this->connected_ssl)
1480
                                {
1481
                                        if($this->debug)
1482
                                                $this->OutputDebug("Reusing connection to ".$this->connected_host);
1483
                                        return('');
1484
                                }
1485
                                if(strlen($error = $this->Disconnect()))
1486
                                        return($error);
1487
                        case "Disconnected":
1488
                                break;
1489
                        default:
1490
                                return("1 already connected");
1491
                }
1492
                if($this->debug)
1493
                        $this->OutputDebug("Connecting to ".$this->host_name);
1494
                if($this->use_curl)
1495
                {
1496
                        $error=(($this->connection=curl_init($this->protocol."://".$this->host_name.($host_port==$default_port ? "" : ":".strval($host_port))."/")) ? "" : "Could not initialize a CURL session");
1497
                        if(strlen($error)==0)
1498
                        {
1499
                                if(IsSet($arguments["SSLCertificateFile"]))
1500
                                        curl_setopt($this->connection,CURLOPT_SSLCERT,$arguments["SSLCertificateFile"]);
1501
                                if(IsSet($arguments["SSLCertificatePassword"]))
1502
                                        curl_setopt($this->connection,CURLOPT_SSLCERTPASSWD,$arguments["SSLCertificatePassword"]);
1503
                                if(IsSet($arguments["SSLKeyFile"]))
1504
                                        curl_setopt($this->connection,CURLOPT_SSLKEY,$arguments["SSLKeyFile"]);
1505
                                if(IsSet($arguments["SSLKeyPassword"]))
1506
                                        curl_setopt($this->connection,CURLOPT_SSLKEYPASSWD,$arguments["SSLKeyPassword"]);
1507
                        }
1508
                        $this->state="Connected";
1509
                }
1510
                else
1511
                {
1512
                        $error="";
1513
                        if(strlen($this->proxy_host_name)
1514
                        && (IsSet($arguments["SSLCertificateFile"])
1515
                        || IsSet($arguments["SSLCertificateFile"])))
1516
                                $error="establishing SSL connections using certificates or private keys via non-SSL proxies is not supported";
1517
                        else
1518
                        {
1519
                                if($ssl)
1520
                                {
1521
                                        if(IsSet($arguments["SSLCertificateFile"]))
1522
                                                $error="establishing SSL connections using certificates is only supported when the cURL extension is enabled";
1523
                                        elseif(IsSet($arguments["SSLKeyFile"]))
1524
                                                $error="establishing SSL connections using a private key is only supported when the cURL extension is enabled";
1525
                                        else
1526
                                        {
1527
                                                $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
1528
                                                $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
1529
                                                if($php_version<4003000)
1530
                                                        $error="establishing SSL connections requires at least PHP version 4.3.0 or having the cURL extension enabled";
1531
                                                elseif(!function_exists("extension_loaded")
1532
                                                || !extension_loaded("openssl"))
1533
                                                        $error="establishing SSL connections requires the OpenSSL extension enabled";
1534
                                        }
1535
                                }
1536
                                if(strlen($error)==0)
1537
                                {
1538
                                        $error=$this->Connect($host_name, $host_port, $ssl, $server_type);
1539
                                        $error_code = $this->error_code;
1540
                                }
1541
                        }
1542
                }
1543
                if(strlen($error))
1544
                        return($this->SetError($error, $error_code));
1545
                $this->session=md5(uniqid(""));
1546
                $this->connected_host = $host_name;
1547
                $this->connected_port = intval($host_port);
1548
                $this->connected_ssl = intval($ssl);
1549
                return("");
1550
        }
1551
 
1552
        Function Close($force = 0)
1553
        {
1554
                if($this->state=="Disconnected")
1555
                        return("1 already disconnected");
1556
                if(!$this->force_close
1557
                && $this->keep_alive
1558
                && !$force
1559
                && $this->state == 'ResponseReceived')
1560
                {
1561
                        if($this->debug)
1562
                                $this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
1563
                        $this->state = 'Connected';
1564
                        return('');
1565
                }
1566
                return($this->Disconnect());
1567
        }
1568
 
1569
        Function PickCookies(&$cookies,$secure)
1570
        {
1571
                if(IsSet($this->cookies[$secure]))
1572
                {
1573
                        $now=gmdate("Y-m-d H-i-s");
1574
                        for($domain=0,Reset($this->cookies[$secure]);$domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$domain++)
1575
                        {
1576
                                $domain_pattern=Key($this->cookies[$secure]);
1577
                                $match=strlen($this->request_host)-strlen($domain_pattern);
1578
                                if($match>=0
1579
                                && !strcmp($domain_pattern,substr($this->request_host,$match))
1580
                                && ($match==0
1581
                                || $domain_pattern[0]=="."
1582
                                || $this->request_host[$match-1]=="."))
1583
                                {
1584
                                        for(Reset($this->cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($this->cookies[$secure][$domain_pattern]);Next($this->cookies[$secure][$domain_pattern]),$path_part++)
1585
                                        {
1586
                                                $path=Key($this->cookies[$secure][$domain_pattern]);
1587
                                                if(strlen($this->request_uri)>=strlen($path)
1588
                                                && substr($this->request_uri,0,strlen($path))==$path)
1589
                                                {
1590
                                                        for(Reset($this->cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($this->cookies[$secure][$domain_pattern][$path]);Next($this->cookies[$secure][$domain_pattern][$path]),$cookie++)
1591
                                                        {
1592
                                                                $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
1593
                                                                $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
1594
                                                                if($expires==""
1595
                                                                || strcmp($now,$expires)<0)
1596
                                                                        $cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
1597
                                                        }
1598
                                                }
1599
                                        }
1600
                                }
1601
                        }
1602
                }
1603
        }
1604
 
1605
        Function GetFileDefinition($file, &$definition)
1606
        {
1607
                $name="";
1608
                if(IsSet($file["FileName"]))
1609
                        $name=basename($file["FileName"]);
1610
                if(IsSet($file["Name"]))
1611
                        $name=$file["Name"];
1612
                if(strlen($name)==0)
1613
                        return("it was not specified the file part name");
1614
                if(IsSet($file["Content-Type"]))
1615
                {
1616
                        $content_type=$file["Content-Type"];
1617
                        $type=$this->Tokenize(strtolower($content_type),"/");
1618
                        $sub_type=$this->Tokenize("");
1619
                        switch($type)
1620
                        {
1621
                                case "text":
1622
                                case "image":
1623
                                case "audio":
1624
                                case "video":
1625
                                case "application":
1626
                                case "message":
1627
                                        break;
1628
                                case "automatic":
1629
                                        switch($sub_type)
1630
                                        {
1631
                                                case "name":
1632
                                                        switch(GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "")
1633
                                                        {
1634
                                                                case ".xls":
1635
                                                                        $content_type="application/excel";
1636
                                                                        break;
1637
                                                                case ".hqx":
1638
                                                                        $content_type="application/macbinhex40";
1639
                                                                        break;
1640
                                                                case ".doc":
1641
                                                                case ".dot":
1642
                                                                case ".wrd":
1643
                                                                        $content_type="application/msword";
1644
                                                                        break;
1645
                                                                case ".pdf":
1646
                                                                        $content_type="application/pdf";
1647
                                                                        break;
1648
                                                                case ".pgp":
1649
                                                                        $content_type="application/pgp";
1650
                                                                        break;
1651
                                                                case ".ps":
1652
                                                                case ".eps":
1653
                                                                case ".ai":
1654
                                                                        $content_type="application/postscript";
1655
                                                                        break;
1656
                                                                case ".ppt":
1657
                                                                        $content_type="application/powerpoint";
1658
                                                                        break;
1659
                                                                case ".rtf":
1660
                                                                        $content_type="application/rtf";
1661
                                                                        break;
1662
                                                                case ".tgz":
1663
                                                                case ".gtar":
1664
                                                                        $content_type="application/x-gtar";
1665
                                                                        break;
1666
                                                                case ".gz":
1667
                                                                        $content_type="application/x-gzip";
1668
                                                                        break;
1669
                                                                case ".php":
1670
                                                                case ".php3":
1671
                                                                        $content_type="application/x-httpd-php";
1672
                                                                        break;
1673
                                                                case ".js":
1674
                                                                        $content_type="application/x-javascript";
1675
                                                                        break;
1676
                                                                case ".ppd":
1677
                                                                case ".psd":
1678
                                                                        $content_type="application/x-photoshop";
1679
                                                                        break;
1680
                                                                case ".swf":
1681
                                                                case ".swc":
1682
                                                                case ".rf":
1683
                                                                        $content_type="application/x-shockwave-flash";
1684
                                                                        break;
1685
                                                                case ".tar":
1686
                                                                        $content_type="application/x-tar";
1687
                                                                        break;
1688
                                                                case ".zip":
1689
                                                                        $content_type="application/zip";
1690
                                                                        break;
1691
                                                                case ".mid":
1692
                                                                case ".midi":
1693
                                                                case ".kar":
1694
                                                                        $content_type="audio/midi";
1695
                                                                        break;
1696
                                                                case ".mp2":
1697
                                                                case ".mp3":
1698
                                                                case ".mpga":
1699
                                                                        $content_type="audio/mpeg";
1700
                                                                        break;
1701
                                                                case ".ra":
1702
                                                                        $content_type="audio/x-realaudio";
1703
                                                                        break;
1704
                                                                case ".wav":
1705
                                                                        $content_type="audio/wav";
1706
                                                                        break;
1707
                                                                case ".bmp":
1708
                                                                        $content_type="image/bitmap";
1709
                                                                        break;
1710
                                                                case ".gif":
1711
                                                                        $content_type="image/gif";
1712
                                                                        break;
1713
                                                                case ".iff":
1714
                                                                        $content_type="image/iff";
1715
                                                                        break;
1716
                                                                case ".jb2":
1717
                                                                        $content_type="image/jb2";
1718
                                                                        break;
1719
                                                                case ".jpg":
1720
                                                                case ".jpe":
1721
                                                                case ".jpeg":
1722
                                                                        $content_type="image/jpeg";
1723
                                                                        break;
1724
                                                                case ".jpx":
1725
                                                                        $content_type="image/jpx";
1726
                                                                        break;
1727
                                                                case ".png":
1728
                                                                        $content_type="image/png";
1729
                                                                        break;
1730
                                                                case ".tif":
1731
                                                                case ".tiff":
1732
                                                                        $content_type="image/tiff";
1733
                                                                        break;
1734
                                                                case ".wbmp":
1735
                                                                        $content_type="image/vnd.wap.wbmp";
1736
                                                                        break;
1737
                                                                case ".xbm":
1738
                                                                        $content_type="image/xbm";
1739
                                                                        break;
1740
                                                                case ".css":
1741
                                                                        $content_type="text/css";
1742
                                                                        break;
1743
                                                                case ".txt":
1744
                                                                        $content_type="text/plain";
1745
                                                                        break;
1746
                                                                case ".htm":
1747
                                                                case ".html":
1748
                                                                        $content_type="text/html";
1749
                                                                        break;
1750
                                                                case ".xml":
1751
                                                                        $content_type="text/xml";
1752
                                                                        break;
1753
                                                                case ".mpg":
1754
                                                                case ".mpe":
1755
                                                                case ".mpeg":
1756
                                                                        $content_type="video/mpeg";
1757
                                                                        break;
1758
                                                                case ".qt":
1759
                                                                case ".mov":
1760
                                                                        $content_type="video/quicktime";
1761
                                                                        break;
1762
                                                                case ".avi":
1763
                                                                        $content_type="video/x-ms-video";
1764
                                                                        break;
1765
                                                                case ".eml":
1766
                                                                        $content_type="message/rfc822";
1767
                                                                        break;
1768
                                                                default:
1769
                                                                        $content_type="application/octet-stream";
1770
                                                                        break;
1771
                                                        }
1772
                                                        break;
1773
                                                default:
1774
                                                        return($content_type." is not a supported automatic content type detection method");
1775
                                        }
1776
                                        break;
1777
                                default:
1778
                                        return($content_type." is not a supported file content type");
1779
                        }
1780
                }
1781
                else
1782
                        $content_type="application/octet-stream";
1783
                $definition=array(
1784
                        "Content-Type"=>$content_type,
1785
                        "NAME"=>$name
1786
                );
1787
                if(IsSet($file["FileName"]))
1788
                {
1789
                        if(GetType($length=@filesize($file["FileName"]))!="integer")
1790
                        {
1791
                                $error="it was not possible to determine the length of the file ".$file["FileName"];
386 daniel-mar 1792
                                /*
171 daniel-mar 1793
                                if(IsSet($php_errormsg)
1794
                                && strlen($php_errormsg))
1795
                                        $error.=": ".$php_errormsg;
386 daniel-mar 1796
                                */
171 daniel-mar 1797
                                if(!file_exists($file["FileName"]))
1798
                                        $error="it was not possible to access the file ".$file["FileName"];
1799
                                return($error);
1800
                        }
1801
                        $definition["FILENAME"]=$file["FileName"];
1802
                        $definition["Content-Length"]=$length;
1803
                }
1804
                elseif(IsSet($file["Data"]))
1805
                        $definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
1806
                else
1807
                        return("it was not specified a valid file name");
1808
                return("");
1809
        }
1810
 
1811
        Function ConnectFromProxy($arguments, &$headers)
1812
        {
1813
                $host = $this->host_name.':'.($this->host_port ? $this->host_port : 443);
1814
                $this->OutputDebug('Connecting from proxy to host '.$host);
1815
                if(!$this->PutLine('CONNECT '.$host.' HTTP/1.0')
1816
                || (strlen($this->user_agent)
1817
                && !$this->PutLine('User-Agent: '.$this->user_agent))
1818
                || (strlen($this->accept)
1819
                && !$this->PutLine('Accept: '.$this->accept))
1820
                || (IsSet($arguments['Headers']['Proxy-Authorization'])
1821
                && !$this->PutLine('Proxy-Authorization: '.$arguments['Headers']['Proxy-Authorization']))
1822
                || !$this->PutLine(''))
1823
                {
1824
                        $this->Disconnect();
1825
                        return($this->error);
1826
                }
1827
                $this->state = "ConnectSent";
1828
                if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1829
                        return($error);
1830
                $proxy_authorization="";
1831
                while(!strcmp($this->response_status, "100"))
1832
                {
1833
                        $this->state="ConnectSent";
1834
                        if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1835
                                return($error);
1836
                }
1837
                switch($this->response_status)
1838
                {
1839
                        case "200":
1840
                                $this->OutputDebug('Establishing the cryptography layer with host '.$host);
1841
                                if(!stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT))
1842
                                {
1843
                                        $this->OutputDebug('Failed establishing the cryptography layer with host '.$host);
386 daniel-mar 1844
                                        $php_errormsg = '';
251 daniel-mar 1845
                                        $this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', $php_errormsg, self::HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
171 daniel-mar 1846
                                        $this->Disconnect();
1847
                                        return($this->error);
1848
                                }
1849
                                $this->OutputDebug('Succeeded establishing the cryptography layer with host '.$host);
1850
                                $this->state = "Connected";
1851
                                break;
1852
                        case "407":
1853
                                if(strlen($error=$this->Authenticate($headers, -1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation)))
1854
                                        return($error);
1855
                                break;
1856
                        default:
251 daniel-mar 1857
                                return($this->SetError("unable to send request via proxy", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 1858
                }
1859
                return("");
1860
        }
1861
 
1862
        Function SendRequest($arguments)
1863
        {
1864
                if(strlen($this->error))
1865
                        return($this->error);
1866
                if(IsSet($arguments["ProxyUser"]))
1867
                        $this->proxy_request_user=$arguments["ProxyUser"];
1868
                elseif(IsSet($this->proxy_user))
1869
                        $this->proxy_request_user=$this->proxy_user;
1870
                if(IsSet($arguments["ProxyPassword"]))
1871
                        $this->proxy_request_password=$arguments["ProxyPassword"];
1872
                elseif(IsSet($this->proxy_password))
1873
                        $this->proxy_request_password=$this->proxy_password;
1874
                if(IsSet($arguments["ProxyRealm"]))
1875
                        $this->proxy_request_realm=$arguments["ProxyRealm"];
1876
                elseif(IsSet($this->proxy_realm))
1877
                        $this->proxy_request_realm=$this->proxy_realm;
1878
                if(IsSet($arguments["ProxyWorkstation"]))
1879
                        $this->proxy_request_workstation=$arguments["ProxyWorkstation"];
1880
                elseif(IsSet($this->proxy_workstation))
1881
                        $this->proxy_request_workstation=$this->proxy_workstation;
1882
                switch($this->state)
1883
                {
1884
                        case "Disconnected":
251 daniel-mar 1885
                                return($this->SetError("connection was not yet established", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1886
                        case "Connected":
1887
                                $connect = 0;
1888
                                break;
1889
                        case "ConnectedToProxy":
386 daniel-mar 1890
                                $headers = array();
171 daniel-mar 1891
                                if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
1892
                                        return($error);
1893
                                $connect = 1;
1894
                                break;
1895
                        default:
251 daniel-mar 1896
                                return($this->SetError("can not send request in the current connection state", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1897
                }
1898
                if(IsSet($arguments["RequestMethod"]))
1899
                        $this->request_method=$arguments["RequestMethod"];
1900
                if(IsSet($arguments["User-Agent"]))
1901
                        $this->user_agent=$arguments["User-Agent"];
1902
                if(!IsSet($arguments["Headers"]["User-Agent"])
1903
                && strlen($this->user_agent))
1904
                        $arguments["Headers"]["User-Agent"]=$this->user_agent;
1905
                if(IsSet($arguments["KeepAlive"]))
1906
                        $this->keep_alive=intval($arguments["KeepAlive"]);
1907
                if(!IsSet($arguments["Headers"]["Connection"])
1908
                && $this->keep_alive)
1909
                        $arguments["Headers"]["Connection"]='Keep-Alive';
1910
                if(IsSet($arguments["Accept"]))
1911
                        $this->user_agent=$arguments["Accept"];
1912
                if(!IsSet($arguments["Headers"]["Accept"])
1913
                && strlen($this->accept))
1914
                        $arguments["Headers"]["Accept"]=$this->accept;
1915
                if(strlen($this->request_method)==0)
251 daniel-mar 1916
                        return($this->SetError("it was not specified a valid request method", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1917
                if(IsSet($arguments["RequestURI"]))
1918
                        $this->request_uri=$arguments["RequestURI"];
1919
                if(strlen($this->request_uri)==0
1920
                || substr($this->request_uri,0,1)!="/")
251 daniel-mar 1921
                        return($this->SetError("it was not specified a valid request URI", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1922
                $this->request_arguments=$arguments;
1923
                $this->request_headers=(IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
1924
                $body_length=0;
1925
                $this->request_body="";
1926
                $get_body=1;
1927
                if($this->request_method=="POST"
1928
                || $this->request_method=="PUT")
1929
                {
1930
                        if(IsSet($arguments['StreamRequest']))
1931
                        {
1932
                                $get_body = 0;
1933
                                $this->request_headers["Transfer-Encoding"]="chunked";
1934
                        }
1935
                        elseif(IsSet($arguments["PostFiles"])
1936
                        || ($this->force_multipart_form_post
1937
                        && IsSet($arguments["PostValues"])))
1938
                        {
1939
                                $boundary="--".md5(uniqid(time()));
1940
                                $this->request_headers["Content-Type"]="multipart/form-data; boundary=".$boundary.(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1941
                                $post_parts=array();
1942
                                if(IsSet($arguments["PostValues"]))
1943
                                {
1944
                                        $values=$arguments["PostValues"];
1945
                                        if(GetType($values)!="array")
251 daniel-mar 1946
                                                return($this->SetError("it was not specified a valid POST method values array", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1947
                                        for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
1948
                                        {
1949
                                                $input=Key($values);
1950
                                                $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"\r\n\r\n";
1951
                                                $data=$values[$input];
1952
                                                $post_parts[]=array("HEADERS"=>$headers,"DATA"=>$data);
1953
                                                $body_length+=strlen($headers)+strlen($data)+strlen("\r\n");
1954
                                        }
1955
                                }
1956
                                $body_length+=strlen("--".$boundary."--\r\n");
1957
                                $files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
1958
                                Reset($files);
1959
                                $end=(GetType($input=Key($files))!="string");
1960
                                for(;!$end;)
1961
                                {
386 daniel-mar 1962
                                        $definition = array();
171 daniel-mar 1963
                                        if(strlen($error=$this->GetFileDefinition($files[$input],$definition)))
1964
                                                return("3 ".$error);
1965
                                        $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"; filename=\"".$definition["NAME"]."\"\r\nContent-Type: ".$definition["Content-Type"]."\r\n\r\n";
1966
                                        $part=count($post_parts);
1967
                                        $post_parts[$part]=array("HEADERS"=>$headers);
1968
                                        if(IsSet($definition["FILENAME"]))
1969
                                        {
1970
                                                $post_parts[$part]["FILENAME"]=$definition["FILENAME"];
1971
                                                $data="";
1972
                                        }
1973
                                        else
1974
                                                $data=$definition["DATA"];
1975
                                        $post_parts[$part]["DATA"]=$data;
1976
                                        $body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
1977
                                        Next($files);
1978
                                        $end=(GetType($input=Key($files))!="string");
1979
                                }
1980
                                $get_body=0;
1981
                        }
1982
                        elseif(IsSet($arguments["PostValues"]))
1983
                        {
1984
                                $values=$arguments["PostValues"];
1985
                                if(GetType($values)!="array")
251 daniel-mar 1986
                                        return($this->SetError("it was not specified a valid POST method values array", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 1987
                                for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
1988
                                {
1989
                                        $k=Key($values);
1990
                                        if(GetType($values[$k])=="array")
1991
                                        {
1992
                                                for($v = 0; $v < count($values[$k]); $v++)
1993
                                                {
1994
                                                        if($value+$v>0)
1995
                                                                $this->request_body.="&";
1996
                                                        $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
1997
                                                }
1998
                                        }
1999
                                        else
2000
                                        {
2001
                                                if($value>0)
2002
                                                        $this->request_body.="&";
2003
                                                $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k]);
2004
                                        }
2005
                                }
2006
                                $this->request_headers["Content-Type"]="application/x-www-form-urlencoded".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
2007
                                $get_body=0;
2008
                        }
2009
                }
2010
                if($get_body
2011
                && (IsSet($arguments["Body"])
2012
                || IsSet($arguments["BodyStream"])))
2013
                {
2014
                        if(IsSet($arguments["Body"]))
2015
                                $this->request_body=$arguments["Body"];
2016
                        else
2017
                        {
2018
                                $stream=$arguments["BodyStream"];
2019
                                $this->request_body="";
2020
                                for($part=0; $part<count($stream); $part++)
2021
                                {
2022
                                        if(IsSet($stream[$part]["Data"]))
2023
                                                $this->request_body.=$stream[$part]["Data"];
2024
                                        elseif(IsSet($stream[$part]["File"]))
2025
                                        {
386 daniel-mar 2026
                                                if(!($file=@fopen($stream[$part]["File"],"rb"))) {
2027
                                                        $php_errormsg = '';
251 daniel-mar 2028
                                                        return($this->SetPHPError("could not open upload file ".$stream[$part]["File"], $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
386 daniel-mar 2029
                                                }
171 daniel-mar 2030
                                                while(!feof($file))
2031
                                                {
2032
                                                        if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
2033
                                                        {
251 daniel-mar 2034
                                                                $error=$this->SetPHPError("could not read body stream file ".$stream[$part]["File"], $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2035
                                                                fclose($file);
2036
                                                                return($error);
2037
                                                        }
2038
                                                        $this->request_body.=$block;
2039
                                                }
2040
                                                fclose($file);
2041
                                        }
2042
                                        else
2043
                                                return("5 it was not specified a valid file or data body stream element at position ".$part);
2044
                                }
2045
                        }
2046
                        if(!IsSet($this->request_headers["Content-Type"]))
2047
                                $this->request_headers["Content-Type"]="application/octet-stream".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
2048
                }
2049
                if(IsSet($arguments["AuthUser"]))
2050
                        $this->request_user=$arguments["AuthUser"];
2051
                elseif(IsSet($this->user))
2052
                        $this->request_user=$this->user;
2053
                if(IsSet($arguments["AuthPassword"]))
2054
                        $this->request_password=$arguments["AuthPassword"];
2055
                elseif(IsSet($this->password))
2056
                        $this->request_password=$this->password;
2057
                if(IsSet($arguments["AuthRealm"]))
2058
                        $this->request_realm=$arguments["AuthRealm"];
2059
                elseif(IsSet($this->realm))
2060
                        $this->request_realm=$this->realm;
2061
                if(IsSet($arguments["AuthWorkstation"]))
2062
                        $this->request_workstation=$arguments["AuthWorkstation"];
2063
                elseif(IsSet($this->workstation))
2064
                        $this->request_workstation=$this->workstation;
2065
                if(strlen($this->proxy_host_name)==0
2066
                || $connect)
2067
                        $request_uri=$this->request_uri;
2068
                else
2069
                {
2070
                        switch(strtolower($this->protocol))
2071
                        {
2072
                                case "http":
2073
                                        $default_port=80;
2074
                                        break;
2075
                                case "https":
2076
                                        $default_port=443;
2077
                                        break;
2078
                        }
2079
                        $request_uri=strtolower($this->protocol)."://".$this->host_name.(($this->host_port==0 || $this->host_port==$default_port) ? "" : ":".$this->host_port).$this->request_uri;
2080
                }
2081
                if($this->use_curl)
2082
                {
386 daniel-mar 2083
                        $m = array();
171 daniel-mar 2084
                        $version=(GetType($v=curl_version())=="array" ? (IsSet($v["version"]) ? $v["version"] : "0.0.0") : (preg_match("/^libcurl\\/([0-9]+\\.[0-9]+\\.[0-9]+)/",$v,$m) ? $m[1] : "0.0.0"));
2085
                        $curl_version=100000*intval($this->Tokenize($version,"."))+1000*intval($this->Tokenize("."))+intval($this->Tokenize(""));
2086
                        $protocol_version=($curl_version<713002 ? "1.0" : $this->protocol_version);
2087
                }
2088
                else
2089
                        $protocol_version=$this->protocol_version;
2090
                $this->request=$this->request_method." ".$request_uri." HTTP/".$protocol_version;
2091
                if($body_length
2092
                || ($body_length=strlen($this->request_body))
2093
                || !strcmp($this->request_method, 'POST'))
2094
                        $this->request_headers["Content-Length"]=$body_length;
2095
                for($headers=array(),$host_set=0,Reset($this->request_headers),$header=0;$header<count($this->request_headers);Next($this->request_headers),$header++)
2096
                {
2097
                        $header_name=Key($this->request_headers);
2098
                        $header_value=$this->request_headers[$header_name];
2099
                        if(GetType($header_value)=="array")
2100
                        {
2101
                                for(Reset($header_value),$value=0;$value<count($header_value);Next($header_value),$value++)
2102
                                        $headers[]=$header_name.": ".$header_value[Key($header_value)];
2103
                        }
2104
                        else
2105
                                $headers[]=$header_name.": ".$header_value;
2106
                        if(strtolower(Key($this->request_headers))=="host")
2107
                        {
2108
                                $this->request_host=strtolower($header_value);
2109
                                $host_set=1;
2110
                        }
2111
                }
2112
                if(!$host_set)
2113
                {
2114
                        $headers[]="Host: ".$this->host_name;
2115
                        $this->request_host=strtolower($this->host_name);
2116
                }
2117
                if(count($this->cookies))
2118
                {
2119
                        $cookies=array();
2120
                        $this->PickCookies($cookies,0);
2121
                        if(strtolower($this->protocol)=="https")
2122
                                $this->PickCookies($cookies,1);
2123
                        if(count($cookies))
2124
                        {
2125
                                $h=count($headers);
2126
                                $headers[$h]="Cookie:";
2127
                                for(Reset($cookies),$cookie=0;$cookie<count($cookies);Next($cookies),$cookie++)
2128
                                {
2129
                                        $cookie_name=Key($cookies);
2130
                                        $headers[$h].=" ".$cookie_name."=".$cookies[$cookie_name]["value"].";";
2131
                                }
2132
                        }
2133
                }
2134
                $next_state = "RequestSent";
2135
                if($this->use_curl)
2136
                {
2137
                        if(IsSet($arguments['StreamRequest']))
251 daniel-mar 2138
                                return($this->SetError("Streaming request data is not supported when using Curl", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2139
                        if($body_length
2140
                        && strlen($this->request_body)==0)
2141
                        {
2142
                                for($request_body="",$success=1,$part=0;$part<count($post_parts);$part++)
2143
                                {
2144
                                        $request_body.=$post_parts[$part]["HEADERS"].$post_parts[$part]["DATA"];
2145
                                        if(IsSet($post_parts[$part]["FILENAME"]))
2146
                                        {
2147
                                                if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
2148
                                                {
386 daniel-mar 2149
                                                        $php_errormsg = '';
251 daniel-mar 2150
                                                        $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2151
                                                        $success=0;
2152
                                                        break;
2153
                                                }
2154
                                                while(!feof($file))
2155
                                                {
2156
                                                        if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
2157
                                                        {
251 daniel-mar 2158
                                                                $this->SetPHPError("could not read upload file", $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2159
                                                                $success=0;
2160
                                                                break;
2161
                                                        }
2162
                                                        $request_body.=$block;
2163
                                                }
2164
                                                fclose($file);
2165
                                                if(!$success)
2166
                                                        break;
2167
                                        }
2168
                                        $request_body.="\r\n";
2169
                                }
2170
                                $request_body.="--".$boundary."--\r\n";
2171
                        }
2172
                        else
2173
                                $request_body=$this->request_body;
2174
                        curl_setopt($this->connection,CURLOPT_HEADER,1);
2175
                        curl_setopt($this->connection,CURLOPT_RETURNTRANSFER,1);
2176
                        if($this->timeout)
2177
                                curl_setopt($this->connection,CURLOPT_TIMEOUT,$this->timeout);
2178
                        curl_setopt($this->connection,CURLOPT_SSL_VERIFYPEER,0);
2179
                        curl_setopt($this->connection,CURLOPT_SSL_VERIFYHOST,0);
2180
                        $request=$this->request."\r\n".implode("\r\n",$headers)."\r\n\r\n".$request_body;
2181
                        curl_setopt($this->connection,CURLOPT_CUSTOMREQUEST,$request);
2182
                        if($this->debug)
2183
                                $this->OutputDebug("C ".$request);
239 daniel-mar 2184
                        if(!($success=(strlen($this->response=@curl_exec($this->connection))!=0)))
171 daniel-mar 2185
                        {
2186
                                $error=curl_error($this->connection);
251 daniel-mar 2187
                                $this->SetError("Could not execute the request".(strlen($error) ? ": ".$error : ""), self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
171 daniel-mar 2188
                        }
2189
                }
2190
                else
2191
                {
2192
                        if(($success=$this->PutLine($this->request)))
2193
                        {
2194
                                for($header=0;$header<count($headers);$header++)
2195
                                {
2196
                                        if(!$success=$this->PutLine($headers[$header]))
2197
                                                break;
2198
                                }
2199
                                if($success
2200
                                && ($success=$this->PutLine("")))
2201
                                {
2202
                                        if(IsSet($arguments['StreamRequest']))
2203
                                                $next_state = "SendingRequestBody";
2204
                                        elseif($body_length)
2205
                                        {
2206
                                                if(strlen($this->request_body))
2207
                                                        $success=$this->PutData($this->request_body);
2208
                                                else
2209
                                                {
2210
                                                        for($part=0;$part<count($post_parts);$part++)
2211
                                                        {
2212
                                                                if(!($success=$this->PutData($post_parts[$part]["HEADERS"]))
2213
                                                                || !($success=$this->PutData($post_parts[$part]["DATA"])))
2214
                                                                        break;
2215
                                                                if(IsSet($post_parts[$part]["FILENAME"]))
2216
                                                                {
2217
                                                                        if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
2218
                                                                        {
251 daniel-mar 2219
                                                                                $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2220
                                                                                $success=0;
2221
                                                                                break;
2222
                                                                        }
2223
                                                                        while(!feof($file))
2224
                                                                        {
2225
                                                                                if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
2226
                                                                                {
251 daniel-mar 2227
                                                                                        $this->SetPHPError("could not read upload file", $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2228
                                                                                        $success=0;
2229
                                                                                        break;
2230
                                                                                }
2231
                                                                                if(!($success=$this->PutData($block)))
2232
                                                                                        break;
2233
                                                                        }
2234
                                                                        fclose($file);
2235
                                                                        if(!$success)
2236
                                                                                break;
2237
                                                                }
2238
                                                                if(!($success=$this->PutLine("")))
2239
                                                                        break;
2240
                                                        }
2241
                                                        if($success)
2242
                                                                $success=$this->PutLine("--".$boundary."--");
2243
                                                }
2244
                                                if($success)
2245
                                                        $sucess=$this->FlushData();
2246
                                        }
2247
                                }
2248
                        }
2249
                }
2250
                if(!$success)
2251
                        return($this->SetError("could not send the HTTP request: ".$this->error, $this->error_code));
2252
                $this->state=$next_state;
2253
                return("");
2254
        }
2255
 
2256
        Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
2257
        {
2258
                if(strlen($this->error))
2259
                        return($this->error);
2260
                if(strlen($name)==0)
251 daniel-mar 2261
                        return($this->SetError("it was not specified a valid cookie name", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2262
                if(strlen($path)==0
2263
                || strcmp($path[0],"/"))
251 daniel-mar 2264
                        return($this->SetError($path." is not a valid path for setting cookie ".$name, self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2265
                if($domain==""
2266
                || !strpos($domain,".",$domain[0]=="." ? 1 : 0))
251 daniel-mar 2267
                        return($this->SetError($domain." is not a valid domain for setting cookie ".$name, self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2268
                $domain=strtolower($domain);
2269
                if(!strcmp($domain[0],"."))
2270
                        $domain=substr($domain,1);
2271
                if(!$verbatim)
2272
                {
2273
                        $name=$this->CookieEncode($name,1);
2274
                        $value=$this->CookieEncode($value,0);
2275
                }
2276
                $secure=intval($secure);
2277
                $this->cookies[$secure][$domain][$path][$name]=array(
2278
                        "name"=>$name,
2279
                        "value"=>$value,
2280
                        "domain"=>$domain,
2281
                        "path"=>$path,
2282
                        "expires"=>$expires,
2283
                        "secure"=>$secure
2284
                );
2285
                return("");
2286
        }
2287
 
2288
        Function SendRequestBody($data, $end_of_data)
2289
        {
2290
                if(strlen($this->error))
2291
                        return($this->error);
2292
                switch($this->state)
2293
                {
2294
                        case "Disconnected":
251 daniel-mar 2295
                                return($this->SetError("connection was not yet established", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2296
                        case "Connected":
2297
                        case "ConnectedToProxy":
251 daniel-mar 2298
                                return($this->SetError("request was not sent", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2299
                        case "SendingRequestBody":
2300
                                break;
2301
                        case "RequestSent":
251 daniel-mar 2302
                                return($this->SetError("request body was already sent", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2303
                        default:
251 daniel-mar 2304
                                return($this->SetError("can not send the request body in the current connection state", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2305
                }
2306
                $length = strlen($data);
2307
                if($length)
2308
                {
2309
                        $size = dechex($length)."\r\n";
2310
                        if(!$this->PutData($size)
2311
                        || !$this->PutData($data))
2312
                                return($this->error);
2313
                }
2314
                if($end_of_data)
2315
                {
2316
                        $size = "0\r\n";
2317
                        if(!$this->PutData($size))
2318
                                return($this->error);
2319
                        $this->state = "RequestSent";
2320
                }
2321
                return("");
2322
        }
2323
 
2324
        Function ReadReplyHeadersResponse(&$headers)
2325
        {
2326
                $headers=array();
2327
                if(strlen($this->error))
2328
                        return($this->error);
2329
                switch($this->state)
2330
                {
2331
                        case "Disconnected":
251 daniel-mar 2332
                                return($this->SetError("connection was not yet established", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2333
                        case "Connected":
251 daniel-mar 2334
                                return($this->SetError("request was not sent", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2335
                        case "ConnectedToProxy":
251 daniel-mar 2336
                                return($this->SetError("connection from the remote server from the proxy was not yet established", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2337
                        case "SendingRequestBody":
251 daniel-mar 2338
                                return($this->SetError("request body data was not completely sent", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2339
                        case "ConnectSent":
2340
                                $connect = 1;
2341
                                break;
2342
                        case "RequestSent":
2343
                                $connect = 0;
2344
                                break;
2345
                        default:
251 daniel-mar 2346
                                return($this->SetError("can not get request headers in the current connection state", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2347
                }
2348
                $this->content_length=$this->read_length=$this->read_response=$this->remaining_chunk=0;
2349
                $this->content_length_set=$this->chunked=$this->last_chunk_read=$chunked=0;
2350
                $this->force_close = $this->connection_close=0;
2351
                for($this->response_status="";;)
2352
                {
2353
                        $line=$this->GetLine();
2354
                        if(GetType($line)!="string")
2355
                                return($this->SetError("could not read request reply: ".$this->error, $this->error_code));
2356
                        if(strlen($this->response_status)==0)
2357
                        {
386 daniel-mar 2358
                                $matches = array();
171 daniel-mar 2359
                                if(!preg_match($match="/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i",$line,$matches))
251 daniel-mar 2360
                                        return($this->SetError("it was received an unexpected HTTP response status", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2361
                                $this->response_status=$matches[1];
2362
                                $this->response_message=$matches[2];
2363
                                if($this->response_status == 204)
2364
                                {
2365
                                        $this->content_length = 0;
2366
                                        $this->content_length_set = 1;
2367
                                }
2368
                        }
2369
                        if($line=="")
2370
                        {
2371
                                if(strlen($this->response_status)==0)
251 daniel-mar 2372
                                        return($this->SetError("it was not received HTTP response status", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2373
                                $this->state=($connect ? "GotConnectHeaders" : "GotReplyHeaders");
2374
                                break;
2375
                        }
2376
                        $header_name=strtolower($this->Tokenize($line,":"));
2377
                        $header_value=Trim(Chop($this->Tokenize("\r\n")));
2378
                        if(IsSet($headers[$header_name]))
2379
                        {
2380
                                if(GetType($headers[$header_name])=="string")
2381
                                        $headers[$header_name]=array($headers[$header_name]);
2382
                                $headers[$header_name][]=$header_value;
2383
                        }
2384
                        else
2385
                                $headers[$header_name]=$header_value;
2386
                        if(!$connect)
2387
                        {
2388
                                switch($header_name)
2389
                                {
2390
                                        case "content-length":
2391
                                                $this->content_length=intval($headers[$header_name]);
2392
                                                $this->content_length_set=1;
2393
                                                break;
2394
                                        case "transfer-encoding":
2395
                                                $encoding=$this->Tokenize($header_value,"; \t");
2396
                                                if(!$this->use_curl
2397
                                                && !strcmp($encoding,"chunked"))
2398
                                                        $chunked=1;
2399
                                                break;
2400
                                        case "set-cookie":
2401
                                                if($this->support_cookies)
2402
                                                {
2403
                                                        if(GetType($headers[$header_name])=="array")
2404
                                                                $cookie_headers=$headers[$header_name];
2405
                                                        else
2406
                                                                $cookie_headers=array($headers[$header_name]);
2407
                                                        for($cookie=0;$cookie<count($cookie_headers);$cookie++)
2408
                                                        {
2409
                                                                $cookie_name=trim($this->Tokenize($cookie_headers[$cookie],"="));
2410
                                                                $cookie_value=$this->Tokenize(";");
2411
                                                                $domain=$this->request_host;
2412
                                                                $path="/";
2413
                                                                $expires="";
2414
                                                                $secure=0;
2415
                                                                while(($name = strtolower(trim(UrlDecode($this->Tokenize("=")))))!="")
2416
                                                                {
2417
                                                                        $value=UrlDecode($this->Tokenize(";"));
2418
                                                                        switch($name)
2419
                                                                        {
2420
                                                                                case "domain":
2421
                                                                                        $domain=$value;
2422
                                                                                        break;
2423
                                                                                case "path":
2424
                                                                                        $path=$value;
2425
                                                                                        break;
2426
                                                                                case "expires":
2427
                                                                                        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))
2428
                                                                                        {
2429
                                                                                                $year=intval($matches[5]);
2430
                                                                                                if($year<1900)
2431
                                                                                                        $year+=($year<70 ? 2000 : 1900);
2432
                                                                                                $expires="$year-".$this->months[$matches[4]]."-".$matches[3]." ".$matches[6].":".$matches[7].":".$matches[8];
2433
                                                                                        }
2434
                                                                                        break;
2435
                                                                                case "secure":
2436
                                                                                        $secure=1;
2437
                                                                                        break;
2438
                                                                        }
2439
                                                                }
2440
                                                                if(strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path , $domain, $secure, 1)))
2441
                                                                        $this->error="";
2442
                                                        }
2443
                                                }
2444
                                                break;
2445
                                        case "connection":
2446
                                                $this->force_close = $this->connection_close=!strcmp(strtolower($header_value),"close");
2447
                                                break;
2448
                                }
2449
                        }
2450
                }
2451
                $this->chunked=$chunked;
2452
                if($this->content_length_set)
2453
                        $this->connection_close=0;
2454
                return("");
2455
        }
2456
 
2457
        Function Redirect(&$headers)
2458
        {
2459
                if($this->follow_redirect)
2460
                {
2461
                        if(!IsSet($headers["location"])
2462
                        || (GetType($headers["location"])!="array"
2463
                        && strlen($location=$headers["location"])==0)
2464
                        || (GetType($headers["location"])=="array"
2465
                        && strlen($location=$headers["location"][0])==0))
251 daniel-mar 2466
                                return($this->SetError("it was received a redirect without location URL", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2467
                        if(strcmp($location[0],"/"))
2468
                        {
2469
                                if(!($location_arguments=@parse_url($location)))
251 daniel-mar 2470
                                        return($this->SetError("the server did not return a valid redirection location URL", self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2471
                                if(!IsSet($location_arguments["scheme"]))
2472
                                        $location=((GetType($end=strrpos($this->request_uri,"/"))=="integer" && $end>1) ? substr($this->request_uri,0,$end) : "")."/".$location;
2473
                        }
2474
                        if(!strcmp($location[0],"/"))
2475
                                $location=$this->protocol."://".$this->host_name.($this->host_port ? ":".$this->host_port : "").$location;
386 daniel-mar 2476
                        $arguments = array();
171 daniel-mar 2477
                        $error=$this->GetRequestArguments($location,$arguments);
2478
                        if(strlen($error))
251 daniel-mar 2479
                                return($this->SetError("could not process redirect url: ".$error, self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2480
                        $arguments["RequestMethod"]="GET";
2481
                        if(strlen($error=$this->Close())==0
2482
                        && strlen($error=$this->Open($arguments))==0
2483
                        && strlen($error=$this->SendRequest($arguments))==0)
2484
                        {
2485
                                $this->redirection_level++;
2486
                                if($this->redirection_level>$this->redirection_limit)
2487
                                {
2488
                                        $error="it was exceeded the limit of request redirections";
251 daniel-mar 2489
                                        $this->error_code = self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
171 daniel-mar 2490
                                }
2491
                                else
2492
                                        $error=$this->ReadReplyHeaders($headers);
2493
                                $this->redirection_level--;
2494
                        }
2495
                        if(strlen($error))
2496
                                return($this->SetError($error, $this->error_code));
2497
                }
2498
                return("");
2499
        }
2500
 
2501
        Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
2502
        {
2503
                if($proxy)
2504
                {
2505
                        $authenticate_header="proxy-authenticate";
2506
                        $authorization_header="Proxy-Authorization";
2507
                        $authenticate_status="407";
2508
                        $authentication_mechanism=$this->proxy_authentication_mechanism;
2509
                }
2510
                else
2511
                {
2512
                        $authenticate_header="www-authenticate";
2513
                        $authorization_header="Authorization";
2514
                        $authenticate_status="401";
2515
                        $authentication_mechanism=$this->authentication_mechanism;
2516
                }
2517
                if(IsSet($headers[$authenticate_header])
2518
                && $this->sasl_authenticate)
2519
                {
2520
                        if(function_exists("class_exists")
2521
                        && !class_exists("sasl_client_class"))
251 daniel-mar 2522
                                return($this->SetError("the SASL client class needs to be loaded to be able to authenticate".($proxy ? " with the proxy server" : "")." and access this site", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2523
                        if(GetType($headers[$authenticate_header])=="array")
2524
                                $authenticate=$headers[$authenticate_header];
2525
                        else
2526
                                $authenticate=array($headers[$authenticate_header]);
2527
                        for($response="", $mechanisms=array(),$m=0;$m<count($authenticate);$m++)
2528
                        {
2529
                                $mechanism=$this->Tokenize($authenticate[$m]," ");
2530
                                $response=$this->Tokenize("");
2531
                                if(strlen($authentication_mechanism))
2532
                                {
2533
                                        if(!strcmp($authentication_mechanism,$mechanism))
2534
                                        {
2535
                                                $mechanisms[]=$mechanism;
2536
                                                break;
2537
                                        }
2538
                                }
2539
                                else
2540
                                        $mechanisms[]=$mechanism;
2541
                        }
2542
                        $sasl=new sasl_client_class;
2543
                        if(IsSet($user))
2544
                                $sasl->SetCredential("user",$user);
2545
                        if(IsSet($password))
2546
                                $sasl->SetCredential("password",$password);
2547
                        if(IsSet($realm))
2548
                                $sasl->SetCredential("realm",$realm);
2549
                        if(IsSet($workstation))
2550
                                $sasl->SetCredential("workstation",$workstation);
2551
                        $sasl->SetCredential("uri",$this->request_uri);
2552
                        $sasl->SetCredential("method",$this->request_method);
2553
                        $sasl->SetCredential("session",$this->session);
2554
                        do
2555
                        {
386 daniel-mar 2556
                                $message = null;
2557
                                $interactions = null;
171 daniel-mar 2558
                                $status=$sasl->Start($mechanisms,$message,$interactions);
2559
                        }
2560
                        while($status==SASL_INTERACT);
2561
                        switch($status)
2562
                        {
2563
                                case SASL_CONTINUE:
2564
                                        break;
2565
                                case SASL_NOMECH:
251 daniel-mar 2566
                                        return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".(strlen($authentication_mechanism) ? "authentication mechanism ".$authentication_mechanism." may not be used: " : "").$sasl->error, self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2567
                                default:
251 daniel-mar 2568
                                        return($this->SetError("Could not start the SASL ".($proxy ? "proxy " : "")."authentication client: ".$sasl->error, self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2569
                        }
2570
                        if($proxy >= 0)
2571
                        {
2572
                                for(;;)
2573
                                {
386 daniel-mar 2574
                                        $body = '';
171 daniel-mar 2575
                                        if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
2576
                                                return($error);
2577
                                        if(strlen($body)==0)
2578
                                                break;
2579
                                }
2580
                        }
2581
                        $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
2582
                        $request_arguments=$this->request_arguments;
2583
                        $arguments=$request_arguments;
2584
                        $arguments["Headers"][$authorization_header]=$authorization_value;
2585
                        if(!$proxy
2586
                        && strlen($proxy_authorization))
2587
                                $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
2588
                        if(strlen($error=$this->Close())
2589
                        || strlen($error=$this->Open($arguments)))
2590
                                return($this->SetError($error, $this->error_code));
2591
                        $authenticated=0;
2592
                        if(IsSet($message))
2593
                        {
2594
                                if($proxy < 0)
2595
                                {
2596
                                        if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
2597
                                                return($this->SetError($error, $this->error_code));
2598
                                }
2599
                                else
2600
                                {
2601
                                        if(strlen($error=$this->SendRequest($arguments))
2602
                                        || strlen($error=$this->ReadReplyHeadersResponse($headers)))
2603
                                                return($this->SetError($error, $this->error_code));
2604
                                }
2605
                                if(!IsSet($headers[$authenticate_header]))
2606
                                        $authenticate=array();
2607
                                elseif(GetType($headers[$authenticate_header])=="array")
2608
                                        $authenticate=$headers[$authenticate_header];
2609
                                else
2610
                                        $authenticate=array($headers[$authenticate_header]);
2611
                                for($mechanism=0;$mechanism<count($authenticate);$mechanism++)
2612
                                {
2613
                                        if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
2614
                                        {
2615
                                                $response=$this->Tokenize("");
2616
                                                break;
2617
                                        }
2618
                                }
2619
                                switch($this->response_status)
2620
                                {
2621
                                        case $authenticate_status:
2622
                                                break;
2623
                                        case "301":
2624
                                        case "302":
2625
                                        case "303":
2626
                                        case "307":
2627
                                                if($proxy >= 0)
2628
                                                        return($this->Redirect($headers));
2629
                                        default:
2630
                                                if(intval($this->response_status/100)==2)
2631
                                                {
2632
                                                        if($proxy)
2633
                                                                $proxy_authorization=$authorization_value;
2634
                                                        $authenticated=1;
2635
                                                        break;
2636
                                                }
2637
                                                if($proxy
2638
                                                && !strcmp($this->response_status,"401"))
2639
                                                {
2640
                                                        $proxy_authorization=$authorization_value;
2641
                                                        $authenticated=1;
2642
                                                        break;
2643
                                                }
251 daniel-mar 2644
                                                return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message, self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2645
                                }
2646
                        }
2647
                        for(;!$authenticated;)
2648
                        {
2649
                                do
2650
                                {
2651
                                        $status=$sasl->Step($response,$message,$interactions);
2652
                                }
2653
                                while($status==SASL_INTERACT);
2654
                                switch($status)
2655
                                {
2656
                                        case SASL_CONTINUE:
2657
                                                $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
2658
                                                $arguments=$request_arguments;
2659
                                                $arguments["Headers"][$authorization_header]=$authorization_value;
2660
                                                if(!$proxy
2661
                                                && strlen($proxy_authorization))
2662
                                                        $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
2663
                                                if($proxy < 0)
2664
                                                {
2665
                                                        if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
2666
                                                                return($this->SetError($error, $this->error_code));
2667
                                                }
2668
                                                else
2669
                                                {
2670
                                                        if(strlen($error=$this->SendRequest($arguments))
2671
                                                        || strlen($error=$this->ReadReplyHeadersResponse($headers)))
2672
                                                                return($this->SetError($error, $this->error_code));
2673
                                                }
2674
                                                switch($this->response_status)
2675
                                                {
2676
                                                        case $authenticate_status:
2677
                                                                if(GetType($headers[$authenticate_header])=="array")
2678
                                                                        $authenticate=$headers[$authenticate_header];
2679
                                                                else
2680
                                                                        $authenticate=array($headers[$authenticate_header]);
2681
                                                                for($response="",$mechanism=0;$mechanism<count($authenticate);$mechanism++)
2682
                                                                {
2683
                                                                        if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
2684
                                                                        {
2685
                                                                                $response=$this->Tokenize("");
2686
                                                                                break;
2687
                                                                        }
2688
                                                                }
2689
                                                                if($proxy >= 0)
2690
                                                                {
2691
                                                                        for(;;)
2692
                                                                        {
2693
                                                                                if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
2694
                                                                                        return($error);
2695
                                                                                if(strlen($body)==0)
2696
                                                                                        break;
2697
                                                                        }
2698
                                                                }
2699
                                                                $this->state="Connected";
2700
                                                                break;
2701
                                                        case "301":
2702
                                                        case "302":
2703
                                                        case "303":
2704
                                                        case "307":
2705
                                                                if($proxy >= 0)
2706
                                                                        return($this->Redirect($headers));
2707
                                                        default:
2708
                                                                if(intval($this->response_status/100)==2)
2709
                                                                {
2710
                                                                        if($proxy)
2711
                                                                                $proxy_authorization=$authorization_value;
2712
                                                                        $authenticated=1;
2713
                                                                        break;
2714
                                                                }
2715
                                                                if($proxy
2716
                                                                && !strcmp($this->response_status,"401"))
2717
                                                                {
2718
                                                                        $proxy_authorization=$authorization_value;
2719
                                                                        $authenticated=1;
2720
                                                                        break;
2721
                                                                }
2722
                                                                return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message));
2723
                                                }
2724
                                                break;
2725
                                        default:
251 daniel-mar 2726
                                                return($this->SetError("Could not process the SASL ".($proxy ? "proxy " : "")."authentication step: ".$sasl->error, self::HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
171 daniel-mar 2727
                                }
2728
                        }
2729
                }
2730
                return("");
2731
        }
386 daniel-mar 2732
 
171 daniel-mar 2733
        Function ReadReplyHeaders(&$headers)
2734
        {
2735
                if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
2736
                        return($error);
2737
                $proxy_authorization="";
2738
                while(!strcmp($this->response_status, "100"))
2739
                {
2740
                        $this->state="RequestSent";
2741
                        if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
2742
                                return($error);
2743
                }
2744
                switch($this->response_status)
2745
                {
2746
                        case "301":
2747
                        case "302":
2748
                        case "303":
2749
                        case "307":
2750
                                if(strlen($error=$this->Redirect($headers)))
2751
                                        return($error);
2752
                                break;
2753
                        case "407":
2754
                                if(strlen($error=$this->Authenticate($headers, 1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation)))
2755
                                        return($error);
2756
                                if(strcmp($this->response_status,"401"))
2757
                                        return("");
2758
                        case "401":
2759
                                return($this->Authenticate($headers, 0, $proxy_authorization, $this->request_user, $this->request_password, $this->request_realm, $this->request_workstation));
2760
                }
2761
                return("");
2762
        }
2763
 
2764
        Function ReadReplyBody(&$body,$length)
2765
        {
2766
                $body="";
2767
                if(strlen($this->error))
2768
                        return($this->error);
2769
                switch($this->state)
2770
                {
2771
                        case "Disconnected":
251 daniel-mar 2772
                                return($this->SetError("connection was not yet established", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2773
                        case "Connected":
2774
                        case "ConnectedToProxy":
251 daniel-mar 2775
                                return($this->SetError("request was not sent", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2776
                        case "RequestSent":
386 daniel-mar 2777
                                $headers = array();
171 daniel-mar 2778
                                if(($error=$this->ReadReplyHeaders($headers))!="")
2779
                                        return($error);
2780
                                break;
2781
                        case "GotReplyHeaders":
2782
                                break;
2783
                        case 'ResponseReceived':
2784
                                $body = '';
2785
                                return('');
2786
                        default:
251 daniel-mar 2787
                                return($this->SetError("can not get request headers in the current connection state", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2788
                }
2789
                if($this->content_length_set)
2790
                        $length=min($this->content_length-$this->read_length,$length);
2791
                $body = '';
2792
                if($length>0)
2793
                {
2794
                        if(!$this->EndOfInput()
2795
                        && ($body=$this->ReadBytes($length))=="")
2796
                        {
2797
                                if(strlen($this->error))
2798
                                        return($this->SetError("could not get the request reply body: ".$this->error, $this->error_code));
2799
                        }
2800
                        $this->read_length+=strlen($body);
2801
                        if($this->EndOfInput())
2802
                                $this->state = 'ResponseReceived';
2803
                }
2804
                return("");
2805
        }
2806
 
2807
        Function ReadWholeReplyBody(&$body)
2808
        {
2809
                $body = '';
2810
                for(;;)
2811
                {
386 daniel-mar 2812
                        $body = '';
2813
                        $block = '';
171 daniel-mar 2814
                        if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
2815
                                return($error);
2816
                        if(strlen($block) == 0)
2817
                                return('');
2818
                        $body .= $block;
2819
                }
2820
        }
2821
 
2822
        Function ReadWholeReplyIntoTemporaryFile(&$file)
2823
        {
386 daniel-mar 2824
                if(!($file = tmpfile())) {
2825
                        $php_errormsg = '';
251 daniel-mar 2826
                        return $this->SetPHPError('could not create the temporary file to save the response', $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
386 daniel-mar 2827
                }
171 daniel-mar 2828
                for(;;)
2829
                {
386 daniel-mar 2830
                        $block = '';
171 daniel-mar 2831
                        if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
2832
                        {
2833
                                fclose($file);
2834
                                return($error);
2835
                        }
2836
                        if(strlen($block) == 0)
2837
                        {
2838
                                if(@fseek($file, 0) != 0)
2839
                                {
251 daniel-mar 2840
                                        $error = $this->SetPHPError('could not seek to the beginning of temporary file with the response', $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2841
                                        fclose($file);
2842
                                        return $error;
2843
                                }
2844
                                return('');
2845
                        }
2846
                        if(!@fwrite($file, $block))
2847
                        {
386 daniel-mar 2848
                                $php_errormsg = '';
251 daniel-mar 2849
                                $error = $this->SetPHPError('could not write to the temporary file to save the response', $php_errormsg, self::HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
171 daniel-mar 2850
                                fclose($file);
2851
                                return $error;
2852
                        }
2853
                }
2854
        }
2855
 
2856
        Function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
2857
        {
2858
                $now=gmdate("Y-m-d H-i-s");
2859
                $cookies=array();
2860
                for($secure_cookies=0,Reset($this->cookies);$secure_cookies<count($this->cookies);Next($this->cookies),$secure_cookies++)
2861
                {
2862
                        $secure=Key($this->cookies);
2863
                        if(!$secure_only
2864
                        || $secure)
2865
                        {
2866
                                for($cookie_domain=0,Reset($this->cookies[$secure]);$cookie_domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$cookie_domain++)
2867
                                {
2868
                                        $domain_pattern=Key($this->cookies[$secure]);
2869
                                        $match=strlen($domain)-strlen($domain_pattern);
2870
                                        if(strlen($domain)==0
2871
                                        || ($match>=0
2872
                                        && !strcmp($domain_pattern,substr($domain,$match))
2873
                                        && ($match==0
2874
                                        || $domain_pattern[0]=="."
2875
                                        || $domain[$match-1]==".")))
2876
                                        {
2877
                                                for(Reset($this->cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($this->cookies[$secure][$domain_pattern]);Next($this->cookies[$secure][$domain_pattern]),$path_part++)
2878
                                                {
2879
                                                        $path=Key($this->cookies[$secure][$domain_pattern]);
2880
                                                        for(Reset($this->cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($this->cookies[$secure][$domain_pattern][$path]);Next($this->cookies[$secure][$domain_pattern][$path]),$cookie++)
2881
                                                        {
2882
                                                                $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
2883
                                                                $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
2884
                                                                if((!$persistent_only
2885
                                                                && strlen($expires)==0)
2886
                                                                || (strlen($expires)
2887
                                                                && strcmp($now,$expires)<0))
2888
                                                                        $cookies[$secure][$domain_pattern][$path][$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
2889
                                                        }
2890
                                                }
2891
                                        }
2892
                                }
2893
                        }
2894
                }
2895
        }
2896
 
2897
        Function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
2898
        {
2899
                $this->SaveCookies($cookies, $domain, $secure_only, 1);
2900
        }
2901
 
2902
        Function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
2903
        {
2904
                $this->SavePersistentCookies($cookies, $domain, $secure_only);
2905
        }
2906
 
2907
        Function RestoreCookies($cookies, $clear=1)
2908
        {
2909
                $new_cookies=($clear ? array() : $this->cookies);
2910
                for($secure_cookies=0, Reset($cookies); $secure_cookies<count($cookies); Next($cookies), $secure_cookies++)
2911
                {
2912
                        $secure=Key($cookies);
2913
                        if(GetType($secure)!="integer")
251 daniel-mar 2914
                                return($this->SetError("invalid cookie secure value type (".serialize($secure).")", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2915
                        for($cookie_domain=0,Reset($cookies[$secure]);$cookie_domain<count($cookies[$secure]);Next($cookies[$secure]),$cookie_domain++)
2916
                        {
2917
                                $domain_pattern=Key($cookies[$secure]);
2918
                                if(GetType($domain_pattern)!="string")
251 daniel-mar 2919
                                        return($this->SetError("invalid cookie domain value type (".serialize($domain_pattern).")", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2920
                                for(Reset($cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($cookies[$secure][$domain_pattern]);Next($cookies[$secure][$domain_pattern]),$path_part++)
2921
                                {
2922
                                        $path=Key($cookies[$secure][$domain_pattern]);
2923
                                        if(GetType($path)!="string"
2924
                                        || strcmp(substr($path, 0, 1), "/"))
251 daniel-mar 2925
                                                return($this->SetError("invalid cookie path value type (".serialize($path).")", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2926
                                        for(Reset($cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($cookies[$secure][$domain_pattern][$path]);Next($cookies[$secure][$domain_pattern][$path]),$cookie++)
2927
                                        {
2928
                                                $cookie_name=Key($cookies[$secure][$domain_pattern][$path]);
2929
                                                $expires=$cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
2930
                                                $value=$cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
2931
                                                if(GetType($expires)!="string"
2932
                                                || (strlen($expires)
2933
                                                && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires)))
251 daniel-mar 2934
                                                        return($this->SetError("invalid cookie expiry value type (".serialize($expires).")", self::HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
171 daniel-mar 2935
                                                $new_cookies[$secure][$domain_pattern][$path][$cookie_name]=array(
2936
                                                        "name"=>$cookie_name,
2937
                                                        "value"=>$value,
2938
                                                        "domain"=>$domain_pattern,
2939
                                                        "path"=>$path,
2940
                                                        "expires"=>$expires,
2941
                                                        "secure"=>$secure
2942
                                                );
2943
                                        }
2944
                                }
2945
                        }
2946
                }
2947
                $this->cookies=$new_cookies;
2948
                return("");
2949
        }
2950
};