<?php

	/**
	* @author Michael Spector <michael@zend.com>
	* @copyright Zend Technologies Ltd 2005
	* @version $Revision: 1.19.4.9 $
	* @since $Date: 2005/09/14 14:26:37 $
	*/

	include_once ('Log.inc');

	/**
	* class Util
	* 
	* This class used for providing helper functions
	*/
	class Util
	{
		/**
		* This function makes specified path nicer
		* It removes '/./', '/../' and extra '/' from it
		*/
		function nicePath($path)
		{
			$path = preg_replace('@///*@', '/', $path); /* multiple '/' */
			$path = preg_replace('@^\./@', '', $path); /* first './' from the path */
			$path = preg_replace('@/\./@', '/', $path); /* '/./' from the path */
			$path = preg_replace('@^[^/]+/\.\./?@', '', $path); /* dir/.. from the beginning */
			$path = preg_replace('@\/[^/]+/\.\./?@', '/', $path); /* /dir/.. from the path */
			$path = preg_replace('@([^/])/+$@', '\\1', $path); /* last / from the end of path */

			return $path;
		}

		/**
		* This function returns first argument as is if its a full path,
		* otherwise it prepends second argument to it.
		* @param string input path
		* @param string root path (to prepend, in case if input path is not full)
		* @return string full path
		*/
		function fullPath($path, $root)
		{
			return $path[0] == '/' ? $path : $root.'/'.$path;
		}

		/**
		* This function performs matching file to pattern
		* @param string file
		* @param string pattern
		* @return bool True whether file matches patterm, otherwise false
		*/
		function fileMatch($file, $pattern)
		{
			if(function_exists('fnmatch')) {
				return fnmatch ($pattern, $file);
			}

			for($i=0; $i<strlen($pattern); $i++) {
				if($pattern[$i] == "*") { /* star wildcard (matches all or nothing :) */
					for($c=$i; $c<max(strlen($pattern), strlen($file)); $c++) {
						if(Util::fileMatch(substr($file, $c), substr($pattern, $i+1))) {
							return true;
						}
					}
					return false;
				}

				if($pattern[$i] == "[") { /* [] set of letters (matches something :) */
					unset($sqr_braket);
					$letter_set = array();
					for($c=$i+1; $c<strlen($pattern); $c++) {
						if($pattern[$c] != "]") {
							array_push($letter_set, $pattern[$c]);
						}
						else {
							$sqr_braket = true;
							break;
						}
					}
					if(!isset($sqr_braket)) {
						print("No closing ']' found\n");
						return false;
					}
					foreach ($letter_set as $letter) {
						if(Util::fileMatch(substr($file, $i), $letter.substr($pattern, $c+1))) {
							return true;
						}
					}
					return false;
				}

				if($pattern[$i] == "?") { /* question sign wildcard (matches only one thing :) */
					continue;
				}

				if($pattern[$i] != $file[$i]) {
					return false;
				}
			}
			return true;
		}

		/**
		* This function returns all directory contents, that
		* match specified pattern
		* @param string directory path
		* @param string pattern
		* @return array filenames that match the pattern
		*/
		function listDir($path, $pattern)
		{
			if(function_exists ('glob')) {
				return glob($path.'/'.$pattern);
			}

			$files_list = array();
			$dir = opendir($path);
			while($file = readdir($dir)){
				if($file == "." || $file == ".."){
					continue;
				}
				if(Util::fileMatch($file, $pattern)){
					array_push($files_list, realpath($path.'/'.$file));
				}
			}
			closedir($dir);

			return $files_list;
		}

		/**
		* This function applies XSLT transformation on XML document and returns the result
		* @param string path to XML file
		* @param string path to XSLT file
		* @return string result of transformation
		*/
		function xsltTransformXML($xml_file, $xslt_file)
		{
			if(function_exists('xslt_create')) {
				return Util::xsltTransformXMLwithSablotron ($xml_file, $xslt_file);
			}
			else if (function_exists('domxml_xslt_stylesheet_file')) {
				return Util::xsltTransformXMLwithDom ($xml_file, $xslt_file);
			}
			else {
				print ("None of XSLT processors is avalable\n");
				return;
			}
		}

		/**
		* This function applies XSLT transformation using Sablotron
		* @param string path to XML file
		* @param string path to XSLT file
		* @return string result of transformation
		*/
		function xsltTransformXMLwithSablotron ($xml_file, $xslt_file)
		{
			$xsltproc = xslt_create();
			$newt_code = xslt_process ($xsltproc, $xml_file, $xslt_file);
			if(empty ($newt_code)) {
				print ('XSLT processing error: '. xslt_error($xsltproc));
				return;
	  	}
	 		xslt_free($xsltproc);
			return preg_replace('@<\?xml.*\?>@U', '', $newt_code);
		}

		/**
		* This function applies XSLT transformation using DOM XSLT
		* @param string path to XML file
		* @param string path to XSLT file
		* @return string result of transformation
		*/
		function xsltTransformXMLwithDom ($xml_file, $xslt_file)
		{
			if(!$dom_xml_obj = domxml_open_file($xml_file)) {
				print("Error parsing XML file: $xml_file\n");
				return;
			}
			$dom_xslt_obj = domxml_xslt_stylesheet_file ($xslt_file);
			$dom_trans_obj = $dom_xslt_obj->process ($dom_xml_obj);
			return $dom_xslt_obj->result_dump_mem ($dom_trans_obj);
		}

		/**
		* This function can be used for sending emails with attachments
		* @param string To: recipient
		* @param string Subject: subject of the letter
		* @param string From: sender
		* @param string path to the file to attach
		* @param string mime type of the file
		* @return bool exit status of PHP function mail() - it doesn't mean the status of mail delivery
		*/
		function sendMailWithAttachment($to, $subject, $message, $from, $file_name, $mime_type="application/octet-stream")
		{
			// Generate a boundary string
			$semi_rand = md5(time());
			$mime_boundary = "Zend-$semi_rand";

			$smtp_headers = "X-Mailer: PHP mailer\n";

			$text_body = "--$mime_boundary\n".
				"Content-Type: text/plain; charset=\"us-ascii\"\n\n".
				"$message\n";

			// Open file to attach
			$data = Util::fileToStr ($file_name);

			// Prepare an encoded message
			$text_encoded = "--$mime_boundary\n".
				"Content-type: $mime_type; name=\"".basename($file_name)."\";\n".
				"Content-Transfer-Encoding: base64\n".
				"Content-disposition: attachment; filename=\"".basename($file_name)."\"\n\n".
				chunk_split(base64_encode($data))."\n".
				"--$mime_boundary--\n";

			$mime_headers = "MIME-version: 1.0\n".
				"Content-type: multipart/mixed; ".
				"boundary=\"$mime_boundary\"\n".
				"Content-transfer-encoding: 7BIT\n".
				"X-attachments: $file_name;\n\n";

			// Send the message
			$headers = (empty($from) ? "" : "From: $from \r\n") . $smtp_headers . $mime_headers;
			$message = $text_body . $text_encoded;

			return mail($to, $subject, $message, $headers);
		}

		/**
		* This function writes contents of string to file
		* @param string string to write
		* @param string filename
		* @return bool exit status
		*/
		function strToFile ($str, $file)
		{
			if (function_exists('file_put_contents')) {
				if(@file_put_contents ($file, $str)) return true;
			}
			$fp = @fopen ($file, "wb");
			if (!is_resource($fp)) {
				Log::append ("Error opening file: $file for writing");
				return false;
			}
			fwrite ($fp, $str);
			fclose ($fp);
			return true;
		}

		/**
		* This function returns contents of the file
		* @param string filename
		* @param int offset from where to start reading (default: 0)
		* @return string contents of the file
		*/
		function fileToStr ($file, $offset=0)
		{
			if (function_exists('file_get_contents') && $offset==0) {
				return @file_get_contents ($file);
			}
			$fp = @fopen ($file, "rb");
			if(is_resource($fp)) {
				if ($offset > 0) fseek ($fp, $offset, SEEK_SET);
				else if($offset < 0) fseek ($fp, $offset, SEEK_END);

				$bytes = filesize($file);
				$str = "";
				if ($bytes > 0) $str = fread ($fp, $offset < 0 ? -$offset : $bytes-$offset);
				fclose ($fp);
				return $str;
			}
			Log::append ("Error opening file: $file for reading");
			return null;
		}

		/**
		* This function executes command and returns output as string
		* @param string command
		* @param int exit status
		* @return string output from the command
		*/
		function cmdToStr ($command, &$status)
		{
			exec($command.' 2>&1', $res_arr, $status);
			Log::append ("Executing: $command (exit status: $status)");
			return implode("\n", $res_arr);
		}

		/**
		* This function executes command and returns exit status
		* @param string command
		* @return int exit status
		*/
		function execCmd ($command)
		{
			$command = preg_replace ('@\d\s*>\s*/dev/null\s*@', '', $command);
			$command = $command.' 2> /dev/null 1> /dev/null';
			passthru ($command, &$status);
			Log::append ("Executing: $command (exit status: $status)");
			return $status;
		}

		/**
		* This function returns Glibc version
		* @return string Glibc version
		*/
		function glibcVersion()
		{
			if (preg_match ("#(\d[\.\d]*\d)#", shell_exec("ls /lib/{libc,ld}-?.?.* 2>/dev/null"), $match)) {
				return $match[1];
			}
			return null;
		}

		/**
		* This functions works like 'which' command in Unix
		* @return string full path of the first command that was found, otherwise - null
		*/
		function whichCmd($command, $extra_path=array())
		{
			static $which_cache;

			if(isset($which_cache[$command])) {
				return $which_cache[$command];
			}

			$extra_path[] = '/sbin';
			$extra_path[] = '/usr/sbin';

			$path_arr = array_merge(explode(':', getenv('PATH')), $extra_path);
			foreach ($path_arr as $path) {
				$full_path = realpath ($path.'/'.$command);
				if (file_exists ($full_path) && is_executable($full_path)) {
					$which_cache[$command] = $full_path;
					return $full_path;
				}
			}
			return null;
		}

		/**
		* This function kills process with specified signal
		* @param int PID
		* @param mixed signal number
		* @return bool exit status of the operation
		*/
		function kill($pid, $sig='TERM')
		{
			$pid = trim($pid);
			if (is_numeric($pid)) {
				$kill = Util::whichCmd("kill");
				if ($kill) {
					if(Util::execCmd ("$kill -$sig $pid") == 0) {
						return true;
					}
				}
			}
			return false;
		}

		/**
		* This function finds all PIDs of specified process
		* @param string name (or part of the name) of the process
		* @param &array PIDs of all matched processes
		* @return bool exit status of the operation
		*/
		function pidof ($process, &$pids)
		{
			$ps = Util::whichCmd("ps");
			$pids = array();

			if($ps) {
				exec ($ps.' ax 2> /dev/null', $ps_table, $status);
				if (count($ps_table) == 0) {
					exec ($ps.' -ef 2> /dev/null', $ps_table, $status);
				}
				foreach ($ps_table as $line) {
					if(preg_match('@^[^\d]*(\d+)\s.*'.addcslashes($process, '@').'@', $line, $match)) {
						array_push ($pids, $match[1]);
					}
				}
				return (count($pids) > 0);
			}
			return false;
		}

		/**
		* This function kills process with specified name
		* @param string name (or part of the name) of the process
		* @param mixed signal number
		* @return bool exit status of the operation
		*/
		function killProcess ($process, $sig='TERM')
		{
			if (Util::pidof ($process, $pids)) {
				foreach ($pids as $pid) {
					if(Util::kill ($pid, $sig)) {
						Log::append ("Killed: $process with signal: $sig");
					}
				}
				// Check whether there are no still opened processes in memory
				return !Util::pidof ($process, $pids);
			}
			return false;
		}

		/**
		* This function parses URL
		* If no protocol was specified, this function assumes 'http' protocol
		* @param string URL
		* @return array output from PHP's parse_url
		*/
		function parseURL ($url)
		{
			// If protocol exists - return native call
			if(preg_match('@^[^:]+://.*$@', $url)) {
				return @parse_url($url);
			}
			// Otherwise assume 'http' protocol and call to native function
			$url = 'http://'.$url;
			$url_arr = @parse_url($url);
			unset ($url_arr['scheme']);
			return $url_arr;
		}

		/**
		* This function strips HTML tags
		* @param string HTML page
		* @return string text
		*/
		function stripHTML ($page)
		{
			foreach (array ('head', 'title', 'form', 'script') as $tag) {
				$page = preg_replace ("/<$tag.*>.+<\/\s*$tag>/U", "", $page);
			}
			$page = preg_replace ("/<.+>/U", "", $page);
			$page = html_entity_decode ($page);

			return $page;
		}

		/**
		* This function strips HTTP error response
		* @param string HTTP response
		* @return string text
		*/
		function stripHTTPError ($text)
		{
			$text = Util::stripHTML ($text);
			$text = trim ($text);
			$text = preg_replace ("/^[\r\n]+/", "", $text);
			$text = preg_replace ("/404\s+Not\s+Found\s+Not Found/si", "", $text);
			$text = preg_replace ("/^Apache\/.*Server at.*$/m", "", $text);
			$text = preg_replace ("/[\r\n]+/", "\n", $text);

			return $text;
		}

		/**
		* Checks whether the given IP is valid
		* @param string IP
		* @return boolean true - valid, false - invalid
		*/
		function IsIPValid ($ip)
		{
			if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $ip, $match)) {
				if($match[1] < 256 && $match[2] < 256 && $match[3] < 256 && $match[4] < 256) {
					return true;
				}
			}
			return false;
		}
	}
?>


syntax highlighted by Code2HTML, v. 0.9.1