* Invision Power Services * IP.Board v3.2.3 * Wrapper for retrieving file contents. Methods available for removing files and directories as well. * Last Updated: $Date: 2011-08-23 10:24:47 -0400 (Tue, 23 Aug 2011) $ * * * @author $Author: mark $ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license This is NULLED! * @package IP.Board * @subpackage Kernel * @link http://hatynka.in * @since Tuesday 22nd February 2005 (16:55) * @version $Revision: 9404 $ */ if ( ! defined( 'IPS_CLASSES_PATH' ) ) { /** * Define classes path */ define( 'IPS_CLASSES_PATH', dirname(__FILE__) ); } class classFileManagement { /** * Use sockets flag * * @var integer */ public $use_sockets = 1; /** * Error array * * @var array */ public $errors = array(); /** * Key prefix * Prefix to identify communication strings * * @var string */ public $key_prefix = ''; /** * HTTP Status Code/Text * * @var integer HTTP Status code */ public $http_status_code = 0; /** * HTTP Status Code/Text * * @var string HTTP Status text */ public $http_status_text = ""; /** * Raw HTTP header output * * @var string Raw HTTP header results */ public $raw_headers = ''; /**#@+ * Set Authentication * * @var string */ public $auth_req = 0; public $auth_user; public $auth_pass; public $auth_raw; /**#@-*/ /** * Timeout setting * * @var int */ public $timeout = 15; /** * Get file contents (accepts URL or path) * * @param string URI / File path * @param string HTTP User * @param string HTTP Pass * @return string File data */ public function getFileContents( $file_location, $http_user='', $http_pass='' ) { //------------------------------- // INIT //------------------------------- $contents = ""; $file_location = str_replace( '&', '&', $file_location ); //----------------------------------------- // Inline user/pass? //----------------------------------------- if ( $http_user and $http_pass ) { $this->auth_req = 1; $this->auth_user = $http_user; $this->auth_pass = $http_pass; } //------------------------------- // Hello //------------------------------- if ( ! $file_location ) { return FALSE; } if ( ! stristr( $file_location, 'http://' ) AND ! stristr( $file_location, 'https://' ) ) { //------------------------------- // It's a path! //------------------------------- if ( ! file_exists( $file_location ) ) { $this->errors[] = "Файл '{$file_location}' не существует, Проверье правильность пути."; return; } $contents = $this->_getContentsWithFopen( $file_location ); } else { //------------------------------- // Is URL, try curl and then fall back //------------------------------- if( ( $contents = $this->_getContentsWithCurl( $file_location ) ) === false ) { if ( $this->use_sockets ) { $contents = $this->_getContentsWithSocket( $file_location ); } else { $contents = $this->_getContentsWithFopen( $file_location ); } } } return $contents; } /** * Sends a POST request to specified URL * * @param string URI to post to * @param array Arry of post fields * @param string HTTP User * @param string HTTP Pass * @return string File data */ public function postFileContents( $file_location='', $post_array=array(), $http_user='', $http_pass='' ) { //------------------------------- // INIT //------------------------------- $contents = ""; $file_location = str_replace( '&', '&', $file_location ); if ( ! is_array( $post_array ) OR ! count( $post_array ) ) { return false; } if ( ! $file_location ) { return false; } if( ( $contents = $this->_getContentsWithCurl( $file_location, $post_array ) ) === false ) { $contents = $this->_getContentsWithSocket( $file_location, $post_array ); } return $contents; } /** * Get file contents (with PHP's fopen) * * @param string File location * @return string File data */ protected function _getContentsWithFopen( $file_location ) { //------------------------------- // INIT //------------------------------- $buffer = ""; @clearstatcache(); if ( $FILE = fopen( $file_location, "r" ) ) { @stream_set_timeout( $FILE, $this->timeout ); $status = @stream_get_meta_data($FILE); while ( ! feof( $FILE ) && ! $status['timed_out'] ) { $buffer .= fgets( $FILE, 4096 ); $status = stream_get_meta_data($FILE); } fclose($FILE); } if ( $buffer ) { $this->http_status_code = 200; } return $buffer; } /** * Get file contents (with sockets) * * @param string File location * @param array Data to post (automatically converts to POST request) * @return string File data */ protected function _getContentsWithSocket( $file_location, $post_array=array() ) { //------------------------------- // INIT //------------------------------- $data = null; //------------------------------- // Parse URL //------------------------------- $url_parts = @parse_url($file_location); if ( ! $url_parts['host'] ) { $this->errors[] = "Не найден хост в URL '{$file_location}'!"; return FALSE; } //------------------------------- // Finalize //------------------------------- $host = $url_parts['host']; $port = ( isset($url_parts['port']) ) ? $url_parts['port'] : ( $url_parts['scheme'] == 'https' ? 443 : 80 ); //------------------------------- // Tidy up path //------------------------------- if ( !empty( $url_parts["path"] ) ) { $path = $url_parts["path"]; } else { $path = "/"; } if ( !empty( $url_parts["query"] ) ) { $path .= "?" . $url_parts["query"]; } //------------------------------- // Open connection //------------------------------- if ( ! $fp = @fsockopen( $url_parts['scheme'] == 'https' ? "ssl://" . $host : $host, $port, $errno, $errstr, $this->timeout ) ) { $this->errors[] = "Не могу установить соединение с {$host}"; return FALSE; } else { $final_carriage = ( $this->auth_req or $this->auth_raw ) ? "" : "\r\n"; //----------------------------------------- // Are we posting? //----------------------------------------- if( is_array($post_array) AND count($post_array) ) { $post_back = array(); foreach ( $post_array as $key => $val ) { $post_back[] = $this->key_prefix . $key . '=' . urlencode($val); } $post_back_str = implode( '&', $post_back); $header = "POST {$path} HTTP/1.0\r\nHost:{$host}\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: Keep-Alive\r\nContent-Length: " . strlen($post_back_str) . "\r\n{$final_carriage}{$post_back_str}"; } else { $header = "GET {$path} HTTP/1.0\r\nHost:{$host}\r\nConnection: Keep-Alive\r\n{$final_carriage}"; } if ( ! fputs( $fp, $header ) ) { $this->errors[] = "Не удалось отправить запрос на {$host}!"; return FALSE; } if ( $this->auth_req ) { if ( $this->auth_user && $this->auth_pass ) { $header = "Authorization: Basic ".base64_encode("{$this->auth_user}:{$this->auth_pass}")."\r\n\r\n"; if ( ! fputs( $fp, $header ) ) { $this->errors[] = "Неверные данные авторизации!"; return FALSE; } } } elseif ( $this->auth_raw ) { $header = $this->auth_raw."\r\n\r\n"; if ( ! fputs( $fp, $header ) ) { $this->errors[] = "Authorization Failed!"; return FALSE; } } } @stream_set_timeout( $fp, $this->timeout ); $status = @stream_get_meta_data($fp); while( ! feof($fp) && ! $status['timed_out'] ) { $data .= fgets( $fp, 8192 ); $status = stream_get_meta_data($fp); } fclose ($fp); //------------------------------- // Strip headers //------------------------------- // HTTP/1.1 ### ABCD $this->http_status_code = substr( $data, 9, 3 ); $this->http_status_text = substr( $data, 13, ( strpos( $data, "\r\n" ) - 13 ) ); //----------------------------------------- // Try to deal with chunked.. //----------------------------------------- $_chunked = false; if( preg_match( '/Transfer\-Encoding:\s*chunked/i', $data ) ) { $_chunked = true; } $tmp = preg_split("/\r\n\r\n/", $data, 2); $data = trim($tmp[1]); $this->raw_headers = trim($tmp[0]); //----------------------------------------- // Easy way out :P //----------------------------------------- if( $_chunked ) { $lines = explode( "\n", $data ); array_pop($lines); array_shift($lines); $data = implode( "\n", $lines ); } return $data; } /** * Get file contents (with cURL) * * @param string File location * @param array Data to post (automatically converts to POST request) * @return string File data */ protected function _getContentsWithCurl( $file_location, $post_array=array() ) { if ( function_exists( 'curl_init' ) AND function_exists("curl_exec") ) { //----------------------------------------- // Are we posting? //----------------------------------------- $ch = curl_init( $file_location ); curl_setopt( $ch, CURLOPT_HEADER , 1 ); curl_setopt( $ch, CURLOPT_TIMEOUT , $this->timeout ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER , 1 ); curl_setopt( $ch, CURLOPT_FAILONERROR , 1 ); curl_setopt( $ch, CURLOPT_MAXREDIRS , 10 ); curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER , false ); curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST , 1 ); /** * Cannot set this when safe_mode or open_basedir is enabled * @link http://forums.invisionpower.com/index.php?autocom=tracker&showissue=11334 */ if( !ini_get('open_basedir') AND !ini_get('safe_mode') ) { curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); } if( $this->auth_req ) { curl_setopt( $ch, CURLOPT_USERPWD , "{$this->auth_user}:{$this->auth_pass}" ); } elseif ( $this->auth_raw ) { curl_setopt( $ch, CURLOPT_HTTPHEADER, array( $this->auth_raw ) ); } //----------------------------------------- // Are we posting? //----------------------------------------- if( is_array($post_array) AND count($post_array) ) { $post_back = array(); foreach ( $post_array as $key => $val ) { $post_back[] = $this->key_prefix . $key . '=' . urlencode($val); } $post_back_str = implode( '&', $post_back); curl_setopt( $ch, CURLOPT_POST , true ); curl_setopt( $ch, CURLOPT_POSTFIELDS , $post_back_str ); } else { curl_setopt( $ch, CURLOPT_POST , false ); } $data = curl_exec($ch); //----------------------------------------- // Handle some errors we can handle //----------------------------------------- if ( curl_errno($ch) == 60 || curl_errno($ch) == 77 ) { // CURL_SSL_CACERT if ( defined('CA_BUNDLE_PATH') ) { curl_setopt( $ch, CURLOPT_CAINFO, CA_BUNDLE_PATH ); } else { curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); } $data = curl_exec($ch); } else if ( curl_errno($ch) == 6 ) { // Name lookup failed / DNS issues $url_parts = @parse_url( $file_location ); $ip = @gethostbyname( $url_parts['host'] ); if ( $ip and preg_match( '#^\d{1,3}\.#', $ip ) ) { // Turn of verify SSL as the IP will not match domain of cert curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); curl_setopt( $ch, CURLOPT_URL, $url_parts['scheme'] . '://' . $ip . '/' . $url_parts['path'] ); $data = curl_exec($ch); } } curl_close($ch); if( $data ) { $tmp = preg_split("/\r\n\r\n/", $data, 2); $data = trim($tmp[1]); $this->raw_headers = trim($tmp[0]); } $this->http_status_code = substr( $this->raw_headers, 9, 3 ); $this->http_status_text = substr( $this->raw_headers, 13, ( strpos( $this->raw_headers, "\r\n" ) - 13 ) ); if ( $data AND !$this->http_status_code ) { $this->http_status_code = 200; } return $data; } else { return false; } } /** * Tail a file * * @param string Full path to file * @param int No. lines to tail */ public function tailFile( $file, $lines=100 ) { /* INIT */ $content = ''; $t = array(); if ( is_file( $file ) ) { $handle = @fopen( $file, 'r' ); if ( $handle ) { $l = $lines; $pos = -2; $beg = false; while ( $l > 0 ) { $_t = " "; while( $_t != "\n" ) { if ( @fseek( $handle, $pos, SEEK_END ) == -1 ) { $beg = true; break; } $_t = @fgetc( $handle ); $pos--; } $l--; if ( $beg ) { rewind( $handle ); } $t[ $lines - $l - 1 ] = @fgets( $handle ); if ( $beg ) { break; } } @fclose ($handle); $content = trim( implode( "", array_reverse( $t ) ) ); } } return $content; } /** * Copies contents of one directory to another, creating if necessary * * @param string File location [from] * @param string File location [destination] * @param string [Optional] CHMOD mode to set * @return boolean Copy successful */ public function copyDirectory($from_path, $to_path, $mode = 0 ) { $this->errors = array(); $mode = $mode ? $mode : IPS_FOLDER_PERMISSION; //----------------------------------------- // Strip off trailing slashes... //----------------------------------------- $from_path = rtrim( $from_path, '/' ); $to_path = rtrim( $to_path, '/' ); if ( ! is_dir( $from_path ) ) { $this->errors[] = "Невозможно найти директорию '{$from_path}'"; return false; } if ( ! is_dir( $to_path ) ) { if ( ! @mkdir( $to_path, $mode ) ) { $this->errors[] = "Невозможно создать директорию '{$to_path}', проверьте права доступа и попробуйте снова"; return FALSE; } else { @chmod( $to_path, $mode ); } } if ( is_dir( $from_path ) ) { $handle = opendir($from_path); while ( ($file = readdir($handle)) !== false ) { if ( ($file != ".") && ($file != "..") ) { if ( is_dir( $from_path."/".$file ) ) { $this->copyDirectory( $from_path."/".$file, $to_path."/".$file ); } if ( is_file( $from_path."/".$file ) ) { copy( $from_path."/".$file, $to_path."/".$file ); @chmod( $to_path."/".$file, IPS_FILE_PERMISSION ); } } } closedir($handle); } if ( ! count( $this->errors ) ) { return true; } } /** * Removes a directory * * @param string File location [from] * @return boolean Removal successful */ public function removeDirectory($file) { $errors = 0; //----------------------------------------- // Remove trailing slashes.. //----------------------------------------- $file = rtrim( $file, '/' ); if ( file_exists($file) ) { //----------------------------------------- // Attempt CHMOD //----------------------------------------- @chmod( $file, IPS_FOLDER_PERMISSION ); if ( is_dir( $file ) ) { $handle = opendir( $file ); while ( ($filename = readdir($handle)) !== false ) { if ( ($filename != ".") && ($filename != "..") ) { $this->removeDirectory( $file . "/" . $filename ); } } closedir($handle); if ( ! @rmdir($file) ) { $errors++; } } else { if ( ! @unlink($file) ) { $errors++; } } } if( $errors == 0 ) { return true; } else { return false; } } /** * Empties a directory * * @param string File location [from] * @param int In a loop (not root folder) * @return boolean Empty successful */ public function emptyDirectory($file, $inLoop=0) { $errors = 0; //----------------------------------------- // Remove trailing slashes.. //----------------------------------------- $file = rtrim( $file, '/' ); if ( file_exists($file) ) { //----------------------------------------- // Attempt CHMOD //----------------------------------------- @chmod( $file, IPS_FOLDER_PERMISSION ); if ( is_dir( $file ) ) { $handle = opendir( $file ); while ( ($filename = readdir($handle)) !== false ) { if ( ($filename != ".") && ($filename != "..") ) { $this->emptyDirectory( $file."/".$filename, 1 ); } } closedir($handle); if ( $inLoop ) { if ( ! @rmdir($file) ) { $errors++; } } } else { if ( ! @unlink($file) ) { $errors++; } } } if( $errors == 0 ) { return true; } else { return false; } } /** * Receive data from the "send" function * * @param array Array of fields to return * @return array Array of fields */ public function communicationReceiveData( $return_fields=array() ) { //----------------------------------------- // INIT //----------------------------------------- $return_array = array(); //----------------------------------------- // Get data... //----------------------------------------- foreach( $_REQUEST as $k => $v ) { if ( strstr( $k, $this->key_prefix ) ) { $k = str_replace( $this->key_prefix, '', $k ); $return_array[ $k ] = $v; } } return $this->_filterFields( $return_array ); } /** * Filter out fields (optional) * * @param array Array of fields to return * @return array Array of fields */ protected function _filterFields( $in_fields=array(), $out_fields=array() ) { //----------------------------------------- // INIT //----------------------------------------- $return_array = array(); //----------------------------------------- // Check //----------------------------------------- if ( ! is_array( $in_fields ) or ! count( $in_fields ) ) { return false; } if ( ! is_array( $out_fields ) or ! count( $out_fields ) ) { return $in_fields; } //----------------------------------------- // Get data... //----------------------------------------- foreach( $out_fields as $k => $type ) { if ( $in_fields[ $k ] ) { switch ( $type ) { default: case 'string': case 'text': $return_array[ $k ] = trim( $in_fields[ $k ] ); break; case 'int': case 'integar': $return_array[ $k ] = intval( $in_fields[ $k ] ); break; case 'float': case 'floatval': $return_array[ $k ] = floatval( $in_fields[ $k ] ); break; } } } return $return_array; } }