コード例 #1
0
 /**
  * Internal function to mask portions of the visitor IP address
  *
  * @param string $ip IP address in network address format
  * @param int $maskLength Number of octets to reset
  */
 public static function applyIPMask($ip, $maskLength)
 {
     $i = Piwik_Common::strlen($ip);
     if ($maskLength > $i) {
         $maskLength = $i;
     }
     while ($maskLength-- > 0) {
         $ip[--$i] = chr(0);
     }
     return $ip;
 }
コード例 #2
0
ファイル: Http.php プロジェクト: nomoto-ubicast/piwik
 /**
  * Sends http request using the specified transport method
  *
  * @param string       $method
  * @param string       $aUrl
  * @param int          $timeout
  * @param string       $userAgent
  * @param string       $destinationPath
  * @param resource     $file
  * @param int          $followDepth
  * @param bool|string  $acceptLanguage               Accept-language header
  * @param bool         $acceptInvalidSslCertificate  Only used with $method == 'curl'. If set to true (NOT recommended!) the SSL certificate will not be checked
  * @throws Exception
  * @return bool  true (or string) on success; false on HTTP response error code (1xx or 4xx)
  */
 public static function sendHttpRequestBy($method = 'socket', $aUrl, $timeout, $userAgent = null, $destinationPath = null, $file = null, $followDepth = 0, $acceptLanguage = false, $acceptInvalidSslCertificate = false)
 {
     if ($followDepth > 5) {
         throw new Exception('Too many redirects (' . $followDepth . ')');
     }
     $contentLength = 0;
     $fileLength = 0;
     // Piwik services behave like a proxy, so we should act like one.
     $xff = 'X-Forwarded-For: ' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] . ',' : '') . Piwik_IP::getIpFromHeader();
     if (empty($userAgent)) {
         $userAgent = self::getUserAgent();
     }
     $via = 'Via: ' . (isset($_SERVER['HTTP_VIA']) && !empty($_SERVER['HTTP_VIA']) ? $_SERVER['HTTP_VIA'] . ', ' : '') . Piwik_Version::VERSION . ' ' . ($userAgent ? " ({$userAgent})" : '');
     // proxy configuration
     $proxyHost = Piwik_Config::getInstance()->proxy['host'];
     $proxyPort = Piwik_Config::getInstance()->proxy['port'];
     $proxyUser = Piwik_Config::getInstance()->proxy['username'];
     $proxyPassword = Piwik_Config::getInstance()->proxy['password'];
     if ($method == 'socket') {
         // initialization
         $url = @parse_url($aUrl);
         if ($url === false || !isset($url['scheme'])) {
             throw new Exception('Malformed URL: ' . $aUrl);
         }
         if ($url['scheme'] != 'http') {
             throw new Exception('Invalid protocol/scheme: ' . $url['scheme']);
         }
         $host = $url['host'];
         $port = isset($url['port)']) ? $url['port'] : 80;
         $path = isset($url['path']) ? $url['path'] : '/';
         if (isset($url['query'])) {
             $path .= '?' . $url['query'];
         }
         $errno = null;
         $errstr = null;
         $proxyAuth = null;
         if (!empty($proxyHost) && !empty($proxyPort)) {
             $connectHost = $proxyHost;
             $connectPort = $proxyPort;
             if (!empty($proxyUser) && !empty($proxyPassword)) {
                 $proxyAuth = 'Proxy-Authorization: Basic ' . base64_encode("{$proxyUser}:{$proxyPassword}") . "\r\n";
             }
             $requestHeader = "GET {$aUrl} HTTP/1.1\r\n";
         } else {
             $connectHost = $host;
             $connectPort = $port;
             $requestHeader = "GET {$path} HTTP/1.0\r\n";
         }
         // connection attempt
         if (($fsock = @fsockopen($connectHost, $connectPort, $errno, $errstr, $timeout)) === false || !is_resource($fsock)) {
             if (is_resource($file)) {
                 @fclose($file);
             }
             throw new Exception("Error while connecting to: {$host}. Please try again later. {$errstr}");
         }
         // send HTTP request header
         $requestHeader .= "Host: {$host}" . ($port != 80 ? ':' . $port : '') . "\r\n" . ($proxyAuth ? $proxyAuth : '') . 'User-Agent: ' . $userAgent . "\r\n" . ($acceptLanguage ? $acceptLanguage . "\r\n" : '') . $xff . "\r\n" . $via . "\r\n" . "Connection: close\r\n" . "\r\n";
         fwrite($fsock, $requestHeader);
         $streamMetaData = array('timed_out' => false);
         @stream_set_blocking($fsock, true);
         if (function_exists('stream_set_timeout')) {
             @stream_set_timeout($fsock, $timeout);
         } elseif (function_exists('socket_set_timeout')) {
             @socket_set_timeout($fsock, $timeout);
         }
         // process header
         $status = null;
         $expectRedirect = false;
         while (!feof($fsock)) {
             $line = fgets($fsock, 4096);
             $streamMetaData = @stream_get_meta_data($fsock);
             if ($streamMetaData['timed_out']) {
                 if (is_resource($file)) {
                     @fclose($file);
                 }
                 @fclose($fsock);
                 throw new Exception('Timed out waiting for server response');
             }
             // a blank line marks the end of the server response header
             if (rtrim($line, "\r\n") == '') {
                 break;
             }
             // parse first line of server response header
             if (!$status) {
                 // expect first line to be HTTP response status line, e.g., HTTP/1.1 200 OK
                 if (!preg_match('~^HTTP/(\\d\\.\\d)\\s+(\\d+)(\\s*.*)?~', $line, $m)) {
                     if (is_resource($file)) {
                         @fclose($file);
                     }
                     @fclose($fsock);
                     throw new Exception('Expected server response code.  Got ' . rtrim($line, "\r\n"));
                 }
                 $status = (int) $m[2];
                 // Informational 1xx or Client Error 4xx
                 if ($status < 200 || $status >= 400) {
                     if (is_resource($file)) {
                         @fclose($file);
                     }
                     @fclose($fsock);
                     return false;
                 }
                 continue;
             }
             // handle redirect
             if (preg_match('/^Location:\\s*(.+)/', rtrim($line, "\r\n"), $m)) {
                 if (is_resource($file)) {
                     @fclose($file);
                 }
                 @fclose($fsock);
                 // Successful 2xx vs Redirect 3xx
                 if ($status < 300) {
                     throw new Exception('Unexpected redirect to Location: ' . rtrim($line) . ' for status code ' . $status);
                 }
                 return self::sendHttpRequestBy($method, trim($m[1]), $timeout, $userAgent, $destinationPath, $file, $followDepth + 1, $acceptLanguage);
             }
             // save expected content length for later verification
             if (preg_match('/^Content-Length:\\s*(\\d+)/', $line, $m)) {
                 $contentLength = (int) $m[1];
             }
         }
         if (feof($fsock)) {
             throw new Exception('Unexpected end of transmission');
         }
         // process content/body
         $response = '';
         while (!feof($fsock)) {
             $line = fread($fsock, 8192);
             $streamMetaData = @stream_get_meta_data($fsock);
             if ($streamMetaData['timed_out']) {
                 if (is_resource($file)) {
                     @fclose($file);
                 }
                 @fclose($fsock);
                 throw new Exception('Timed out waiting for server response');
             }
             $fileLength += Piwik_Common::strlen($line);
             if (is_resource($file)) {
                 // save to file
                 fwrite($file, $line);
             } else {
                 // concatenate to response string
                 $response .= $line;
             }
         }
         // determine success or failure
         @fclose(@$fsock);
     } else {
         if ($method == 'fopen') {
             $response = false;
             // we make sure the request takes less than a few seconds to fail
             // we create a stream_context (works in php >= 5.2.1)
             // we also set the socket_timeout (for php < 5.2.1)
             $default_socket_timeout = @ini_get('default_socket_timeout');
             @ini_set('default_socket_timeout', $timeout);
             $ctx = null;
             if (function_exists('stream_context_create')) {
                 $stream_options = array('http' => array('header' => 'User-Agent: ' . $userAgent . "\r\n" . ($acceptLanguage ? $acceptLanguage . "\r\n" : '') . $xff . "\r\n" . $via . "\r\n", 'max_redirects' => 5, 'timeout' => $timeout));
                 if (!empty($proxyHost) && !empty($proxyPort)) {
                     $stream_options['http']['proxy'] = 'tcp://' . $proxyHost . ':' . $proxyPort;
                     $stream_options['http']['request_fulluri'] = true;
                     // required by squid proxy
                     if (!empty($proxyUser) && !empty($proxyPassword)) {
                         $stream_options['http']['header'] .= 'Proxy-Authorization: Basic ' . base64_encode("{$proxyUser}:{$proxyPassword}") . "\r\n";
                     }
                 }
                 $ctx = stream_context_create($stream_options);
             }
             // save to file
             if (is_resource($file)) {
                 $handle = fopen($aUrl, 'rb', false, $ctx);
                 while (!feof($handle)) {
                     $response = fread($handle, 8192);
                     $fileLength += Piwik_Common::strlen($response);
                     fwrite($file, $response);
                 }
                 fclose($handle);
             } else {
                 $response = @file_get_contents($aUrl, 0, $ctx);
                 $fileLength = Piwik_Common::strlen($response);
             }
             // restore the socket_timeout value
             if (!empty($default_socket_timeout)) {
                 @ini_set('default_socket_timeout', $default_socket_timeout);
             }
         } else {
             if ($method == 'curl') {
                 $ch = @curl_init();
                 if (!empty($proxyHost) && !empty($proxyPort)) {
                     @curl_setopt($ch, CURLOPT_PROXY, $proxyHost . ':' . $proxyPort);
                     if (!empty($proxyUser) && !empty($proxyPassword)) {
                         // PROXYAUTH defaults to BASIC
                         @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyUser . ':' . $proxyPassword);
                     }
                 }
                 $curl_options = array(CURLOPT_BINARYTRANSFER => is_resource($file), CURLOPT_URL => $aUrl, CURLOPT_USERAGENT => $userAgent, CURLOPT_HTTPHEADER => array($xff, $via, $acceptLanguage), CURLOPT_HEADER => false, CURLOPT_CONNECTTIMEOUT => $timeout);
                 // Case archive.php is triggering archiving on https:// and the certificate is not valid
                 if ($acceptInvalidSslCertificate) {
                     $curl_options += array(CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false);
                 }
                 @curl_setopt_array($ch, $curl_options);
                 self::configCurlCertificate($ch);
                 /*
                  * as of php 5.2.0, CURLOPT_FOLLOWLOCATION can't be set if
                  * in safe_mode or open_basedir is set
                  */
                 if ((string) ini_get('safe_mode') == '' && ini_get('open_basedir') == '') {
                     $curl_options = array(CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5);
                     @curl_setopt_array($ch, $curl_options);
                 }
                 if (is_resource($file)) {
                     // write output directly to file
                     @curl_setopt($ch, CURLOPT_FILE, $file);
                 } else {
                     // internal to ext/curl
                     @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                 }
                 ob_start();
                 $response = @curl_exec($ch);
                 ob_end_clean();
                 if ($response === true) {
                     $response = '';
                 } else {
                     if ($response === false) {
                         $errstr = curl_error($ch);
                         if ($errstr != '') {
                             throw new Exception('curl_exec: ' . $errstr);
                         }
                         $response = '';
                     }
                 }
                 $contentLength = @curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
                 $fileLength = is_resource($file) ? @curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD) : Piwik_Common::strlen($response);
                 @curl_close($ch);
                 unset($ch);
             } else {
                 throw new Exception('Invalid request method: ' . $method);
             }
         }
     }
     if (is_resource($file)) {
         fflush($file);
         @fclose($file);
         $fileSize = filesize($destinationPath);
         if ($contentLength > 0 && $fileLength != $contentLength || $fileSize != $fileLength) {
             throw new Exception('File size error: ' . $destinationPath . '; expected ' . $contentLength . ' bytes; received ' . $fileLength . ' bytes; saved ' . $fileSize . ' bytes to file');
         }
         return true;
     }
     if ($contentLength > 0 && $fileLength != $contentLength) {
         throw new Exception('Content length error: expected ' . $contentLength . ' bytes; received ' . $fileLength . ' bytes');
     }
     return trim($response);
 }
コード例 #3
0
ファイル: Url.php プロジェクト: nnnnathann/piwik
 /**
  * Validate "Host" (untrusted user input)
  *
  * @param string $host         Contents of Host: header from Request
  * @param array  $trustedHosts An array of trusted hosts
  *
  * @return boolean True if valid; false otherwise
  */
 public static function isValidHost($host, $trustedHosts)
 {
     // Only punctuation we allow is '[', ']', ':', '.' and '-'
     $hostLength = Piwik_Common::strlen($host);
     if ($hostLength !== strcspn($host, '`~!@#$%^&*()_+={}\\|;"\'<>,?/ ')) {
         return false;
     }
     $untrustedHost = Piwik_Common::mb_strtolower($host);
     $hostRegex = Piwik_Common::mb_strtolower(str_replace('.', '\\.', '/(^|.)' . implode('|', $trustedHosts) . '(:[0-9]+)?$/'));
     return 0 !== preg_match($hostRegex, rtrim($untrustedHost, '.'));
 }
コード例 #4
0
ファイル: IP.php プロジェクト: neolf/PIWIK4MOBILE
 /**
  * Determines if an IP address is in a specified IP address range.
  *
  * An IPv4-mapped address should be range checked with an IPv4-mapped address range.
  *
  * @param string $ip IP address in network address format
  * @param array $ipRanges List of IP address ranges
  * @return bool True if in any of the specified IP address ranges; else false.
  */
 public static function isIpInRange($ip, $ipRanges)
 {
     $ipLen = Piwik_Common::strlen($ip);
     if (empty($ip) || empty($ipRanges) || $ipLen != 4 && $ipLen != 16) {
         return false;
     }
     foreach ($ipRanges as $range) {
         if (is_array($range)) {
             // already split into low/high IP addresses
             $range[0] = self::P2N($range[0]);
             $range[1] = self::P2N($range[1]);
         } else {
             // expect CIDR format but handle some variations
             $range = self::getIpsForRange($range);
         }
         if ($range === false) {
             continue;
         }
         $low = $range[0];
         $high = $range[1];
         if (Piwik_Common::strlen($low) != $ipLen) {
             continue;
         }
         // binary-safe string comparison
         if ($ip >= $low && $ip <= $high) {
             return true;
         }
     }
     return false;
 }
コード例 #5
0
ファイル: Url.php プロジェクト: nomoto-ubicast/piwik
 /**
  * Validate "Host" (untrusted user input)
  *
  * @param string|false $host Contents of Host: header from Request. If false, gets the
  *                           value from the request.
  *
  * @return boolean True if valid; false otherwise
  */
 public static function isValidHost($host = false)
 {
     // only do trusted host check if it's enabled
     if (isset(Piwik_Config::getInstance()->General['enable_trusted_host_check']) && Piwik_Config::getInstance()->General['enable_trusted_host_check'] == 0) {
         return true;
     }
     if ($host === false) {
         $host = $_SERVER['HTTP_HOST'];
         if (empty($host)) {
             return true;
         }
     }
     // if host is in hardcoded whitelist, assume it's valid
     if (in_array($host, self::$alwaysTrustedHosts)) {
         return true;
     }
     $trustedHosts = @Piwik_Config::getInstance()->General['trusted_hosts'];
     // if no trusted hosts, just assume it's valid
     if (empty($trustedHosts)) {
         self::saveTrustedHostnameInConfig($host);
         return true;
     }
     // Only punctuation we allow is '[', ']', ':', '.' and '-'
     $hostLength = Piwik_Common::strlen($host);
     if ($hostLength !== strcspn($host, '`~!@#$%^&*()_+={}\\|;"\'<>,?/ ')) {
         return false;
     }
     foreach ($trustedHosts as &$trustedHost) {
         $trustedHost = preg_quote($trustedHost);
     }
     $untrustedHost = Piwik_Common::mb_strtolower($host);
     $untrustedHost = rtrim($untrustedHost, '.');
     $hostRegex = Piwik_Common::mb_strtolower('/(^|.)' . implode('|', $trustedHosts) . '$/');
     $result = preg_match($hostRegex, $untrustedHost);
     //		var_dump($hostRegex);var_dump($untrustedHost);var_dump($result);
     return 0 !== $result;
 }