/** * Downloads a package archive from an http URL. * * @param string $httpUrl * @param string $prefix * @return string path to the dowloaded file */ public static function downloadFileFromHttp($httpUrl, $prefix = 'package') { $extension = strrchr($httpUrl, '.'); //$newFileName = self::getTemporaryFilename($prefix.'_', $extension); $newFileName = self::getTemporaryFilename($prefix . '_'); $localFile = new File($newFileName); // the file to write. // get proxy $options = array(); if (PROXY_SERVER_HTTP) { $options['http']['proxy'] = PROXY_SERVER_HTTP; } // first look if php's built-in fopen() is available, and if so, use it. if (function_exists('fopen') && ini_get('allow_url_fopen')) { $remoteFile = new File($httpUrl, 'rb', $options); // the file to read. // get the content of the remote file and write it to a local file. while (!$remoteFile->eof()) { $buffer = $remoteFile->gets(4096); $localFile->write($buffer); } } else { $port = 80; $parsedUrl = parse_url($httpUrl); $host = $parsedUrl['host']; $path = $parsedUrl['path']; require_once WCF_DIR . 'lib/system/io/RemoteFile.class.php'; $remoteFile = new RemoteFile($host, $port, 30, $options); // the file to read. if (!isset($remoteFile)) { $localFile->close(); unlink($newFileName); throw new SystemException("cannot connect to http host '" . $host . "'", 14000); } // build and send the http request. $request = "GET " . $path . (!empty($parsedUrl['query']) ? '?' . $parsedUrl['query'] : '') . " HTTP/1.0\r\n"; $request .= "User-Agent: HTTP.PHP (FileUtil.class.php; WoltLab Community Framework/" . WCF_VERSION . "; " . WCF::getLanguage()->getLanguageCode() . ")\r\n"; $request .= "Accept: */*\r\n"; $request .= "Accept-Language: " . WCF::getLanguage()->getLanguageCode() . "\r\n"; $request .= "Host: " . $host . "\r\n"; $request .= "Connection: Close\r\n\r\n"; $remoteFile->puts($request); $waiting = true; $readResponse = array(); // read http response. while (!$remoteFile->eof()) { $readResponse[] = $remoteFile->gets(); // look if we are done with transferring the requested file. if ($waiting) { if (rtrim($readResponse[count($readResponse) - 1]) == '') { $waiting = false; } } else { // look if the webserver sent an error http statuscode // This has still to be checked if really sufficient! $arrayHeader = array('201', '301', '302', '303', '307', '404'); foreach ($arrayHeader as $code) { $error = strpos($readResponse[0], $code); } if ($error !== false) { $localFile->close(); unlink($newFileName); throw new SystemException("file " . $path . " not found at host '" . $host . "'", 14001); } // write to the target system. $localFile->write($readResponse[count($readResponse) - 1]); } } } $remoteFile->close(); $localFile->close(); return $newFileName; }
/** * Sends a request to a remote (update) server. * * @param string $url * @param array $values * @param array $authData * @return array $response */ protected static function sendRequest($url, $values = array(), $authData = array()) { // default values $host = ''; $path = '/'; $port = 80; $postString = ''; // parse url $parsedURL = parse_url($url); if (!empty($parsedURL['host'])) { $host = $parsedURL['host']; } if (!empty($parsedURL['path'])) { $path = $parsedURL['path']; } if (!empty($parsedURL['query'])) { $postString = $parsedURL['query']; } if (!empty($parsedURL['port'])) { $port = $parsedURL['port']; } // connect to server $options = array(); if (PROXY_SERVER_HTTP) { $options['http']['proxy'] = PROXY_SERVER_HTTP; } require_once WCF_DIR . 'lib/system/io/RemoteFile.class.php'; $remoteFile = new RemoteFile($host, $port, 30, $options); // Build and send the http request $request = "POST " . $path . " HTTP/1.0\r\n"; if (isset($authData['authType'])) { $request .= "Authorization: Basic " . base64_encode($authData['htUsername'] . ":" . $authData['htPassword']) . "\r\n"; } $request .= "User-Agent: HTTP.PHP (PackageUpdate.class.php; WoltLab Community Framework/" . WCF_VERSION . "; " . WCF::getLanguage()->getLanguageCode() . ")\r\n"; $request .= "Accept: */*\r\n"; $request .= "Accept-Language: " . WCF::getLanguage()->getLanguageCode() . "\r\n"; $request .= "Host: " . $host . "\r\n"; // build post string foreach ($values as $name => $value) { if (!empty($postString)) { $postString .= '&'; } $postString .= $name . '=' . $value; } // send content type and length $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; $request .= "Content-Length: " . strlen($postString) . "\r\n"; // if it is a POST request, there MUST be a blank line before the POST data, but there MUST NOT be // another blank line before, and of course there must be another blank line at the end of the request! $request .= "\r\n"; if (!empty($postString)) { $request .= $postString . "\r\n"; } // send close $request .= "Connection: Close\r\n\r\n"; // send request $remoteFile->puts($request); unset($request, $postString); // define response vars $header = $content = ''; // fetch the response. while (!$remoteFile->eof()) { $line = $remoteFile->gets(); if (rtrim($line) != '') { $header .= $line; } else { break; } } while (!$remoteFile->eof()) { $content .= $remoteFile->gets(); } // clean up and return the server's response. $remoteFile->close(); // get http status code / line $httpStatusCode = 0; $httpStatusLine = ''; if (preg_match('%http/\\d\\.\\d (\\d{3})[^\\n]*%i', $header, $match)) { $httpStatusLine = trim($match[0]); $httpStatusCode = $match[1]; } // catch http 301 Moved Permanently // catch http 302 Found // catch http 303 See Other if ($httpStatusCode == 301 || $httpStatusCode == 302 || $httpStatusCode == 303) { // find location if (preg_match('/location:([^\\n]*)/i', $header, $match)) { $location = trim($match[1]); if ($location != $url) { return self::sendRequest($location, $values, $authData); } } } // catch other http codes here return array('httpStatusLine' => $httpStatusLine, 'httpStatusCode' => $httpStatusCode, 'header' => $header, 'content' => $content); }