MediaWiki  1.23.13
HttpFunctions.php
Go to the documentation of this file.
1 <?php
29 
34 class Http {
35  static public $httpEngine = false;
36 
62  public static function request( $method, $url, $options = array() ) {
63  wfDebug( "HTTP: $method: $url\n" );
64  wfProfileIn( __METHOD__ . "-$method" );
65 
66  $options['method'] = strtoupper( $method );
67 
68  if ( !isset( $options['timeout'] ) ) {
69  $options['timeout'] = 'default';
70  }
71  if ( !isset( $options['connectTimeout'] ) ) {
72  $options['connectTimeout'] = 'default';
73  }
74 
75  $req = MWHttpRequest::factory( $url, $options );
76  $status = $req->execute();
77 
78  $content = false;
79  if ( $status->isOK() ) {
80  $content = $req->getContent();
81  } else {
82  $errors = $status->getErrorsByType( 'error' );
83  $logger = LoggerFactory::getInstance( 'http' );
84  $logger->warning( $status->getWikiText(), array( 'caller' => $caller ) );
85  }
86  wfProfileOut( __METHOD__ . "-$method" );
87  return $content;
88  }
89 
99  public static function get( $url, $timeout = 'default', $options = array() ) {
100  $options['timeout'] = $timeout;
101  return Http::request( 'GET', $url, $options );
102  }
103 
112  public static function post( $url, $options = array() ) {
113  return Http::request( 'POST', $url, $options );
114  }
115 
122  public static function isLocalURL( $url ) {
123  global $wgCommandLineMode, $wgConf;
124 
125  if ( $wgCommandLineMode ) {
126  return false;
127  }
128 
129  // Extract host part
130  $matches = array();
131  if ( preg_match( '!^http://([\w.-]+)[/:].*$!', $url, $matches ) ) {
132  $host = $matches[1];
133  // Split up dotwise
134  $domainParts = explode( '.', $host );
135  // Check if this domain or any superdomain is listed in $wgConf as a local virtual host
136  $domainParts = array_reverse( $domainParts );
137 
138  $domain = '';
139  $countParts = count( $domainParts );
140  for ( $i = 0; $i < $countParts; $i++ ) {
141  $domainPart = $domainParts[$i];
142  if ( $i == 0 ) {
143  $domain = $domainPart;
144  } else {
145  $domain = $domainPart . '.' . $domain;
146  }
147 
148  if ( $wgConf->isLocalVHost( $domain ) ) {
149  return true;
150  }
151  }
152  }
153 
154  return false;
155  }
156 
161  public static function userAgent() {
162  global $wgVersion;
163  return "MediaWiki/$wgVersion";
164  }
165 
178  public static function isValidURI( $uri ) {
179  return preg_match(
180  '/^https?:\/\/[^\/\s]\S*$/D',
181  $uri
182  );
183  }
184 }
185 
194  const SUPPORTS_FILE_POSTS = false;
195 
196  protected $content;
197  protected $timeout = 'default';
198  protected $headersOnly = null;
199  protected $postData = null;
200  protected $proxy = null;
201  protected $noProxy = false;
202  protected $sslVerifyHost = true;
203  protected $sslVerifyCert = true;
204  protected $caInfo = null;
205  protected $method = "GET";
206  protected $reqHeaders = array();
207  protected $url;
208  protected $parsedUrl;
209  protected $callback;
210  protected $maxRedirects = 5;
211  protected $followRedirects = false;
212 
216  protected $cookieJar;
217 
218  protected $headerList = array();
219  protected $respVersion = "0.9";
220  protected $respStatus = "200 Ok";
221  protected $respHeaders = array();
222 
223  public $status;
224 
229  protected function __construct( $url, $options = array() ) {
230  global $wgHTTPTimeout, $wgHTTPConnectTimeout;
231 
232  $this->url = wfExpandUrl( $url, PROTO_HTTP );
233  $this->parsedUrl = wfParseUrl( $this->url );
234 
235  if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) {
236  $this->status = Status::newFatal( 'http-invalid-url' );
237  } else {
238  $this->status = Status::newGood( 100 ); // continue
239  }
240 
241  if ( isset( $options['timeout'] ) && $options['timeout'] != 'default' ) {
242  $this->timeout = $options['timeout'];
243  } else {
244  $this->timeout = $wgHTTPTimeout;
245  }
246  if ( isset( $options['connectTimeout'] ) && $options['connectTimeout'] != 'default' ) {
247  $this->connectTimeout = $options['connectTimeout'];
248  } else {
249  $this->connectTimeout = $wgHTTPConnectTimeout;
250  }
251  if ( isset( $options['userAgent'] ) ) {
252  $this->setUserAgent( $options['userAgent'] );
253  }
254 
255  $members = array( "postData", "proxy", "noProxy", "sslVerifyHost", "caInfo",
256  "method", "followRedirects", "maxRedirects", "sslVerifyCert", "callback" );
257 
258  foreach ( $members as $o ) {
259  if ( isset( $options[$o] ) ) {
260  // ensure that MWHttpRequest::method is always
261  // uppercased. Bug 36137
262  if ( $o == 'method' ) {
263  $options[$o] = strtoupper( $options[$o] );
264  }
265  $this->$o = $options[$o];
266  }
267  }
268 
269  if ( $this->noProxy ) {
270  $this->proxy = ''; // noProxy takes precedence
271  }
272  }
273 
279  public static function canMakeRequests() {
280  return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' );
281  }
282 
291  public static function factory( $url, $options = null ) {
292  if ( !Http::$httpEngine ) {
293  Http::$httpEngine = function_exists( 'curl_init' ) ? 'curl' : 'php';
294  } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) {
295  throw new MWException( __METHOD__ . ': curl (http://php.net/curl) is not installed, but' .
296  ' Http::$httpEngine is set to "curl"' );
297  }
298 
299  switch ( Http::$httpEngine ) {
300  case 'curl':
301  return new CurlHttpRequest( $url, $options );
302  case 'php':
303  if ( !wfIniGetBool( 'allow_url_fopen' ) ) {
304  throw new MWException( __METHOD__ . ': allow_url_fopen ' .
305  'needs to be enabled for pure PHP http requests to ' .
306  'work. If possible, curl should be used instead. See ' .
307  'http://php.net/curl.'
308  );
309  }
310  return new PhpHttpRequest( $url, $options );
311  default:
312  throw new MWException( __METHOD__ . ': The setting of Http::$httpEngine is not valid.' );
313  }
314  }
315 
321  public function getContent() {
322  return $this->content;
323  }
324 
331  public function setData( $args ) {
332  $this->postData = $args;
333  }
334 
340  public function proxySetup() {
341  global $wgHTTPProxy;
342 
343  // If there is an explicit proxy set and proxies are not disabled, then use it
344  if ( $this->proxy && !$this->noProxy ) {
345  return;
346  }
347 
348  // Otherwise, fallback to $wgHTTPProxy/http_proxy (when set) if this is not a machine
349  // local URL and proxies are not disabled
350  if ( Http::isLocalURL( $this->url ) || $this->noProxy ) {
351  $this->proxy = '';
352  } elseif ( $wgHTTPProxy ) {
353  $this->proxy = $wgHTTPProxy;
354  } elseif ( getenv( "http_proxy" ) ) {
355  $this->proxy = getenv( "http_proxy" );
356  }
357  }
358 
363  public function setUserAgent( $UA ) {
364  $this->setHeader( 'User-Agent', $UA );
365  }
366 
372  public function setHeader( $name, $value ) {
373  // I feel like I should normalize the case here...
374  $this->reqHeaders[$name] = $value;
375  }
376 
381  public function getHeaderList() {
382  $list = array();
383 
384  if ( $this->cookieJar ) {
385  $this->reqHeaders['Cookie'] =
386  $this->cookieJar->serializeToHttpRequest(
387  $this->parsedUrl['path'],
388  $this->parsedUrl['host']
389  );
390  }
391 
392  foreach ( $this->reqHeaders as $name => $value ) {
393  $list[] = "$name: $value";
394  }
395 
396  return $list;
397  }
398 
417  public function setCallback( $callback ) {
418  if ( !is_callable( $callback ) ) {
419  throw new MWException( 'Invalid MwHttpRequest callback' );
420  }
421  $this->callback = $callback;
422  }
423 
432  public function read( $fh, $content ) {
433  $this->content .= $content;
434  return strlen( $content );
435  }
436 
442  public function execute() {
443  wfProfileIn( __METHOD__ );
444 
445  $this->content = "";
446 
447  if ( strtoupper( $this->method ) == "HEAD" ) {
448  $this->headersOnly = true;
449  }
450 
451  $this->proxySetup(); // set up any proxy as needed
452 
453  if ( !$this->callback ) {
454  $this->setCallback( array( $this, 'read' ) );
455  }
456 
457  if ( !isset( $this->reqHeaders['User-Agent'] ) ) {
458  $this->setUserAgent( Http::userAgent() );
459  }
460 
461  wfProfileOut( __METHOD__ );
462  }
463 
469  protected function parseHeader() {
470  wfProfileIn( __METHOD__ );
471 
472  $lastname = "";
473 
474  foreach ( $this->headerList as $header ) {
475  if ( preg_match( "#^HTTP/([0-9.]+) (.*)#", $header, $match ) ) {
476  $this->respVersion = $match[1];
477  $this->respStatus = $match[2];
478  } elseif ( preg_match( "#^[ \t]#", $header ) ) {
479  $last = count( $this->respHeaders[$lastname] ) - 1;
480  $this->respHeaders[$lastname][$last] .= "\r\n$header";
481  } elseif ( preg_match( "#^([^:]*):[\t ]*(.*)#", $header, $match ) ) {
482  $this->respHeaders[strtolower( $match[1] )][] = $match[2];
483  $lastname = strtolower( $match[1] );
484  }
485  }
486 
487  $this->parseCookies();
488 
489  wfProfileOut( __METHOD__ );
490  }
491 
500  protected function setStatus() {
501  if ( !$this->respHeaders ) {
502  $this->parseHeader();
503  }
504 
505  if ( (int)$this->respStatus > 399 ) {
506  list( $code, $message ) = explode( " ", $this->respStatus, 2 );
507  $this->status->fatal( "http-bad-status", $code, $message );
508  }
509  }
510 
518  public function getStatus() {
519  if ( !$this->respHeaders ) {
520  $this->parseHeader();
521  }
522 
523  return (int)$this->respStatus;
524  }
525 
531  public function isRedirect() {
532  if ( !$this->respHeaders ) {
533  $this->parseHeader();
534  }
535 
536  $status = (int)$this->respStatus;
537 
538  if ( $status >= 300 && $status <= 303 ) {
539  return true;
540  }
541 
542  return false;
543  }
544 
553  public function getResponseHeaders() {
554  if ( !$this->respHeaders ) {
555  $this->parseHeader();
556  }
557 
558  return $this->respHeaders;
559  }
560 
567  public function getResponseHeader( $header ) {
568  if ( !$this->respHeaders ) {
569  $this->parseHeader();
570  }
571 
572  if ( isset( $this->respHeaders[strtolower( $header )] ) ) {
573  $v = $this->respHeaders[strtolower( $header )];
574  return $v[count( $v ) - 1];
575  }
576 
577  return null;
578  }
579 
585  public function setCookieJar( $jar ) {
586  $this->cookieJar = $jar;
587  }
588 
594  public function getCookieJar() {
595  if ( !$this->respHeaders ) {
596  $this->parseHeader();
597  }
598 
599  return $this->cookieJar;
600  }
601 
611  public function setCookie( $name, $value = null, $attr = null ) {
612  if ( !$this->cookieJar ) {
613  $this->cookieJar = new CookieJar;
614  }
615 
616  $this->cookieJar->setCookie( $name, $value, $attr );
617  }
618 
622  protected function parseCookies() {
623  wfProfileIn( __METHOD__ );
624 
625  if ( !$this->cookieJar ) {
626  $this->cookieJar = new CookieJar;
627  }
628 
629  if ( isset( $this->respHeaders['set-cookie'] ) ) {
630  $url = parse_url( $this->getFinalUrl() );
631  foreach ( $this->respHeaders['set-cookie'] as $cookie ) {
632  $this->cookieJar->parseCookieResponseHeader( $cookie, $url['host'] );
633  }
634  }
635 
636  wfProfileOut( __METHOD__ );
637  }
638 
655  public function getFinalUrl() {
656  $headers = $this->getResponseHeaders();
657 
658  //return full url (fix for incorrect but handled relative location)
659  if ( isset( $headers['location'] ) ) {
660  $locations = $headers['location'];
661  $domain = '';
662  $foundRelativeURI = false;
663  $countLocations = count( $locations );
664 
665  for ( $i = $countLocations - 1; $i >= 0; $i-- ) {
666  $url = parse_url( $locations[$i] );
667 
668  if ( isset( $url['host'] ) ) {
669  $domain = $url['scheme'] . '://' . $url['host'];
670  break; //found correct URI (with host)
671  } else {
672  $foundRelativeURI = true;
673  }
674  }
675 
676  if ( $foundRelativeURI ) {
677  if ( $domain ) {
678  return $domain . $locations[$countLocations - 1];
679  } else {
680  $url = parse_url( $this->url );
681  if ( isset( $url['host'] ) ) {
682  return $url['scheme'] . '://' . $url['host'] .
683  $locations[$countLocations - 1];
684  }
685  }
686  } else {
687  return $locations[$countLocations - 1];
688  }
689  }
690 
691  return $this->url;
692  }
693 
699  public function canFollowRedirects() {
700  return true;
701  }
702 }
703 
708  const SUPPORTS_FILE_POSTS = true;
709 
710  protected $curlOptions = array();
711  protected $headerText = "";
712 
718  protected function readHeader( $fh, $content ) {
719  $this->headerText .= $content;
720  return strlen( $content );
721  }
722 
723  public function execute() {
724  wfProfileIn( __METHOD__ );
725 
726  parent::execute();
727 
728  if ( !$this->status->isOK() ) {
729  wfProfileOut( __METHOD__ );
730  return $this->status;
731  }
732 
733  $this->curlOptions[CURLOPT_PROXY] = $this->proxy;
734  $this->curlOptions[CURLOPT_TIMEOUT] = $this->timeout;
735 
736  // Only supported in curl >= 7.16.2
737  if ( defined( 'CURLOPT_CONNECTTIMEOUT_MS' ) ) {
738  $this->curlOptions[CURLOPT_CONNECTTIMEOUT_MS] = $this->connectTimeout * 1000;
739  }
740 
741  $this->curlOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
742  $this->curlOptions[CURLOPT_WRITEFUNCTION] = $this->callback;
743  $this->curlOptions[CURLOPT_HEADERFUNCTION] = array( $this, "readHeader" );
744  $this->curlOptions[CURLOPT_MAXREDIRS] = $this->maxRedirects;
745  $this->curlOptions[CURLOPT_ENCODING] = ""; # Enable compression
746 
747  $this->curlOptions[CURLOPT_USERAGENT] = $this->reqHeaders['User-Agent'];
748 
749  $this->curlOptions[CURLOPT_SSL_VERIFYHOST] = $this->sslVerifyHost ? 2 : 0;
750  $this->curlOptions[CURLOPT_SSL_VERIFYPEER] = $this->sslVerifyCert;
751 
752  if ( $this->caInfo ) {
753  $this->curlOptions[CURLOPT_CAINFO] = $this->caInfo;
754  }
755 
756  if ( $this->headersOnly ) {
757  $this->curlOptions[CURLOPT_NOBODY] = true;
758  $this->curlOptions[CURLOPT_HEADER] = true;
759  } elseif ( $this->method == 'POST' ) {
760  $this->curlOptions[CURLOPT_POST] = true;
762  // Don't interpret POST parameters starting with '@' as file uploads, because this
763  // makes it impossible to POST plain values starting with '@' (and causes security
764  // issues potentially exposing the contents of local files).
765  // The PHP manual says this option was introduced in PHP 5.5 defaults to true in PHP 5.6,
766  // but we support lower versions, and the option doesn't exist in HHVM 5.6.99.
767  if ( defined( 'CURLOPT_SAFE_UPLOAD' ) ) {
768  $this->curlOptions[CURLOPT_SAFE_UPLOAD] = true;
769  } else if ( is_array( $postData ) ) {
770  // In PHP 5.2 and later, '@' is interpreted as a file upload if POSTFIELDS
771  // is an array, but not if it's a string. So convert $req['body'] to a string
772  // for safety.
774  }
775  $this->curlOptions[CURLOPT_POSTFIELDS] = $postData;
776 
777  // Suppress 'Expect: 100-continue' header, as some servers
778  // will reject it with a 417 and Curl won't auto retry
779  // with HTTP 1.0 fallback
780  $this->reqHeaders['Expect'] = '';
781  } else {
782  $this->curlOptions[CURLOPT_CUSTOMREQUEST] = $this->method;
783  }
784 
785  $this->curlOptions[CURLOPT_HTTPHEADER] = $this->getHeaderList();
786 
787  $curlHandle = curl_init( $this->url );
788 
789  if ( !curl_setopt_array( $curlHandle, $this->curlOptions ) ) {
790  wfProfileOut( __METHOD__ );
791  throw new MWException( "Error setting curl options." );
792  }
793 
794  if ( $this->followRedirects && $this->canFollowRedirects() ) {
796  if ( ! curl_setopt( $curlHandle, CURLOPT_FOLLOWLOCATION, true ) ) {
797  wfDebug( __METHOD__ . ": Couldn't set CURLOPT_FOLLOWLOCATION. " .
798  "Probably safe_mode or open_basedir is set.\n" );
799  // Continue the processing. If it were in curl_setopt_array,
800  // processing would have halted on its entry
801  }
803  }
804 
805  $curlRes = curl_exec( $curlHandle );
806  if ( curl_errno( $curlHandle ) == CURLE_OPERATION_TIMEOUTED ) {
807  $this->status->fatal( 'http-timed-out', $this->url );
808  } elseif ( $curlRes === false ) {
809  $this->status->fatal( 'http-curl-error', curl_error( $curlHandle ) );
810  } else {
811  $this->headerList = explode( "\r\n", $this->headerText );
812  }
813 
814  curl_close( $curlHandle );
815 
816  $this->parseHeader();
817  $this->setStatus();
818 
819  wfProfileOut( __METHOD__ );
820 
821  return $this->status;
822  }
823 
827  public function canFollowRedirects() {
828  if ( strval( ini_get( 'open_basedir' ) ) !== '' || wfIniGetBool( 'safe_mode' ) ) {
829  wfDebug( "Cannot follow redirects in safe mode\n" );
830  return false;
831  }
832 
833  if ( !defined( 'CURLOPT_REDIR_PROTOCOLS' ) ) {
834  wfDebug( "Cannot follow redirects with libcurl < 7.19.4 due to CVE-2009-0037\n" );
835  return false;
836  }
837 
838  return true;
839  }
840 }
841 
842 class PhpHttpRequest extends MWHttpRequest {
843 
844  private $fopenErrors = array();
845 
850  protected function urlToTcp( $url ) {
851  $parsedUrl = parse_url( $url );
852 
853  return 'tcp://' . $parsedUrl['host'] . ':' . $parsedUrl['port'];
854  }
855 
863  protected function getCertOptions() {
864  $certOptions = array();
865  $certLocations = array();
866  if ( $this->caInfo ) {
867  $certLocations = array( 'manual' => $this->caInfo );
868  } elseif ( version_compare( PHP_VERSION, '5.6.0', '<' ) ) {
869  // Default locations, based on
870  // https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/
871  // PHP 5.5 and older doesn't have any defaults, so we try to guess ourselves. PHP 5.6+ gets the CA location
872  // from OpenSSL as long as it is not set manually, so we should leave capath/cafile empty there.
873  $certLocations = array_filter( array(
874  getenv( 'SSL_CERT_DIR' ),
875  getenv( 'SSL_CERT_PATH' ),
876  '/etc/pki/tls/certs/ca-bundle.crt', # Fedora et al
877  '/etc/ssl/certs', # Debian et al
878  '/etc/pki/tls/certs/ca-bundle.trust.crt',
879  '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem',
880  '/System/Library/OpenSSL', # OSX
881  ) );
882  }
883 
884  foreach( $certLocations as $key => $cert ) {
885  if ( is_dir( $cert ) ) {
886  $certOptions['capath'] = $cert;
887  break;
888  } elseif ( is_file( $cert ) ) {
889  $certOptions['cafile'] = $cert;
890  break;
891  } elseif ( $key === 'manual' ) {
892  // fail more loudly if a cert path was manually configured and it is not valid
893  throw new DomainException( "Invalid CA info passed: $cert" );
894  }
895  }
896 
897  return $certOptions;
898  }
899 
905  public function errorHandler( $errno, $errstr ) {
906  $n = count( $this->fopenErrors ) + 1;
907  $this->fopenErrors += array( "errno$n" => $errno, "errstr$n" => $errstr );
908  }
909 
910  public function execute() {
911  wfProfileIn( __METHOD__ );
912 
913  parent::execute();
914 
915  if ( is_array( $this->postData ) ) {
916  $this->postData = wfArrayToCgi( $this->postData );
917  }
918 
919  if ( $this->parsedUrl['scheme'] != 'http'
920  && $this->parsedUrl['scheme'] != 'https' ) {
921  $this->status->fatal( 'http-invalid-scheme', $this->parsedUrl['scheme'] );
922  }
923 
924  $this->reqHeaders['Accept'] = "*/*";
925  $this->reqHeaders['Connection'] = 'Close';
926  if ( $this->method == 'POST' ) {
927  // Required for HTTP 1.0 POSTs
928  $this->reqHeaders['Content-Length'] = strlen( $this->postData );
929  if ( !isset( $this->reqHeaders['Content-Type'] ) ) {
930  $this->reqHeaders['Content-Type'] = "application/x-www-form-urlencoded";
931  }
932  }
933 
934  // Set up PHP stream context
935  $options = array(
936  'http' => array(
937  'method' => $this->method,
938  'header' => implode( "\r\n", $this->getHeaderList() ),
939  'protocol_version' => '1.1',
940  'max_redirects' => $this->followRedirects ? $this->maxRedirects : 0,
941  'ignore_errors' => true,
942  'timeout' => $this->timeout,
943  // Curl options in case curlwrappers are installed
944  'curl_verify_ssl_host' => $this->sslVerifyHost ? 2 : 0,
945  'curl_verify_ssl_peer' => $this->sslVerifyCert,
946  ),
947  'ssl' => array(
948  'verify_peer' => $this->sslVerifyCert,
949  'SNI_enabled' => true,
950  ),
951  );
952 
953  if ( $this->proxy ) {
954  $options['http']['proxy'] = $this->urlToTCP( $this->proxy );
955  $options['http']['request_fulluri'] = true;
956  }
957 
958  if ( $this->postData ) {
959  $options['http']['content'] = $this->postData;
960  }
961 
962  if ( $this->sslVerifyHost ) {
963  // PHP 5.6.0 deprecates CN_match, in favour of peer_name which
964  // actually checks SubjectAltName properly.
965  if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
966  $options['ssl']['peer_name'] = $this->parsedUrl['host'];
967  } else {
968  $options['ssl']['CN_match'] = $this->parsedUrl['host'];
969  }
970  }
971 
972  $options['ssl'] += $this->getCertOptions();
973 
974  $context = stream_context_create( $options );
975 
976  $this->headerList = array();
977  $reqCount = 0;
978  $url = $this->url;
979 
980  $result = array();
981 
982  do {
983  $reqCount++;
984  $this->fopenErrors = array();
985  set_error_handler( array( $this, 'errorHandler' ) );
986  $fh = fopen( $url, "r", false, $context );
987  restore_error_handler();
988 
989  if ( !$fh ) {
990  // HACK for instant commons.
991  // If we are contacting (commons|upload).wikimedia.org
992  // try again with CN_match for en.wikipedia.org
993  // as php does not handle SubjectAltName properly
994  // prior to "peer_name" option in php 5.6
995  if ( isset( $options['ssl']['CN_match'] )
996  && ( $options['ssl']['CN_match'] === 'commons.wikimedia.org'
997  || $options['ssl']['CN_match'] === 'upload.wikimedia.org' )
998  ) {
999  $options['ssl']['CN_match'] = 'en.wikipedia.org';
1000  $context = stream_context_create( $options );
1001  continue;
1002  }
1003  break;
1004  }
1005 
1006  $result = stream_get_meta_data( $fh );
1007  $this->headerList = $result['wrapper_data'];
1008  $this->parseHeader();
1009 
1010  if ( !$this->followRedirects ) {
1011  break;
1012  }
1013 
1014  # Handle manual redirection
1015  if ( !$this->isRedirect() || $reqCount > $this->maxRedirects ) {
1016  break;
1017  }
1018  # Check security of URL
1019  $url = $this->getResponseHeader( "Location" );
1020 
1021  if ( !Http::isValidURI( $url ) ) {
1022  wfDebug( __METHOD__ . ": insecure redirection\n" );
1023  break;
1024  }
1025  } while ( true );
1026 
1027  $this->setStatus();
1028 
1029  if ( $fh === false ) {
1030  if ( $this->fopenErrors ) {
1031  LoggerFactory::getInstance( 'http' )->warning( __CLASS__
1032  . ': error opening connection: {errstr1}', $this->fopenErrors );
1033  }
1034  $this->status->fatal( 'http-request-error' );
1035  wfProfileOut( __METHOD__ );
1036  return $this->status;
1037  }
1038 
1039  if ( $result['timed_out'] ) {
1040  $this->status->fatal( 'http-timed-out', $this->url );
1041  wfProfileOut( __METHOD__ );
1042  return $this->status;
1043  }
1044 
1045  // If everything went OK, or we received some error code
1046  // get the response body content.
1047  if ( $this->status->isOK() || (int)$this->respStatus >= 300 ) {
1048  while ( !feof( $fh ) ) {
1049  $buf = fread( $fh, 8192 );
1050 
1051  if ( $buf === false ) {
1052  $this->status->fatal( 'http-read-error' );
1053  break;
1054  }
1055 
1056  if ( strlen( $buf ) ) {
1057  call_user_func( $this->callback, $fh, $buf );
1058  }
1059  }
1060  }
1061  fclose( $fh );
1062 
1063  wfProfileOut( __METHOD__ );
1064 
1065  return $this->status;
1066  }
1067 }
MWHttpRequest\$headerList
$headerList
Definition: HttpFunctions.php:217
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
MWHttpRequest\$headersOnly
$headersOnly
Definition: HttpFunctions.php:198
PhpHttpRequest\$fopenErrors
$fopenErrors
Definition: HttpFunctions.php:843
Http\$httpEngine
static $httpEngine
Definition: HttpFunctions.php:35
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
content
per default it will return the text for text based content
Definition: contenthandler.txt:107
MWHttpRequest\setStatus
setStatus()
Sets HTTPRequest status member to a fatal value with the error message if the returned integer value ...
Definition: HttpFunctions.php:499
MWHttpRequest\$respVersion
$respVersion
Definition: HttpFunctions.php:218
MWHttpRequest\proxySetup
proxySetup()
Take care of setting up the proxy (do nothing if "noProxy" is set)
Definition: HttpFunctions.php:339
$last
$last
Definition: profileinfo.php:365
MWHttpRequest\$maxRedirects
$maxRedirects
Definition: HttpFunctions.php:210
MWHttpRequest\$sslVerifyCert
$sslVerifyCert
Definition: HttpFunctions.php:203
Http\userAgent
static userAgent()
A standard user-agent we can use for external requests.
Definition: HttpFunctions.php:161
MWHttpRequest\$followRedirects
$followRedirects
Definition: HttpFunctions.php:211
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$n
$n
Definition: RandomTest.php:76
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2434
Debian
MediaWiki has optional support for a high distributed memory object caching system For general information on but for a larger site with heavy like it should help lighten the load on the database servers by caching data and objects in Debian
Definition: memcached.txt:10
Status\newGood
static newGood( $value=null)
Factory function for good results.
Definition: Status.php:77
Http\isLocalURL
static isLocalURL( $url)
Check if the URL can be served by localhost.
Definition: HttpFunctions.php:122
MWHttpRequest\setData
setData( $args)
Set the parameters of the request.
Definition: HttpFunctions.php:330
MWHttpRequest\$content
$content
Definition: HttpFunctions.php:196
CurlHttpRequest\$headerText
$headerText
Definition: HttpFunctions.php:710
CurlHttpRequest
MWHttpRequest implemented using internal curl compiled into PHP.
Definition: HttpFunctions.php:706
MWHttpRequest\$timeout
$timeout
Definition: HttpFunctions.php:197
PhpHttpRequest\errorHandler
errorHandler( $errno, $errstr)
Custom error handler for dealing with fopen() errors.
Definition: HttpFunctions.php:904
MWHttpRequest\$status
$status
Definition: HttpFunctions.php:222
PhpHttpRequest\urlToTcp
urlToTcp( $url)
Definition: HttpFunctions.php:849
MWHttpRequest\getStatus
getStatus()
Get the integer value of the HTTP status code (e.g.
Definition: HttpFunctions.php:517
MWHttpRequest\$noProxy
$noProxy
Definition: HttpFunctions.php:201
MWHttpRequest\__construct
__construct( $url, $options=array())
Definition: HttpFunctions.php:228
MWHttpRequest\parseHeader
parseHeader()
Parses the headers, including the HTTP status code and any Set-Cookie headers.
Definition: HttpFunctions.php:468
wfParseUrl
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Definition: GlobalFunctions.php:802
MWHttpRequest\$postData
$postData
Definition: HttpFunctions.php:199
Http\request
static request( $method, $url, $options=array())
Perform an HTTP request.
Definition: HttpFunctions.php:62
MWHttpRequest\getContent
getContent()
Get the body, or content, of the response to the request.
Definition: HttpFunctions.php:320
MWException
MediaWiki exception.
Definition: MWException.php:26
MWHttpRequest\SUPPORTS_FILE_POSTS
const SUPPORTS_FILE_POSTS
Definition: HttpFunctions.php:194
MediaWiki\Logger\LoggerFactory
Backwards compatible PSR-3 logger instance factory.
Definition: LoggerFactory.php:36
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2464
MWHttpRequest\parseCookies
parseCookies()
Parse the cookies in the response headers and store them in the cookie jar.
Definition: HttpFunctions.php:621
MWHttpRequest\$respStatus
$respStatus
Definition: HttpFunctions.php:219
CookieJar\setCookie
setCookie( $name, $value, $attr)
Set a cookie in the cookie jar.
Definition: Cookie.php:214
$wgCommandLineMode
global $wgCommandLineMode
Definition: Setup.php:408
MWHttpRequest\isRedirect
isRedirect()
Returns true if the last status code was a redirect.
Definition: HttpFunctions.php:530
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
MWHttpRequest\getCookieJar
getCookieJar()
Returns the cookie jar in use.
Definition: HttpFunctions.php:593
MWHttpRequest\$reqHeaders
$reqHeaders
Definition: HttpFunctions.php:206
MWHttpRequest\setCookieJar
setCookieJar( $jar)
Tells the MWHttpRequest object to use this pre-loaded CookieJar.
Definition: HttpFunctions.php:584
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
MWHttpRequest\$respHeaders
$respHeaders
Definition: HttpFunctions.php:220
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
MWHttpRequest\$cookieJar
CookieJar $cookieJar
Definition: HttpFunctions.php:215
PhpHttpRequest\execute
execute()
Take care of whatever is necessary to perform the URI request.
Definition: HttpFunctions.php:909
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1530
MWHttpRequest\read
read( $fh, $content)
A generic callback to read the body of the response from a remote server.
Definition: HttpFunctions.php:431
execute
$batch execute()
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
CurlHttpRequest\execute
execute()
Take care of whatever is necessary to perform the URI request.
Definition: HttpFunctions.php:722
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
$value
$value
Definition: styleTest.css.php:45
MWHttpRequest\$method
$method
Definition: HttpFunctions.php:205
MWHttpRequest
This wrapper class will call out to curl (if available) or fallback to regular PHP if necessary for h...
Definition: HttpFunctions.php:193
MWHttpRequest\setCallback
setCallback( $callback)
Set a read callback to accept data read from the HTTP request.
Definition: HttpFunctions.php:416
MWHttpRequest\setHeader
setHeader( $name, $value)
Set an arbitrary header.
Definition: HttpFunctions.php:371
PROTO_HTTP
const PROTO_HTTP
Definition: Defines.php:267
MWHttpRequest\getHeaderList
getHeaderList()
Get an array of the headers.
Definition: HttpFunctions.php:380
MWHttpRequest\$parsedUrl
$parsedUrl
Definition: HttpFunctions.php:208
MWHttpRequest\setCookie
setCookie( $name, $value=null, $attr=null)
Sets a cookie.
Definition: HttpFunctions.php:610
MWHttpRequest\getResponseHeaders
getResponseHeaders()
Returns an associative array of response headers after the request has been executed.
Definition: HttpFunctions.php:552
wfIniGetBool
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
Definition: GlobalFunctions.php:2732
MWHttpRequest\$sslVerifyHost
$sslVerifyHost
Definition: HttpFunctions.php:202
$args
if( $line===false) $args
Definition: cdb.php:62
CurlHttpRequest\$curlOptions
$curlOptions
Definition: HttpFunctions.php:709
PhpHttpRequest\getCertOptions
getCertOptions()
Returns an array with a 'capath' or 'cafile' key that is suitable to be merged into the 'ssl' sub-arr...
Definition: HttpFunctions.php:862
CookieJar
Definition: Cookie.php:207
MWHttpRequest\$caInfo
$caInfo
Definition: HttpFunctions.php:204
MWHttpRequest\canMakeRequests
static canMakeRequests()
Simple function to test if we can make any sort of requests at all, using cURL or fopen()
Definition: HttpFunctions.php:278
CurlHttpRequest\canFollowRedirects
canFollowRedirects()
Definition: HttpFunctions.php:826
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
CurlHttpRequest\SUPPORTS_FILE_POSTS
const SUPPORTS_FILE_POSTS
Definition: HttpFunctions.php:707
MWHttpRequest\getResponseHeader
getResponseHeader( $header)
Returns the value of the given response header.
Definition: HttpFunctions.php:566
MWHttpRequest\setUserAgent
setUserAgent( $UA)
Set the user agent.
Definition: HttpFunctions.php:362
MWHttpRequest\execute
execute()
Take care of whatever is necessary to perform the URI request.
Definition: HttpFunctions.php:441
Http\isValidURI
static isValidURI( $uri)
Checks that the given URI is a valid one.
Definition: HttpFunctions.php:178
CurlHttpRequest\readHeader
readHeader( $fh, $content)
Definition: HttpFunctions.php:717
MWHttpRequest\canFollowRedirects
canFollowRedirects()
Returns true if the backend can follow redirects.
Definition: HttpFunctions.php:698
PhpHttpRequest
Definition: HttpFunctions.php:841
MWHttpRequest\$callback
$callback
Definition: HttpFunctions.php:209
MWHttpRequest\$proxy
$proxy
Definition: HttpFunctions.php:200
MWHttpRequest\factory
static factory( $url, $options=null)
Generate a new request object.
Definition: HttpFunctions.php:290
MWHttpRequest\getFinalUrl
getFinalUrl()
Returns the final URL after all redirections.
Definition: HttpFunctions.php:654
Http
Various HTTP related functions.
Definition: HttpFunctions.php:34
MWHttpRequest\$url
$url
Definition: HttpFunctions.php:207
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:544
Http\post
static post( $url, $options=array())
Simple wrapper for Http::request( 'POST' )
Definition: HttpFunctions.php:112
Status\newFatal
static newFatal( $message)
Factory function for fatal errors.
Definition: Status.php:63
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes two arrays as input, and returns a CGI-style string, e.g.
Definition: GlobalFunctions.php:414