From f1ab2f022fdc780aca0944d90e9a0e844a0820d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Mon, 27 May 2024 13:12:17 +0200 Subject: =?UTF-8?q?2024-02-19:=20popravljen=20(prej=C5=A1nji=20commit=20je?= =?UTF-8?q?=20napa=C4=8Den)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/RFC822.php | 872 ---------------------------------- function/mimePart.php | 333 ------------- function/smtp.php | 361 -------------- function/thumb.php | 1244 ------------------------------------------------- 4 files changed, 2810 deletions(-) delete mode 100644 function/RFC822.php delete mode 100644 function/mimePart.php delete mode 100644 function/smtp.php delete mode 100644 function/thumb.php (limited to 'function') diff --git a/function/RFC822.php b/function/RFC822.php deleted file mode 100644 index ce41f72..0000000 --- a/function/RFC822.php +++ /dev/null @@ -1,872 +0,0 @@ - (A comment), ted@example.com (Ted Bloggs), Barney;'; -* $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', TRUE) -* print_r($structure); -* -* @author Richard Heyes -* @author Chuck Hagenbuch -* @version $Revision: 1.1 $ -* @package Mail -*/ - -class Mail_RFC822 -{ - /** - * The address being parsed by the RFC822 object. - * @var string $address - */ - var $address = ''; - - /** - * The default domain to use for unqualified addresses. - * @var string $default_domain - */ - var $default_domain = 'localhost'; - - /** - * Should we return a nested array showing groups, or flatten everything? - * @var boolean $nestGroups - */ - var $nestGroups = true; - - /** - * Whether or not to validate atoms for non-ascii characters. - * @var boolean $validate - */ - var $validate = true; - - /** - * The array of raw addresses built up as we parse. - * @var array $addresses - */ - var $addresses = array(); - - /** - * The final array of parsed address information that we build up. - * @var array $structure - */ - var $structure = array(); - - /** - * The current error message, if any. - * @var string $error - */ - var $error = null; - - /** - * An internal counter/pointer. - * @var integer $index - */ - var $index = null; - - /** - * The number of groups that have been found in the address list. - * @var integer $num_groups - * @access public - */ - var $num_groups = 0; - - /** - * A variable so that we can tell whether or not we're inside a - * Mail_RFC822 object. - * @var boolean $mailRFC822 - */ - var $mailRFC822 = true; - - /** - * A limit after which processing stops - * @var int $limit - */ - var $limit = null; - - - /** - * Sets up the object. The address must either be set here or when - * calling parseAddressList(). One or the other. - * - * @access public - * @param string $address The address(es) to validate. - * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. - * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. - * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. - * - * @return object Mail_RFC822 A new Mail_RFC822 object. - */ - function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) - { - if (isset($address)) $this->address = $address; - if (isset($default_domain)) $this->default_domain = $default_domain; - if (isset($nest_groups)) $this->nestGroups = $nest_groups; - if (isset($validate)) $this->validate = $validate; - if (isset($limit)) $this->limit = $limit; - } - - - /** - * Starts the whole process. The address must either be set here - * or when creating the object. One or the other. - * - * @access public - * @param string $address The address(es) to validate. - * @param string $default_domain Default domain/host etc. - * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. - * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. - * - * @return array A structured array of addresses. - */ - function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) - { - - if (!isset($this->mailRFC822)) { - $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); - return $obj->parseAddressList(); - } - - if (isset($address)) $this->address = $address; - if (isset($default_domain)) $this->default_domain = $default_domain; - if (isset($nest_groups)) $this->nestGroups = $nest_groups; - if (isset($validate)) $this->validate = $validate; - if (isset($limit)) $this->limit = $limit; - - $this->structure = array(); - $this->addresses = array(); - $this->error = null; - $this->index = null; - - while ($this->address = $this->_splitAddresses($this->address)) { - continue; - } - - if ($this->address === false || isset($this->error)) { - return false; - } - - // Reset timer since large amounts of addresses can take a long time to - // get here - set_time_limit(30); - - // Loop through all the addresses - for ($i = 0; $i < count($this->addresses); $i++){ - - if (($return = $this->_validateAddress($this->addresses[$i])) === false - || isset($this->error)) { - return false; - } - - if (!$this->nestGroups) { - $this->structure = array_merge($this->structure, $return); - } else { - $this->structure[] = $return; - } - } - - return $this->structure; - } - - /** - * Splits an address into seperate addresses. - * - * @access private - * @param string $address The addresses to split. - * @return boolean Success or failure. - */ - function _splitAddresses($address) - { - - if (!empty($this->limit) AND count($this->addresses) == $this->limit) { - return ''; - } - - if ($this->_isGroup($address) && !isset($this->error)) { - $split_char = ';'; - $is_group = true; - } elseif (!isset($this->error)) { - $split_char = ','; - $is_group = false; - } elseif (isset($this->error)) { - return false; - } - - // Split the string based on the above ten or so lines. - $parts = explode($split_char, $address); - $string = $this->_splitCheck($parts, $split_char); - - // If a group... - if ($is_group) { - // If $string does not contain a colon outside of - // brackets/quotes etc then something's fubar. - - // First check there's a colon at all: - if (strpos($string, ':') === false) { - $this->error = 'Invalid address: ' . $string; - return false; - } - - // Now check it's outside of brackets/quotes: - if (!$this->_splitCheck(explode(':', $string), ':')) - return false; - - // We must have a group at this point, so increase the counter: - $this->num_groups++; - } - - // $string now contains the first full address/group. - // Add to the addresses array. - $this->addresses[] = array( - 'address' => trim($string), - 'group' => $is_group - ); - - // Remove the now stored address from the initial line, the +1 - // is to account for the explode character. - $address = trim(substr($address, strlen($string) + 1)); - - // If the next char is a comma and this was a group, then - // there are more addresses, otherwise, if there are any more - // chars, then there is another address. - if ($is_group && substr($address, 0, 1) == ','){ - $address = trim(substr($address, 1)); - return $address; - - } elseif (strlen($address) > 0) { - return $address; - - } else { - return ''; - } - - // If you got here then something's off - return false; - } - - /** - * Checks for a group at the start of the string. - * - * @access private - * @param string $address The address to check. - * @return boolean Whether or not there is a group at the start of the string. - */ - function _isGroup($address) - { - // First comma not in quotes, angles or escaped: - $parts = explode(',', $address); - $string = $this->_splitCheck($parts, ','); - - // Now we have the first address, we can reliably check for a - // group by searching for a colon that's not escaped or in - // quotes or angle brackets. - if (count($parts = explode(':', $string)) > 1) { - $string2 = $this->_splitCheck($parts, ':'); - return ($string2 !== $string); - } else { - return false; - } - } - - /** - * A common function that will check an exploded string. - * - * @access private - * @param array $parts The exloded string. - * @param string $char The char that was exploded on. - * @return mixed False if the string contains unclosed quotes/brackets, or the string on success. - */ - function _splitCheck($parts, $char) - { - $string = $parts[0]; - - for ($i = 0; $i < count($parts); $i++) { - if ($this->_hasUnclosedQuotes($string) - || $this->_hasUnclosedBrackets($string, '<>') - || $this->_hasUnclosedBrackets($string, '[]') - || $this->_hasUnclosedBrackets($string, '()') - || substr($string, -1) == '\\') { - if (isset($parts[$i + 1])) { - $string = $string . $char . $parts[$i + 1]; - } else { - $this->error = 'Invalid address spec. Unclosed bracket or quotes'; - return false; - } - } else { - $this->index = $i; - break; - } - } - - return $string; - } - - /** - * Checks if a string has an unclosed quotes or not. - * - * @access private - * @param string $string The string to check. - * @return boolean True if there are unclosed quotes inside the string, false otherwise. - */ - function _hasUnclosedQuotes($string) - { - $string = explode('"', $string); - $string_cnt = count($string); - - for ($i = 0; $i < (count($string) - 1); $i++) - if (substr($string[$i], -1) == '\\') - $string_cnt--; - - return ($string_cnt % 2 === 0); - } - - /** - * Checks if a string has an unclosed brackets or not. IMPORTANT: - * This function handles both angle brackets and square brackets; - * - * @access private - * @param string $string The string to check. - * @param string $chars The characters to check for. - * @return boolean True if there are unclosed brackets inside the string, false otherwise. - */ - function _hasUnclosedBrackets($string, $chars) - { - $num_angle_start = substr_count($string, $chars[0]); - $num_angle_end = substr_count($string, $chars[1]); - - $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]); - $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]); - - if ($num_angle_start < $num_angle_end) { - $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')'; - return false; - } else { - return ($num_angle_start > $num_angle_end); - } - } - - /** - * Sub function that is used only by hasUnclosedBrackets(). - * - * @access private - * @param string $string The string to check. - * @param integer &$num The number of occurences. - * @param string $char The character to count. - * @return integer The number of occurences of $char in $string, adjusted for backslashes. - */ - function _hasUnclosedBracketsSub($string, &$num, $char) - { - $parts = explode($char, $string); - for ($i = 0; $i < count($parts); $i++){ - if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) - $num--; - if (isset($parts[$i + 1])) - $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1]; - } - - return $num; - } - - /** - * Function to begin checking the address. - * - * @access private - * @param string $address The address to validate. - * @return mixed False on failure, or a structured array of address information on success. - */ - function _validateAddress($address) - { - $is_group = false; - - if ($address['group']) { - $is_group = true; - - // Get the group part of the name - $parts = explode(':', $address['address']); - $groupname = $this->_splitCheck($parts, ':'); - $structure = array(); - - // And validate the group part of the name. - if (!$this->_validatePhrase($groupname)){ - $this->error = 'Group name did not validate.'; - return false; - } else { - // Don't include groups if we are not nesting - // them. This avoids returning invalid addresses. - if ($this->nestGroups) { - $structure = new stdClass; - $structure->groupname = $groupname; - } - } - - $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':'))); - } - - // If a group then split on comma and put into an array. - // Otherwise, Just put the whole address in an array. - if ($is_group) { - while (strlen($address['address']) > 0) { - $parts = explode(',', $address['address']); - $addresses[] = $this->_splitCheck($parts, ','); - $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ','))); - } - } else { - $addresses[] = $address['address']; - } - - // Check that $addresses is set, if address like this: - // Groupname:; - // Then errors were appearing. - if (!isset($addresses)){ - $this->error = 'Empty group.'; - return false; - } - - for ($i = 0; $i < count($addresses); $i++) { - $addresses[$i] = trim($addresses[$i]); - } - - // Validate each mailbox. - // Format could be one of: name - // geezer@domain.com - // geezer - // ... or any other format valid by RFC 822. - array_walk($addresses, array($this, 'validateMailbox')); - - // Nested format - if ($this->nestGroups) { - if ($is_group) { - $structure->addresses = $addresses; - } else { - $structure = $addresses[0]; - } - - // Flat format - } else { - if ($is_group) { - $structure = array_merge($structure, $addresses); - } else { - $structure = $addresses; - } - } - - return $structure; - } - - /** - * Function to validate a phrase. - * - * @access private - * @param string $phrase The phrase to check. - * @return boolean Success or failure. - */ - function _validatePhrase($phrase) - { - // Splits on one or more Tab or space. - $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); - - $phrase_parts = array(); - while (count($parts) > 0){ - $phrase_parts[] = $this->_splitCheck($parts, ' '); - for ($i = 0; $i < $this->index + 1; $i++) - array_shift($parts); - } - - for ($i = 0; $i < count($phrase_parts); $i++) { - // If quoted string: - if (substr($phrase_parts[$i], 0, 1) == '"') { - if (!$this->_validateQuotedString($phrase_parts[$i])) - return false; - continue; - } - - // Otherwise it's an atom: - if (!$this->_validateAtom($phrase_parts[$i])) return false; - } - - return true; - } - - /** - * Function to validate an atom which from rfc822 is: - * atom = 1* - * - * If validation ($this->validate) has been turned off, then - * validateAtom() doesn't actually check anything. This is so that you - * can split a list of addresses up before encoding personal names - * (umlauts, etc.), for example. - * - * @access private - * @param string $atom The string to check. - * @return boolean Success or failure. - */ - function _validateAtom($atom) - { - if (!$this->validate) { - // Validation has been turned off; assume the atom is okay. - return true; - } - - // Check for any char from ASCII 0 - ASCII 127 - if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) { - return false; - } - - // Check for specials: - if (preg_match('/[][()<>@,;\\:". ]/', $atom)) { - return false; - } - - // Check for control characters (ASCII 0-31): - if (preg_match('/[\\x00-\\x1F]+/', $atom)) { - return false; - } - - return true; - } - - /** - * Function to validate quoted string, which is: - * quoted-string = <"> *(qtext/quoted-pair) <"> - * - * @access private - * @param string $qstring The string to check - * @return boolean Success or failure. - */ - function _validateQuotedString($qstring) - { - // Leading and trailing " - $qstring = substr($qstring, 1, -1); - - // Perform check. - return !(preg_match('/(.)[\x0D\\\\"]/', $qstring, $matches) && $matches[1] != '\\'); - } - - /** - * Function to validate a mailbox, which is: - * mailbox = addr-spec ; simple address - * / phrase route-addr ; name and route-addr - * - * @access public - * @param string &$mailbox The string to check. - * @return boolean Success or failure. - */ - function validateMailbox(&$mailbox) - { - // A couple of defaults. - $phrase = ''; - $comment = ''; - - // Catch any RFC822 comments and store them separately - $_mailbox = $mailbox; - while (strlen(trim($_mailbox)) > 0) { - $parts = explode('(', $_mailbox); - $before_comment = $this->_splitCheck($parts, '('); - if ($before_comment != $_mailbox) { - // First char should be a ( - $comment = substr(str_replace($before_comment, '', $_mailbox), 1); - $parts = explode(')', $comment); - $comment = $this->_splitCheck($parts, ')'); - $comments[] = $comment; - - // +1 is for the trailing ) - $_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1); - } else { - break; - } - } - - for($i=0; $i' && substr($mailbox, 0, 1) != '<') { - $parts = explode('<', $mailbox); - $name = $this->_splitCheck($parts, '<'); - - $phrase = trim($name); - $route_addr = trim(substr($mailbox, strlen($name.'<'), -1)); - - if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) - return false; - - // Only got addr-spec - } else { - // First snip angle brackets if present. - if (substr($mailbox,0,1) == '<' && substr($mailbox,-1) == '>') - $addr_spec = substr($mailbox,1,-1); - else - $addr_spec = $mailbox; - - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) - return false; - } - - // Construct the object that will be returned. - $mbox = new stdClass(); - - // Add the phrase (even if empty) and comments - $mbox->personal = $phrase; - $mbox->comment = isset($comments) ? $comments : array(); - - if (isset($route_addr)) { - $mbox->mailbox = $route_addr['local_part']; - $mbox->host = $route_addr['domain']; - $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : ''; - } else { - $mbox->mailbox = $addr_spec['local_part']; - $mbox->host = $addr_spec['domain']; - } - - $mailbox = $mbox; - return true; - } - - /** - * This function validates a route-addr which is: - * route-addr = "<" [route] addr-spec ">" - * - * Angle brackets have already been removed at the point of - * getting to this function. - * - * @access private - * @param string $route_addr The string to check. - * @return mixed False on failure, or an array containing validated address/route information on success. - */ - function _validateRouteAddr($route_addr) - { - // Check for colon. - if (strpos($route_addr, ':') !== false) { - $parts = explode(':', $route_addr); - $route = $this->_splitCheck($parts, ':'); - } else { - $route = $route_addr; - } - - // If $route is same as $route_addr then the colon was in - // quotes or brackets or, of course, non existent. - if ($route === $route_addr){ - unset($route); - $addr_spec = $route_addr; - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { - return false; - } - } else { - // Validate route part. - if (($route = $this->_validateRoute($route)) === false) { - return false; - } - - $addr_spec = substr($route_addr, strlen($route . ':')); - - // Validate addr-spec part. - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { - return false; - } - } - - if (isset($route)) { - $return['adl'] = $route; - } else { - $return['adl'] = ''; - } - - $return = array_merge($return, $addr_spec); - return $return; - } - - /** - * Function to validate a route, which is: - * route = 1#("@" domain) ":" - * - * @access private - * @param string $route The string to check. - * @return mixed False on failure, or the validated $route on success. - */ - function _validateRoute($route) - { - // Split on comma. - $domains = explode(',', trim($route)); - - for ($i = 0; $i < count($domains); $i++) { - $domains[$i] = str_replace('@', '', trim($domains[$i])); - if (!$this->_validateDomain($domains[$i])) return false; - } - - return $route; - } - - /** - * Function to validate a domain, though this is not quite what - * you expect of a strict internet domain. - * - * domain = sub-domain *("." sub-domain) - * - * @access private - * @param string $domain The string to check. - * @return mixed False on failure, or the validated domain on success. - */ - function _validateDomain($domain) - { - // Note the different use of $subdomains and $sub_domains - $subdomains = explode('.', $domain); - - while (count($subdomains) > 0) { - $sub_domains[] = $this->_splitCheck($subdomains, '.'); - for ($i = 0; $i < $this->index + 1; $i++) - array_shift($subdomains); - } - - for ($i = 0; $i < count($sub_domains); $i++) { - if (!$this->_validateSubdomain(trim($sub_domains[$i]))) - return false; - } - - // Managed to get here, so return input. - return $domain; - } - - /** - * Function to validate a subdomain: - * subdomain = domain-ref / domain-literal - * - * @access private - * @param string $subdomain The string to check. - * @return boolean Success or failure. - */ - function _validateSubdomain($subdomain) - { - if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){ - if (!$this->_validateDliteral($arr[1])) return false; - } else { - if (!$this->_validateAtom($subdomain)) return false; - } - - // Got here, so return successful. - return true; - } - - /** - * Function to validate a domain literal: - * domain-literal = "[" *(dtext / quoted-pair) "]" - * - * @access private - * @param string $dliteral The string to check. - * @return boolean Success or failure. - */ - function _validateDliteral($dliteral) - { - return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\'; - } - - /** - * Function to validate an addr-spec. - * - * addr-spec = local-part "@" domain - * - * @access private - * @param string $addr_spec The string to check. - * @return mixed False on failure, or the validated addr-spec on success. - */ - function _validateAddrSpec($addr_spec) - { - $addr_spec = trim($addr_spec); - - // Split on @ sign if there is one. - if (strpos($addr_spec, '@') !== false) { - $parts = explode('@', $addr_spec); - $local_part = $this->_splitCheck($parts, '@'); - $domain = substr($addr_spec, strlen($local_part . '@')); - - // No @ sign so assume the default domain. - } else { - $local_part = $addr_spec; - $domain = $this->default_domain; - } - - if (($local_part = $this->_validateLocalPart($local_part)) === false) return false; - if (($domain = $this->_validateDomain($domain)) === false) return false; - - // Got here so return successful. - return array('local_part' => $local_part, 'domain' => $domain); - } - - /** - * Function to validate the local part of an address: - * local-part = word *("." word) - * - * @access private - * @param string $local_part - * @return mixed False on failure, or the validated local part on success. - */ - function _validateLocalPart($local_part) - { - $parts = explode('.', $local_part); - - // Split the local_part into words. - while (count($parts) > 0){ - $words[] = $this->_splitCheck($parts, '.'); - for ($i = 0; $i < $this->index + 1; $i++) { - array_shift($parts); - } - } - - // Validate each word. - for ($i = 0; $i < count($words); $i++) { - if ($this->_validatePhrase(trim($words[$i])) === false) return false; - } - - // Managed to get here, so return the input. - return $local_part; - } - - /** - * Returns an approximate count of how many addresses are - * in the given string. This is APPROXIMATE as it only splits - * based on a comma which has no preceding backslash. Could be - * useful as large amounts of addresses will end up producing - * *large* structures when used with parseAddressList(). - * - * @param string $data Addresses to count - * @return int Approximate count - */ - function approximateCount($data) - { - return count(preg_split('/(?@. This can be - * sufficient for most people. Optional stricter mode can - * be utilised which restricts mailbox characters allowed - * to alphanumeric, full stop, hyphen and underscore. - * - * @param string $data Address to check - * @param boolean $strict Optional stricter mode - * @return mixed False if it fails, an indexed array - * username/domain if it matches - */ - function isValidInetAddress($data, $strict = false) - { - $regex = $strict ? '/^([.0-9a-z_-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i'; - if (preg_match($regex, trim($data), $matches)) { - return array($matches[1], $matches[2]); - } else { - return false; - } - } -} - -?> diff --git a/function/mimePart.php b/function/mimePart.php deleted file mode 100644 index 120df42..0000000 --- a/function/mimePart.php +++ /dev/null @@ -1,333 +0,0 @@ - | -// +----------------------------------------------------------------------+ - -/** -* -* Raw mime encoding class -* -* What is it? -* This class enables you to manipulate and build -* a mime email from the ground up. -* -* Why use this instead of mime.php? -* mime.php is a userfriendly api to this class for -* people who aren't interested in the internals of -* mime mail. This class however allows full control -* over the email. -* -* Eg. -* -* // Since multipart/mixed has no real body, (the body is -* // the subpart), we set the body argument to blank. -* -* $params['content_type'] = 'multipart/mixed'; -* $email = new Mail_mimePart('', $params); -* -* // Here we add a text part to the multipart we have -* // already. Assume $body contains plain text. -* -* $params['content_type'] = 'text/plain'; -* $params['encoding'] = '7bit'; -* $text = $email->addSubPart($body, $params); -* -* // Now add an attachment. Assume $attach is -* the contents of the attachment -* -* $params['content_type'] = 'application/zip'; -* $params['encoding'] = 'base64'; -* $params['disposition'] = 'attachment'; -* $params['dfilename'] = 'example.zip'; -* $attach =& $email->addSubPart($body, $params); -* -* // Now build the email. Note that the encode -* // function returns an associative array containing two -* // elements, body and headers. You will need to add extra -* // headers, (eg. Mime-Version) before sending. -* -* $email = $message->encode(); -* $email['headers'][] = 'Mime-Version: 1.0'; -* -* -* Further examples are available at http://www.phpguru.org -* -* TODO: -* - Set encode() to return the $obj->encoded if encode() -* has already been run. Unless a flag is passed to specifically -* re-build the message. -* -* @author Richard Heyes -* @version $Revision: 1.3 $ -* @package Mail -*/ - -class Mail_mimePart { - - /** - * The encoding type of this part - * @var string - */ - var $_encoding; - - /** - * An array of subparts - * @var array - */ - var $_subparts; - - /** - * The output of this part after being built - * @var string - */ - var $_encoded; - - /** - * Headers for this part - * @var array - */ - var $_headers; - - /** - * The body of this part (not encoded) - * @var string - */ - var $_body; - - /** - * Constructor. - * - * Sets up the object. - * - * @param $body - The body of the mime part if any. - * @param $params - An associative array of parameters: - * content_type - The content type for this part eg multipart/mixed - * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable - * cid - Content ID to apply - * disposition - Content disposition, inline or attachment - * dfilename - Optional filename parameter for content disposition - * description - Content description - * charset - Character set to use - * @access public - */ - function __construct($body = '', $params = array()) - { - if (!defined('MAIL_MIMEPART_CRLF')) { - define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); - } - - foreach ($params as $key => $value) { - switch ($key) { - case 'content_type': - $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); - break; - - case 'encoding': - $this->_encoding = $value; - $headers['Content-Transfer-Encoding'] = $value; - break; - - case 'cid': - $headers['Content-ID'] = '<' . $value . '>'; - break; - - case 'disposition': - $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); - break; - - case 'dfilename': - if (isset($headers['Content-Disposition'])) { - $headers['Content-Disposition'] .= '; filename="' . $value . '"'; - } else { - $dfilename = $value; - } - break; - - case 'description': - $headers['Content-Description'] = $value; - break; - - case 'charset': - if (isset($headers['Content-Type'])) { - $headers['Content-Type'] .= '; charset="' . $value . '"'; - } else { - $charset = $value; - } - break; - } - } - - // Default content-type - if (!isset($headers['Content-Type'])) { - $headers['Content-Type'] = 'text/plain'; - } - - //Default encoding - if (!isset($this->_encoding)) { - $this->_encoding = '7bit'; - } - - // Assign stuff to member variables - $this->_encoded = array(); - $this->_headers = $headers; - $this->_body = $body; - } - - /** - * encode() - * - * Encodes and returns the email. Also stores - * it in the encoded member variable - * - * @return An associative array containing two elements, - * body and headers. The headers element is itself - * an indexed array. - * @access public - */ - function encode() - { - $encoded =& $this->_encoded; - - if (!empty($this->_subparts)) { - srand((double)microtime()*1000000); - $boundary = '=_' . md5(uniqid(rand()) . microtime()); - $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; - - // Add body parts to $subparts - for ($i = 0; $i < count($this->_subparts); $i++) { - $headers = array(); - $tmp = $this->_subparts[$i]->encode(); - foreach ($tmp['headers'] as $key => $value) { - $headers[] = $key . ': ' . $value; - } - $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; - } - - $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . - implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . - '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; - - } else { - $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; - } - - // Add headers to $encoded - $encoded['headers'] =& $this->_headers; - - return $encoded; - } - - /** - * &addSubPart() - * - * Adds a subpart to current mime part and returns - * a reference to it - * - * @param $body The body of the subpart, if any. - * @param $params The parameters for the subpart, same - * as the $params argument for constructor. - * @return A reference to the part you just added. It is - * crucial if using multipart/* in your subparts that - * you use =& in your script when calling this function, - * otherwise you will not be able to add further subparts. - * @access public - */ - function &addSubPart($body, $params) - { - $this->_subparts[] = new Mail_mimePart($body, $params); - return $this->_subparts[count($this->_subparts) - 1]; - } - - /** - * _getEncodedData() - * - * Returns encoded data based upon encoding passed to it - * - * @param $data The data to encode. - * @param $encoding The encoding type to use, 7bit, base64, - * or quoted-printable. - * @access private - */ - function _getEncodedData($data, $encoding) - { - switch ($encoding) { - case '8bit': - case '7bit': - return $data; - break; - - case 'quoted-printable': - return $this->_quotedPrintableEncode($data); - break; - - case 'base64': - return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); - break; - - default: - return $data; - } - } - - /** - * quoteadPrintableEncode() - * - * Encodes data to quoted-printable standard. - * - * @param $input The data to encode - * @param $line_max Optional max line length. Should - * not be more than 76 chars - * - * @access private - */ - function _quotedPrintableEncode($input , $line_max = 76) - { - $lines = preg_split("/\r?\n/", $input); - $eol = MAIL_MIMEPART_CRLF; - $escape = '='; - $output = ''; - - while(list(, $line) = each($lines)){ - - $linlen = strlen($line); - $newline = ''; - - for ($i = 0; $i < $linlen; $i++) { - $char = substr($line, $i, 1); - $dec = ord($char); - - if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only - $char = '=20'; - - } elseif($dec == 9) { - ; // Do nothing if a tab. - } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { - $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); - } - - if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted - $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay - $newline = ''; - } - $newline .= $char; - } // end of for - $output .= $newline . $eol; - } - $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf - return $output; - } -} // End of class -?> diff --git a/function/smtp.php b/function/smtp.php deleted file mode 100644 index 1d420b0..0000000 --- a/function/smtp.php +++ /dev/null @@ -1,361 +0,0 @@ - - * pass - Password for authentication Default: - * timeout - The timeout in seconds for the call Default: 5 - * to fsockopen() - */ - - function __construct($params = array()){ - - if(!defined('CRLF')) - define('CRLF', "\r\n", TRUE); - - $this->authenticated = FALSE; - $this->timeout = 5; - $this->status = SMTP_STATUS_NOT_CONNECTED; - $this->host = 'localhost'; - $this->port = 25; - $this->helo = 'localhost'; - $this->auth = FALSE; - $this->user = ''; - $this->pass = ''; - $this->errors = array(); - - foreach($params as $key => $value){ - $this->$key = $value; - } - } - - /** - * Connect function. This will, when called - * statically, create a new smtp object, - * call the connect function (ie this function) - * and return it. When not called statically, - * it will connect to the server and send - * the HELO command. - */ - - function &connect($params = array()){ - - if(!isset($this->status)){ - $obj = new smtp($params); - if($obj->connect()){ - $obj->status = SMTP_STATUS_CONNECTED; - } - - return $obj; - - }else{ - $this->connection = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); - if(function_exists('socket_set_timeout')){ - @socket_set_timeout($this->connection, 5, 0); - } - - $greeting = $this->get_data(); - if(is_resource($this->connection)){ - $this->status = SMTP_STATUS_CONNECTED; - - return $this->auth ? $this->ehlo() : $this->helo(); - }else{ - $this->errors[] = 'Failed to connect to server: '.$errstr; - return FALSE; - } - } - } - - /** - * Function which handles sending the mail. - * Arguments: - * $params - Optional assoc array of parameters. - * Can contain: - * recipients - Indexed array of recipients - * from - The from address. (used in MAIL FROM:), - * this will be the return path - * headers - Indexed array of headers, one header per array entry - * body - The body of the email - * It can also contain any of the parameters from the connect() - * function - */ - - function send($params = array()){ - - foreach($params as $key => $value){ - $this->set($key, $value); - } - - if($this->is_connected()){ - - // Do we auth or not? Note the distinction between the auth variable and auth() function - if($this->auth AND !$this->authenticated){ - if(!$this->auth()) - return FALSE; - } - - $this->mail($this->from); - if(is_array($this->recipients)) - foreach($this->recipients as $value) - $this->rcpt($value); - else - $this->rcpt($this->recipients); - - if(!$this->data()) - return FALSE; - - // Transparency - $headers = str_replace(CRLF.'.', CRLF.'..', trim(implode(CRLF, $this->headers))); - $body = str_replace(CRLF.'.', CRLF.'..', $this->body); - $body = $body[0] == '.' ? '.'.$body : $body; - - $this->send_data($headers); - $this->send_data(''); - $this->send_data($body); - $this->send_data('.'); - - $result = (substr(trim($this->get_data()), 0, 3) === '250'); - //$this->rset(); - return $result; - }else{ - $this->errors[] = 'Not connected!'; - return FALSE; - } - } - - /** - * Function to implement HELO cmd - */ - - function helo(){ - if(is_resource($this->connection) - AND $this->send_data('HELO '.$this->helo) - AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){ - - return TRUE; - - }else{ - $this->errors[] = 'HELO command failed, output: ' . trim(substr(trim($error),3)); - return FALSE; - } - } - - /** - * Function to implement EHLO cmd - */ - - function ehlo(){ - if(is_resource($this->connection) - AND $this->send_data('EHLO '.$this->helo) - AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){ - - return TRUE; - - }else{ - $this->errors[] = 'EHLO command failed, output: ' . trim(substr(trim($error),3)); - return FALSE; - } - } - - /** - * Function to implement RSET cmd - */ - - function rset(){ - if(is_resource($this->connection) - AND $this->send_data('RSET') - AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){ - - return TRUE; - - }else{ - $this->errors[] = 'RSET command failed, output: ' . trim(substr(trim($error),3)); - return FALSE; - } - } - - /** - * Function to implement QUIT cmd - */ - - function quit(){ - if(is_resource($this->connection) - AND $this->send_data('QUIT') - AND substr(trim($error = $this->get_data()), 0, 3) === '221' ){ - - fclose($this->connection); - $this->status = SMTP_STATUS_NOT_CONNECTED; - return TRUE; - - }else{ - $this->errors[] = 'QUIT command failed, output: ' . trim(substr(trim($error),3)); - return FALSE; - } - } - - /** - * Function to implement AUTH cmd - */ - - function auth(){ - if(is_resource($this->connection) - AND $this->send_data('AUTH LOGIN') - AND substr(trim($error = $this->get_data()), 0, 3) === '334' - AND $this->send_data(base64_encode($this->user)) // Send username - AND substr(trim($error = $this->get_data()),0,3) === '334' - AND $this->send_data(base64_encode($this->pass)) // Send password - AND substr(trim($error = $this->get_data()),0,3) === '235' ){ - - $this->authenticated = TRUE; - return TRUE; - - }else{ - $this->errors[] = 'AUTH command failed: ' . trim(substr(trim($error),3)); - return FALSE; - } - } - - /** - * Function that handles the MAIL FROM: cmd - */ - - function mail($from){ - - if($this->is_connected() - AND $this->send_data('MAIL FROM:<'.$from.'>') - AND substr(trim($this->get_data()), 0, 2) === '250' ){ - - return TRUE; - - }else - return FALSE; - } - - /** - * Function that handles the RCPT TO: cmd - */ - - function rcpt($to){ - - if($this->is_connected() - AND $this->send_data('RCPT TO:<'.$to.'>') - AND substr(trim($error = $this->get_data()), 0, 2) === '25' ){ - - return TRUE; - - }else{ - $this->errors[] = trim(substr(trim($error), 3)); - return FALSE; - } - } - - /** - * Function that sends the DATA cmd - */ - - function data(){ - - if($this->is_connected() - AND $this->send_data('DATA') - AND substr(trim($error = $this->get_data()), 0, 3) === '354' ){ - - return TRUE; - - }else{ - $this->errors[] = trim(substr(trim($error), 3)); - return FALSE; - } - } - - /** - * Function to determine if this object - * is connected to the server or not. - */ - - function is_connected(){ - - return (is_resource($this->connection) AND ($this->status === SMTP_STATUS_CONNECTED)); - } - - /** - * Function to send a bit of data - */ - - function send_data($data){ - - if(is_resource($this->connection)){ - return fwrite($this->connection, $data.CRLF, strlen($data)+2); - - }else - return FALSE; - } - - /** - * Function to get data. - */ - - function &get_data(){ - - $return = ''; - $line = ''; - $loops = 0; - - if(is_resource($this->connection)){ - while((strpos($return, CRLF) === FALSE OR substr($line,3,1) !== ' ') AND $loops < 100){ - $line = fgets($this->connection, 512); - $return .= $line; - $loops++; - } - return $return; - - }else - return FALSE; - } - - /** - * Sets a variable - */ - - function set($var, $value){ - - $this->$var = $value; - return TRUE; - } - - } // End of class -?> \ No newline at end of file diff --git a/function/thumb.php b/function/thumb.php deleted file mode 100644 index 8eb6bb8..0000000 --- a/function/thumb.php +++ /dev/null @@ -1,1244 +0,0 @@ - /dev/null 2>&1 & - Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated. - You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable) - You will also need to take responsibility for server security if you're running Xvfb as root. - - -*/ -if(! defined('WEBSHOT_ENABLED') ) define ('WEBSHOT_ENABLED', false); //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image. -if(! defined('WEBSHOT_CUTYCAPT') ) define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt. -if(! defined('WEBSHOT_XVFB') ) define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run'); //The path to the Xvfb server -if(! defined('WEBSHOT_SCREEN_X') ) define ('WEBSHOT_SCREEN_X', '1024'); //1024 works ok -if(! defined('WEBSHOT_SCREEN_Y') ) define ('WEBSHOT_SCREEN_Y', '768'); //768 works ok -if(! defined('WEBSHOT_COLOR_DEPTH') ) define ('WEBSHOT_COLOR_DEPTH', '24'); //I haven't tested anything besides 24 -if(! defined('WEBSHOT_IMAGE_FORMAT') ) define ('WEBSHOT_IMAGE_FORMAT', 'png'); //png is about 2.5 times the size of jpg but is a LOT better quality -if(! defined('WEBSHOT_TIMEOUT') ) define ('WEBSHOT_TIMEOUT', '20'); //Seconds to wait for a webshot -if(! defined('WEBSHOT_USER_AGENT') ) define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox -if(! defined('WEBSHOT_JAVASCRIPT_ON') ) define ('WEBSHOT_JAVASCRIPT_ON', true); //Setting to false might give you a slight speedup and block ads. But it could cause other issues. -if(! defined('WEBSHOT_JAVA_ON') ) define ('WEBSHOT_JAVA_ON', false); //Have only tested this as fase -if(! defined('WEBSHOT_PLUGINS_ON') ) define ('WEBSHOT_PLUGINS_ON', true); //Enable flash and other plugins -if(! defined('WEBSHOT_PROXY') ) define ('WEBSHOT_PROXY', ''); //In case you're behind a proxy server. -if(! defined('WEBSHOT_XVFB_RUNNING') ) define ('WEBSHOT_XVFB_RUNNING', false); //ADVANCED: Enable this if you've got Xvfb running in the background. - - -// If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains. -if(! isset($ALLOWED_SITES)){ - $ALLOWED_SITES = array ( - 'flickr.com', - 'staticflickr.com', - 'picasa.com', - 'img.youtube.com', - 'upload.wikimedia.org', - 'photobucket.com', - 'imgur.com', - 'imageshack.us', - 'tinypic.com', - ); -} -// ------------------------------------------------------------- -// -------------- STOP EDITING CONFIGURATION HERE -------------- -// ------------------------------------------------------------- - -timthumb::start(); - -class timthumb { - protected $src = ""; - protected $is404 = false; - protected $docRoot = ""; - protected $lastURLError = false; - protected $localImage = ""; - protected $localImageMTime = 0; - protected $url = false; - protected $myHost = ""; - protected $isURL = false; - protected $cachefile = ''; - protected $errors = array(); - protected $toDeletes = array(); - protected $cacheDirectory = ''; - protected $startTime = 0; - protected $lastBenchTime = 0; - protected $cropTop = false; - protected $salt = ""; - protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen. - protected $filePrependSecurityBlock = "handleErrors(); - $tim->securityChecks(); - if($tim->tryBrowserCache()){ - exit(0); - } - $tim->handleErrors(); - if(FILE_CACHE_ENABLED && $tim->tryServerCache()){ - exit(0); - } - $tim->handleErrors(); - $tim->run(); - $tim->handleErrors(); - exit(0); - } - public function __construct(){ - global $ALLOWED_SITES; - $this->startTime = microtime(true); - date_default_timezone_set('UTC'); - $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']); - $this->calcDocRoot(); - //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this. - $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__); - $this->debug(3, "Salt is: " . $this->salt); - if(FILE_CACHE_DIRECTORY){ - if(! is_dir(FILE_CACHE_DIRECTORY)){ - @mkdir(FILE_CACHE_DIRECTORY); - if(! is_dir(FILE_CACHE_DIRECTORY)){ - $this->error("Could not create the file cache directory."); - return false; - } - } - $this->cacheDirectory = FILE_CACHE_DIRECTORY; - if (!touch($this->cacheDirectory . '/index.html')) { - $this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory."); - } - } else { - $this->cacheDirectory = sys_get_temp_dir(); - } - //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image. - $this->cleanCache(); - - $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']); - $this->src = $this->param('src'); - $this->url = parse_url($this->src); - $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src); - - if(strlen($this->src) <= 3){ - $this->error("No image specified"); - return false; - } - if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){ - // base64 encoded red image that says 'no hotlinkers' - // nothing to worry about! :) - $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs="); - header('Content-Type: image/gif'); - header('Content-Length: ' . sizeof($imgData)); - header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); - header("Pragma: no-cache"); - header('Expires: ' . gmdate ('D, d M Y H:i:s', time())); - echo $imgData; - return false; - exit(0); - } - if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){ - $this->debug(2, "Is a request for an external URL: " . $this->src); - $this->isURL = true; - } else { - $this->debug(2, "Is a request for an internal file: " . $this->src); - } - if($this->isURL && (! ALLOW_EXTERNAL)){ - $this->error("You are not allowed to fetch images from an external website."); - return false; - } - if($this->isURL){ - if(ALLOW_ALL_EXTERNAL_SITES){ - $this->debug(2, "Fetching from all external sites is enabled."); - } else { - $this->debug(2, "Fetching only from selected external sites is enabled."); - $allowed = false; - foreach($ALLOWED_SITES as $site){ - if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) { - $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing."); - $allowed = true; - } - } - if(! $allowed){ - return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs."); - } - } - } - - $cachePrefix = ($this->isURL ? '_ext_' : '_int_'); - if($this->isURL){ - $arr = explode('&', $_SERVER ['QUERY_STRING']); - asort($arr); - $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX; - } else { - $this->localImage = $this->getLocalImagePath($this->src); - if(! $this->localImage){ - $this->debug(1, "Could not find the local image: {$this->localImage}"); - $this->error("Could not find the internal image you specified."); - $this->set404(); - return false; - } - $this->debug(1, "Local image path is {$this->localImage}"); - $this->localImageMTime = @filemtime($this->localImage); - //We include the mtime of the local file in case in changes on disk. - $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX; - } - $this->debug(2, "Cache file is: " . $this->cachefile); - - return true; - } - public function __destruct(){ - foreach($this->toDeletes as $del){ - $this->debug(2, "Deleting temp file $del"); - @unlink($del); - } - } - public function run(){ - if($this->isURL){ - if(! ALLOW_EXTERNAL){ - $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg."); - $this->error("You are not allowed to fetch images from an external website."); - return false; - } - $this->debug(3, "Got request for external image. Starting serveExternalImage."); - if($this->param('webshot')){ - if(WEBSHOT_ENABLED){ - $this->debug(3, "webshot param is set, so we're going to take a webshot."); - $this->serveWebshot(); - } else { - $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots."); - } - } else { - $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image."); - $this->serveExternalImage(); - - } - } else { - $this->debug(3, "Got request for internal image. Starting serveInternalImage()"); - $this->serveInternalImage(); - } - return true; - } - protected function handleErrors(){ - if($this->haveErrors()){ - if(NOT_FOUND_IMAGE && $this->is404()){ - if($this->serveImg(NOT_FOUND_IMAGE)){ - exit(0); - } else { - $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it."); - } - } - if(ERROR_IMAGE){ - if($this->serveImg(ERROR_IMAGE)){ - exit(0); - } else { - $this->error("Additionally, the error image that is configured could not be found or there was an error serving it."); - } - } - $this->serveErrors(); - exit(0); - } - return false; - } - protected function tryBrowserCache(){ - if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; } - if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){ - $this->debug(3, "Got a conditional get"); - $mtime = false; - //We've already checked if the real file exists in the constructor - if(! is_file($this->cachefile)){ - //If we don't have something cached, regenerate the cached image. - return false; - } - if($this->localImageMTime){ - $mtime = $this->localImageMTime; - $this->debug(3, "Local real file's modification time is $mtime"); - } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304 - $mtime = @filemtime($this->cachefile); - $this->debug(3, "Cached file's modification time is $mtime"); - } - if(! $mtime){ return false; } - - $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); - $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime"); - if($iftime < 1){ - $this->debug(3, "Got an invalid conditional get modified since time. Returning false."); - return false; - } - if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch. - $this->debug(3, "File has been modified since last fetch."); - return false; - } else { //Otherwise serve a 304 - $this->debug(3, "File has not been modified since last get, so serving a 304."); - header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); - $this->debug(1, "Returning 304 not modified"); - return true; - } - } - return false; - } - protected function tryServerCache(){ - $this->debug(3, "Trying server cache"); - if(file_exists($this->cachefile)){ - $this->debug(3, "Cachefile {$this->cachefile} exists"); - if($this->isURL){ - $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously."); - if(filesize($this->cachefile) < 1){ - $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is."); - //Fetching error occured previously - if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){ - $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file."); - @unlink($this->cachefile); - return false; //to indicate we didn't serve from cache and app should try and load - } else { - $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host."); - $this->set404(); - $this->error("An error occured fetching image."); - return false; - } - } - } else { - $this->debug(3, "Trying to serve cachefile {$this->cachefile}"); - } - if($this->serveCacheFile()){ - $this->debug(3, "Succesfully served cachefile {$this->cachefile}"); - return true; - } else { - $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache."); - //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it - @unlink($this->cachefile); - return true; - } - } - } - protected function error($err){ - $this->debug(3, "Adding error message: $err"); - $this->errors[] = $err; - return false; - - } - protected function haveErrors(){ - if(sizeof($this->errors) > 0){ - return true; - } - return false; - } - protected function serveErrors(){ - header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request'); - $html = '
    '; - foreach($this->errors as $err){ - $html .= '
  • ' . htmlentities($err) . '
  • '; - } - $html .= '
'; - echo '

A TimThumb error has occured

The following error(s) occured:
' . $html . '
'; - echo '
Query String : ' . htmlentities ($_SERVER['QUERY_STRING']); - echo '
TimThumb version : ' . VERSION . ''; - } - protected function serveInternalImage(){ - $this->debug(3, "Local image path is $this->localImage"); - if(! $this->localImage){ - $this->sanityFail("localImage not set after verifying it earlier in the code."); - return false; - } - $fileSize = filesize($this->localImage); - if($fileSize > MAX_FILE_SIZE){ - $this->error("The file you specified is greater than the maximum allowed file size."); - return false; - } - if($fileSize <= 0){ - $this->error("The file you specified is <= 0 bytes."); - return false; - } - $this->debug(3, "Calling processImageAndWriteToCache() for local image."); - if($this->processImageAndWriteToCache($this->localImage)){ - $this->serveCacheFile(); - return true; - } else { - return false; - } - } - protected function cleanCache(){ - if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) { - return; - } - $this->debug(3, "cleanCache() called"); - $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch'; - - //If this is a new timthumb installation we need to create the file - if(! is_file($lastCleanFile)){ - $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile"); - if (!touch($lastCleanFile)) { - $this->error("Could not create cache clean timestamp file."); - } - return; - } - if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago - $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now."); - // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day. - if (!touch($lastCleanFile)) { - $this->error("Could not create cache clean timestamp file."); - } - $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX); - if ($files) { - $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE; - foreach($files as $file){ - if(@filemtime($file) < $timeAgo){ - $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds"); - @unlink($file); - } - } - } - return true; - } else { - $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed."); - } - return false; - } - protected function processImageAndWriteToCache($localImage){ - $sData = getimagesize($localImage); - $origType = $sData[2]; - $mimeType = $sData['mime']; - - $this->debug(3, "Mime type of image is $mimeType"); - if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){ - return $this->error("The image being resized is not a valid gif, jpg or png."); - } - - if (!function_exists ('imagecreatetruecolor')) { - return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library'); - } - - if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) { - $imageFilters = array ( - 1 => array (IMG_FILTER_NEGATE, 0), - 2 => array (IMG_FILTER_GRAYSCALE, 0), - 3 => array (IMG_FILTER_BRIGHTNESS, 1), - 4 => array (IMG_FILTER_CONTRAST, 1), - 5 => array (IMG_FILTER_COLORIZE, 4), - 6 => array (IMG_FILTER_EDGEDETECT, 0), - 7 => array (IMG_FILTER_EMBOSS, 0), - 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0), - 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0), - 10 => array (IMG_FILTER_MEAN_REMOVAL, 0), - 11 => array (IMG_FILTER_SMOOTH, 0), - ); - } - - // get standard input properties - $new_width = (int) abs ($this->param('w', 0)); - $new_height = (int) abs ($this->param('h', 0)); - $zoom_crop = (int) $this->param('zc', DEFAULT_ZC); - $quality = (int) abs ($this->param('q', DEFAULT_Q)); - $align = $this->cropTop ? 't' : $this->param('a', 'c'); - $filters = $this->param('f', DEFAULT_F); - $sharpen = (bool) $this->param('s', DEFAULT_S); - $canvas_color = $this->param('cc', DEFAULT_CC); - $canvas_trans = (bool) $this->param('ct', '1'); - - // set default width and height if neither are set already - if ($new_width == 0 && $new_height == 0) { - $new_width = 100; - $new_height = 100; - } - - // ensure size limits can not be abused - $new_width = min ($new_width, MAX_WIDTH); - $new_height = min ($new_height, MAX_HEIGHT); - - // set memory limit to be able to have enough space to resize larger images - $this->setMemoryLimit(); - - // open the existing image - $image = $this->openImage ($mimeType, $localImage); - if ($image === false) { - return $this->error('Unable to open image.'); - } - - // Get original width and height - $width = imagesx ($image); - $height = imagesy ($image); - $origin_x = 0; - $origin_y = 0; - - // generate new w/h if not provided - if ($new_width && !$new_height) { - $new_height = floor ($height * ($new_width / $width)); - } else if ($new_height && !$new_width) { - $new_width = floor ($width * ($new_height / $height)); - } - - // scale down and add borders - if ($zoom_crop == 3) { - - $final_height = $height * ($new_width / $width); - - if ($final_height > $new_height) { - $new_width = $width * ($new_height / $height); - } else { - $new_height = $final_height; - } - - } - - // create a new true color image - $canvas = imagecreatetruecolor ($new_width, $new_height); - imagealphablending ($canvas, false); - - if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation - $canvas_color = str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2); - } else if (strlen($canvas_color) != 6) { - $canvas_color = DEFAULT_CC; // on error return default canvas color - } - - $canvas_color_R = hexdec (substr ($canvas_color, 0, 2)); - $canvas_color_G = hexdec (substr ($canvas_color, 2, 2)); - $canvas_color_B = hexdec (substr ($canvas_color, 4, 2)); - - // Create a new transparent color for image - // If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency - // (and if is set a canvas color show it in the background) - if(preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans){ - $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127); - }else{ - $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0); - } - - - // Completely fill the background of the new image with allocated color. - imagefill ($canvas, 0, 0, $color); - - // scale down and add borders - if ($zoom_crop == 2) { - - $final_height = $height * ($new_width / $width); - - if ($final_height > $new_height) { - - $origin_x = $new_width / 2; - $new_width = $width * ($new_height / $height); - $origin_x = round ($origin_x - ($new_width / 2)); - - } else { - - $origin_y = $new_height / 2; - $new_height = $final_height; - $origin_y = round ($origin_y - ($new_height / 2)); - - } - - } - - // Restore transparency blending - imagesavealpha ($canvas, true); - - if ($zoom_crop > 0) { - - $src_x = $src_y = 0; - $src_w = $width; - $src_h = $height; - - $cmp_x = $width / $new_width; - $cmp_y = $height / $new_height; - - // calculate x or y coordinate and width or height of source - if ($cmp_x > $cmp_y) { - - $src_w = round ($width / $cmp_x * $cmp_y); - $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2); - - } else if ($cmp_y > $cmp_x) { - - $src_h = round ($height / $cmp_y * $cmp_x); - $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2); - - } - - // positional cropping! - if ($align) { - if (strpos ($align, 't') !== false) { - $src_y = 0; - } - if (strpos ($align, 'b') !== false) { - $src_y = $height - $src_h; - } - if (strpos ($align, 'l') !== false) { - $src_x = 0; - } - if (strpos ($align, 'r') !== false) { - $src_x = $width - $src_w; - } - } - - imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h); - - } else { - - // copy and resize part of an image with resampling - imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); - - } - - if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) { - // apply filters to image - $filterList = explode ('|', $filters); - foreach ($filterList as $fl) { - - $filterSettings = explode (',', $fl); - if (isset ($imageFilters[$filterSettings[0]])) { - - for ($i = 0; $i < 4; $i ++) { - if (!isset ($filterSettings[$i])) { - $filterSettings[$i] = null; - } else { - $filterSettings[$i] = (int) $filterSettings[$i]; - } - } - - switch ($imageFilters[$filterSettings[0]][1]) { - - case 1: - - imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]); - break; - - case 2: - - imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]); - break; - - case 3: - - imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]); - break; - - case 4: - - imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]); - break; - - default: - - imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]); - break; - - } - } - } - } - - // sharpen image - if ($sharpen && function_exists ('imageconvolution')) { - - $sharpenMatrix = array ( - array (-1,-1,-1), - array (-1,16,-1), - array (-1,-1,-1), - ); - - $divisor = 8; - $offset = 0; - - imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset); - - } - //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's - if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){ - imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) ); - } - - $imgType = ""; - $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_'); - if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){ - $imgType = 'jpg'; - imagejpeg($canvas, $tempfile, $quality); - } else if(preg_match('/^image\/png$/i', $mimeType)){ - $imgType = 'png'; - imagepng($canvas, $tempfile, floor($quality * 0.09)); - } else if(preg_match('/^image\/gif$/i', $mimeType)){ - $imgType = 'gif'; - imagegif($canvas, $tempfile); - } else { - return $this->sanityFail("Could not match mime type after verifying it previously."); - } - - if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){ - $exec = OPTIPNG_PATH; - $this->debug(3, "optipng'ing $tempfile"); - $presize = filesize($tempfile); - $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down - clearstatcache(); - $aftersize = filesize($tempfile); - $sizeDrop = $presize - $aftersize; - if($sizeDrop > 0){ - $this->debug(1, "optipng reduced size by $sizeDrop"); - } else if($sizeDrop < 0){ - $this->debug(1, "optipng increased size! Difference was: $sizeDrop"); - } else { - $this->debug(1, "optipng did not change image size."); - } - } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){ - $exec = PNGCRUSH_PATH; - $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_'); - $this->debug(3, "pngcrush'ing $tempfile to $tempfile2"); - $out = `$exec $tempfile $tempfile2`; - $todel = ""; - if(is_file($tempfile2)){ - $sizeDrop = filesize($tempfile) - filesize($tempfile2); - if($sizeDrop > 0){ - $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction"); - $todel = $tempfile; - $tempfile = $tempfile2; - } else { - $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes."); - $todel = $tempfile2; - } - } else { - $this->debug(3, "pngcrush failed with output: $out"); - $todel = $tempfile2; - } - @unlink($todel); - } - - $this->debug(3, "Rewriting image with security header."); - $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_'); - $context = stream_context_create (); - $fp = fopen($tempfile,'r',0,$context); - file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type - file_put_contents($tempfile4, $fp, FILE_APPEND); - fclose($fp); - @unlink($tempfile); - $this->debug(3, "Locking and replacing cache file."); - $lockFile = $this->cachefile . '.lock'; - $fh = fopen($lockFile, 'w'); - if(! $fh){ - return $this->error("Could not open the lockfile for writing an image."); - } - if(flock($fh, LOCK_EX)){ - @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet. - rename($tempfile4, $this->cachefile); - flock($fh, LOCK_UN); - fclose($fh); - @unlink($lockFile); - } else { - fclose($fh); - @unlink($lockFile); - @unlink($tempfile4); - return $this->error("Could not get a lock for writing."); - } - $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()"); - imagedestroy($canvas); - imagedestroy($image); - return true; - } - protected function calcDocRoot(){ - $docRoot = @$_SERVER['DOCUMENT_ROOT']; - if (defined('LOCAL_FILE_BASE_DIRECTORY')) { - $docRoot = LOCAL_FILE_BASE_DIRECTORY; - } - if(!isset($docRoot)){ - $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1."); - if(isset($_SERVER['SCRIPT_FILENAME'])){ - $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF']))); - $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot"); - } - } - if(!isset($docRoot)){ - $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2."); - if(isset($_SERVER['PATH_TRANSLATED'])){ - $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF']))); - $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot"); - } - } - if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); } - $this->debug(3, "Doc root is: " . $docRoot); - $this->docRoot = $docRoot; - - } - protected function getLocalImagePath($src){ - $src = ltrim($src, '/'); //strip off the leading '/' - if(! $this->docRoot){ - $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that."); - //We don't support serving images outside the current dir if we don't have a doc root for security reasons. - $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename. - if(is_file($file)){ - return $this->realpath($file); - } - return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons."); - } //Do not go past this point without docRoot set - - //Try src under docRoot - if(file_exists ($this->docRoot . '/' . $src)) { - $this->debug(3, "Found file as " . $this->docRoot . '/' . $src); - $real = $this->realpath($this->docRoot . '/' . $src); - if(stripos($real, $this->docRoot) === 0){ - return $real; - } else { - $this->debug(1, "Security block: The file specified occurs outside the document root."); - //allow search to continue - } - } - //Check absolute paths and then verify the real path is under doc root - $absolute = $this->realpath('/' . $src); - if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here - $this->debug(3, "Found absolute path: $absolute"); - if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); } - if(stripos($absolute, $this->docRoot) === 0){ - return $absolute; - } else { - $this->debug(1, "Security block: The file specified occurs outside the document root."); - //and continue search - } - } - - $base = $this->docRoot; - - // account for Windows directory structure - if (strstr($_SERVER['SCRIPT_FILENAME'],':')) { - $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME'])); - } else { - $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME'])); - } - - foreach ($sub_directories as $sub){ - $base .= $sub . '/'; - $this->debug(3, "Trying file as: " . $base . $src); - if(file_exists($base . $src)){ - $this->debug(3, "Found file as: " . $base . $src); - $real = $this->realpath($base . $src); - if(stripos($real, $this->realpath($this->docRoot)) === 0){ - return $real; - } else { - $this->debug(1, "Security block: The file specified occurs outside the document root."); - //And continue search - } - } - } - return false; - } - protected function realpath($path){ - //try to remove any relative paths - $remove_relatives = '/\w+\/\.\.\//'; - while(preg_match($remove_relatives,$path)){ - $path = preg_replace($remove_relatives, '', $path); - } - //if any remain use PHP realpath to strip them out, otherwise return $path - //if using realpath, any symlinks will also be resolved - return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path; - } - protected function toDelete($name){ - $this->debug(3, "Scheduling file $name to delete on destruct."); - $this->toDeletes[] = $name; - } - protected function serveWebshot(){ - $this->debug(3, "Starting serveWebshot"); - $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots."; - if(! is_file(WEBSHOT_CUTYCAPT)){ - return $this->error("CutyCapt is not installed. $instr"); - } - if(! is_file(WEBSHOT_XVFB)){ - return $this->Error("Xvfb is not installed. $instr"); - } - $cuty = WEBSHOT_CUTYCAPT; - $xv = WEBSHOT_XVFB; - $screenX = WEBSHOT_SCREEN_X; - $screenY = WEBSHOT_SCREEN_Y; - $colDepth = WEBSHOT_COLOR_DEPTH; - $format = WEBSHOT_IMAGE_FORMAT; - $timeout = WEBSHOT_TIMEOUT * 1000; - $ua = WEBSHOT_USER_AGENT; - $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off'; - $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off'; - $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off'; - $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : ''; - $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot'); - $url = $this->src; - if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){ - return $this->error("Invalid URL supplied."); - } - $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986 - //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC - // which AFAIKT can't be used for shell injection. - if(WEBSHOT_XVFB_RUNNING){ - putenv('DISPLAY=:100.0'); - $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile"; - } else { - $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile"; - } - $this->debug(3, "Executing command: $command"); - $out = `$command`; - $this->debug(3, "Received output: $out"); - if(! is_file($tempfile)){ - $this->set404(); - return $this->error("The command to create a thumbnail failed."); - } - $this->cropTop = true; - if($this->processImageAndWriteToCache($tempfile)){ - $this->debug(3, "Image processed succesfully. Serving from cache"); - return $this->serveCacheFile(); - } else { - return false; - } - } - protected function serveExternalImage(){ - if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){ - $this->error("Invalid URL supplied."); - return false; - } - $tempfile = tempnam($this->cacheDirectory, 'timthumb'); - $this->debug(3, "Fetching external image into temporary file $tempfile"); - $this->toDelete($tempfile); - #fetch file here - if(! $this->getURL($this->src, $tempfile)){ - @unlink($this->cachefile); - touch($this->cachefile); - $this->debug(3, "Error fetching URL: " . $this->lastURLError); - $this->error("Error reading the URL you specified from remote host." . $this->lastURLError); - return false; - } - - $mimeType = $this->getMimeType($tempfile); - if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){ - $this->debug(3, "Remote file has invalid mime type: $mimeType"); - @unlink($this->cachefile); - touch($this->cachefile); - $this->error("The remote file is not a valid image."); - return false; - } - if($this->processImageAndWriteToCache($tempfile)){ - $this->debug(3, "Image processed succesfully. Serving from cache"); - return $this->serveCacheFile(); - } else { - return false; - } - } - public static function curlWrite($h, $d){ - fwrite(self::$curlFH, $d); - self::$curlDataWritten += strlen($d); - if(self::$curlDataWritten > MAX_FILE_SIZE){ - return 0; - } else { - return strlen($d); - } - } - protected function serveCacheFile(){ - $this->debug(3, "Serving {$this->cachefile}"); - if(! is_file($this->cachefile)){ - $this->error("serveCacheFile called in timthumb but we couldn't find the cached file."); - return false; - } - $fp = fopen($this->cachefile, 'rb'); - if(! $fp){ return $this->error("Could not open cachefile."); } - fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET); - $imgType = fread($fp, 3); - fseek($fp, 3, SEEK_CUR); - if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){ - @unlink($this->cachefile); - return $this->error("The cached image file seems to be corrupt."); - } - $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6); - $this->sendImageHeaders($imgType, $imageDataSize); - $bytesSent = @fpassthru($fp); - fclose($fp); - if($bytesSent > 0){ - return true; - } - $content = file_get_contents ($this->cachefile); - if ($content != FALSE) { - $content = substr($content, strlen($this->filePrependSecurityBlock) + 6); - echo $content; - $this->debug(3, "Served using file_get_contents and echo"); - return true; - } else { - $this->error("Cache file could not be loaded."); - return false; - } - } - protected function sendImageHeaders($mimeType, $dataSize){ - if(! preg_match('/^image\//i', $mimeType)){ - $mimeType = 'image/' . $mimeType; - } - if(strtolower($mimeType) == 'image/jpg'){ - $mimeType = 'image/jpeg'; - } - $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT'; - $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT'; - // send content headers then display image - header ('Content-Type: ' . $mimeType); - header ('Accept-Ranges: none'); //Changed this because we don't accept range requests - header ('Last-Modified: ' . $gmdate_modified); - header ('Content-Length: ' . $dataSize); - if(BROWSER_CACHE_DISABLE){ - $this->debug(3, "Browser cache is disabled so setting non-caching headers."); - header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); - header("Pragma: no-cache"); - header('Expires: ' . gmdate ('D, d M Y H:i:s', time())); - } else { - $this->debug(3, "Browser caching is enabled"); - header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate'); - header('Expires: ' . $gmdate_expires); - } - return true; - } - protected function securityChecks(){ - } - protected function param($property, $default = ''){ - if (isset ($_GET[$property])) { - return $_GET[$property]; - } else { - return $default; - } - } - protected function openImage($mimeType, $src){ - switch ($mimeType) { - case 'image/jpeg': - $image = imagecreatefromjpeg ($src); - break; - - case 'image/png': - $image = imagecreatefrompng ($src); - break; - - case 'image/gif': - $image = imagecreatefromgif ($src); - break; - - default: - $this->error("Unrecognised mimeType"); - } - - return $image; - } - protected function getIP(){ - $rem = @$_SERVER["REMOTE_ADDR"]; - $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"]; - $ci = @$_SERVER["HTTP_CLIENT_IP"]; - if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){ - if($ff){ return $ff; } - if($ci){ return $ci; } - return $rem; - } else { - if($rem){ return $rem; } - if($ff){ return $ff; } - if($ci){ return $ci; } - return "UNKNOWN"; - } - } - protected function debug($level, $msg){ - if(DEBUG_ON && $level <= DEBUG_LEVEL){ - $execTime = sprintf('%.6f', microtime(true) - $this->startTime); - $tick = sprintf('%.6f', 0); - if($this->lastBenchTime > 0){ - $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime); - } - $this->lastBenchTime = microtime(true); - error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg"); - } - } - protected function sanityFail($msg){ - return $this->error("There is a problem in the timthumb code. Message: Please report this error at timthumb's bug tracking page: $msg"); - } - protected function getMimeType($file){ - $info = getimagesize($file); - if(is_array($info) && $info['mime']){ - return $info['mime']; - } - return ''; - } - protected function setMemoryLimit(){ - $inimem = ini_get('memory_limit'); - $inibytes = timthumb::returnBytes($inimem); - $ourbytes = timthumb::returnBytes(MEMORY_LIMIT); - if($inibytes < $ourbytes){ - ini_set ('memory_limit', MEMORY_LIMIT); - $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT); - } else { - $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller."); - } - } - protected static function returnBytes($size_str){ - switch (substr ($size_str, -1)) - { - case 'M': case 'm': return (int)$size_str * 1048576; - case 'K': case 'k': return (int)$size_str * 1024; - case 'G': case 'g': return (int)$size_str * 1073741824; - default: return $size_str; - } - } - protected function getURL($url, $tempfile){ - $this->lastURLError = false; - $url = preg_replace('/ /', '%20', $url); - if(function_exists('curl_init')){ - $this->debug(3, "Curl is installed so using it to fetch URL."); - self::$curlFH = fopen($tempfile, 'w'); - if(! self::$curlFH){ - $this->error("Could not open $tempfile for writing."); - return false; - } - self::$curlDataWritten = 0; - $this->debug(3, "Fetching url with curl: $url"); - $curl = curl_init($url); - curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT); - curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30"); - curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt ($curl, CURLOPT_HEADER, 0); - curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE); - curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite'); - @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true); - @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10); - - $curlResult = curl_exec($curl); - fclose(self::$curlFH); - $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE); - if($httpStatus == 404){ - $this->set404(); - } - if($curlResult){ - curl_close($curl); - return true; - } else { - $this->lastURLError = curl_error($curl); - curl_close($curl); - return false; - } - } else { - $img = @file_get_contents ($url); - if($img === false){ - $err = error_get_last(); - if(is_array($err) && $err['message']){ - $this->lastURLError = $err['message']; - } else { - $this->lastURLError = $err; - } - if(preg_match('/404/', $this->lastURLError)){ - $this->set404(); - } - - return false; - } - if(! file_put_contents($tempfile, $img)){ - $this->error("Could not write to $tempfile."); - return false; - } - return true; - } - - } - protected function serveImg($file){ - $s = getimagesize($file); - if(! ($s && $s['mime'])){ - return false; - } - header ('Content-Type: ' . $s['mime']); - header ('Content-Length: ' . filesize($file) ); - header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'); - header ("Pragma: no-cache"); - $bytes = @readfile($file); - if($bytes > 0){ - return true; - } - $content = @file_get_contents ($file); - if ($content != FALSE){ - echo $content; - return true; - } - return false; - - } - protected function set404(){ - $this->is404 = true; - } - protected function is404(){ - return $this->is404; - } -} -- cgit v1.2.3