/** * Executes an unbuffered SQL query * * @param string|fStatement $statement The statement to perform * @param fUnbufferedResult $result The result object for the query * @param array $params The parameters for prepared statements * @return void */ private function performUnbufferedQuery($statement, $result, $params) { fCore::startErrorCapture(); $extra = NULL; if (is_object($statement)) { $statement->executeUnbufferedQuery($result, $params, $extra, $statement != $this->statement); } elseif ($this->extension == 'ibm_db2') { $result->setResult(db2_exec($this->connection, $statement, array('cursor' => DB2_FORWARD_ONLY))); } elseif ($this->extension == 'mssql') { $result->setResult(mssql_query($result->getSQL(), $this->connection, 20)); } elseif ($this->extension == 'mysql') { $result->setResult(mysql_unbuffered_query($result->getSQL(), $this->connection)); } elseif ($this->extension == 'mysqli') { $result->setResult(mysqli_query($this->connection, $result->getSQL(), MYSQLI_USE_RESULT)); } elseif ($this->extension == 'oci8') { $extra = oci_parse($this->connection, $result->getSQL()); if (oci_execute($extra, $this->inside_transaction ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS)) { $result->setResult($extra); } else { $result->setResult(FALSE); } } elseif ($this->extension == 'pgsql') { $result->setResult(pg_query($this->connection, $result->getSQL())); } elseif ($this->extension == 'sqlite') { $result->setResult(sqlite_unbuffered_query($this->connection, $result->getSQL(), SQLITE_ASSOC, $extra)); } elseif ($this->extension == 'sqlsrv') { $result->setResult(sqlsrv_query($this->connection, $result->getSQL())); } elseif ($this->extension == 'pdo') { $result->setResult($this->connection->query($result->getSQL())); } $this->statement = $statement; $this->handleErrors(fCore::stopErrorCapture()); $this->checkForError($result, $extra); }
/** * Connects to the server * * @return void */ private function connect() { if ($this->connection) { return; } fCore::startErrorCapture(E_WARNING); $this->connection = fsockopen($this->secure ? 'tls://' . $this->host : $this->host, $this->port, $error_number, $error_string, $this->timeout); foreach (fCore::stopErrorCapture('#ssl#i') as $error) { throw new fConnectivityException('There was an error connecting to the server. A secure connection was requested, but was not available. Try a non-secure connection instead.'); } if (!$this->connection) { throw new fConnectivityException('There was an error connecting to the server'); } stream_set_timeout($this->connection, $this->timeout); if ($this->type == 'imap') { if (!$this->secure && extension_loaded('openssl')) { $response = $this->write('CAPABILITY'); if (preg_match('#\\bstarttls\\b#i', $response[0])) { $this->write('STARTTLS'); do { if (isset($res)) { sleep(0.1); } $res = stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); } while ($res === 0); } } $response = $this->write('LOGIN ' . $this->username . ' ' . $this->password); if (!$response || !preg_match('#^[^ ]+\\s+OK#', $response[count($response) - 1])) { throw new fValidationException('The username and password provided were not accepted for the %1$s server %2$s on port %3$s', strtoupper($this->type), $this->host, $this->port); } $this->write('SELECT "INBOX"'); } elseif ($this->type == 'pop3') { $response = $this->read(1); if (isset($response[0])) { if ($response[0][0] == '-') { throw new fConnectivityException('There was an error connecting to the POP3 server %1$s on port %2$s', $this->host, $this->port); } preg_match('#<[^@]+@[^>]+>#', $response[0], $match); } if (!$this->secure && extension_loaded('openssl')) { $response = $this->write('STLS', 1); if ($response[0][0] == '+') { do { if (isset($res)) { sleep(0.1); } $res = stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); } while ($res === 0); if ($res === FALSE) { throw new fConnectivityException('Error establishing secure connection'); } } } $authenticated = FALSE; if (isset($match[0])) { $response = $this->write('APOP ' . $this->username . ' ' . md5($match[0] . $this->password), 1); if (isset($response[0]) && $response[0][0] == '+') { $authenticated = TRUE; } } if (!$authenticated) { $response = $this->write('USER ' . $this->username, 1); if ($response[0][0] == '+') { $response = $this->write('PASS ' . $this->password, 1); if (isset($response[0][0]) && $response[0][0] == '+') { $authenticated = TRUE; } } } if (!$authenticated) { throw new fValidationException('The username and password provided were not accepted for the %1$s server %2$s on port %3$s', strtoupper($this->type), $this->host, $this->port); } } }
public function testHandleErrorCapturePattern() { error_reporting(E_ALL | E_STRICT); ob_start(); fCore::enableErrorHandling('html'); fCore::startErrorCapture(E_NOTICE, '#print_r#'); echo $print_r; echo $undefined_var; print_r(); $errors = fCore::stopErrorCapture(); $output = ob_get_clean(); $this->assertEquals(1, count($errors)); $this->assertEquals(TRUE, strlen($output) > 0); }
/** * Removes any invalid UTF-8 characters from a string or array of strings * * @param array|string $value The string or array of strings to clean * @return string The cleaned string */ public static function clean($value) { if (!is_array($value)) { if (self::$can_ignore_invalid === NULL) { self::$can_ignore_invalid = !in_array(strtolower(ICONV_IMPL), array('unknown', 'ibm iconv')); } fCore::startErrorCapture(E_NOTICE); $value = self::iconv('UTF-8', 'UTF-8' . (self::$can_ignore_invalid ? '//IGNORE' : ''), (string) $value); fCore::stopErrorCapture(); return $value; } $keys = array_keys($value); $num_keys = sizeof($keys); for ($i = 0; $i < $num_keys; $i++) { $value[$keys[$i]] = self::clean($value[$keys[$i]]); } return $value; }
/** * Clears the WHOLE cache of every key, use with caution! * * xcache may require a login or password depending on your ini settings. * * @return boolean If the cache was successfully cleared */ public function clear() { switch ($this->type) { case 'apc': return apc_clear_cache('user'); case 'database': $this->data_store->query("DELETE FROM %r", $this->config['table']); return TRUE; case 'directory': $files = array_diff(scandir($this->config['path']), array('.', '..')); $success = TRUE; foreach ($files as $file) { $success = unlink($this->config['path'] . $file) && $success; } return $success; case 'file': $this->data_store = array(); $this->config['state'] = 'dirty'; return TRUE; case 'memcache': return $this->data_store->flush(); case 'redis': return $this->data_store->flushDB(); case 'xcache': fCore::startErrorCapture(); xcache_clear_cache(XC_TYPE_VAR, 0); return (bool) fCore::stopErrorCapture(); } }
/** * Removes any invalid UTF-8 characters from a string or array of strings * * @param array|string $value The string or array of strings to clean * @return string The cleaned string */ public static function clean($value) { if (!is_array($value)) { self::checkMbString(); if (self::$mbstring_available) { $old_sub = ini_get('mbstring.substitute_character'); ini_set('mbstring.substitute_character', 'none'); $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8'); ini_set('mbstring.substitute_character', $old_sub); return $value; } if (self::$can_ignore_invalid === NULL) { self::$can_ignore_invalid = !in_array(strtolower(ICONV_IMPL), array('unknown', 'ibm iconv')); } fCore::startErrorCapture(E_NOTICE); $value = self::iconv('UTF-8', 'UTF-8' . (self::$can_ignore_invalid ? '//IGNORE' : ''), (string) $value); fCore::stopErrorCapture(); return $value; } $keys = array_keys($value); $num_keys = sizeof($keys); for ($i = 0; $i < $num_keys; $i++) { $value[$keys[$i]] = self::clean($value[$keys[$i]]); } return $value; }
/** * Opens the session for writing, is automatically called by ::clear(), ::get() and ::set() * * A `Cannot send session cache limiter` warning will be triggered if this, * ::add(), ::clear(), ::delete(), ::get() or ::set() is called after output * has been sent to the browser. To prevent such a warning, explicitly call * this method before generating any output. * * @param boolean $cookie_only_session_id If the session id should only be allowed via cookie - this is a security issue and should only be set to `FALSE` when absolutely necessary * @return void */ public static function open($cookie_only_session_id = TRUE) { if (self::$open) { return; } self::$open = TRUE; if (self::$normal_timespan === NULL) { self::$normal_timespan = ini_get('session.gc_maxlifetime'); } if (self::$backend && self::exists() && session_module_name() != 'user') { throw new fProgrammerException('A custom backend was provided by %1$s, however the session has already been started, so it can not be used', __CLASS__ . '::setBackend()'); } // If the session is already open, we just piggy-back without setting options if (!self::exists()) { if ($cookie_only_session_id) { ini_set('session.use_cookies', 1); ini_set('session.use_only_cookies', 1); } // If we are using a custom backend we have to set the session handler if (self::$backend && session_module_name() != 'user') { session_set_save_handler(array('fSession', 'openCache'), array('fSession', 'closeCache'), array('fSession', 'readCache'), array('fSession', 'writeCache'), array('fSession', 'destroyCache'), array('fSession', 'gcCache')); } // https://bugs.php.net/bug.php?id=68063 // Fix warning with Bad IDs fCore::startErrorCapture(); $started = session_start(); fCore::stopErrorCapture(); if (!$started) { session_regenerate_id(TRUE); session_start(); } } // If the session has existed for too long, reset it if (isset($_SESSION['fSession::expires']) && $_SESSION['fSession::expires'] < $_SERVER['REQUEST_TIME']) { $_SESSION = array(); self::regenerateID(); } if (!isset($_SESSION['fSession::type'])) { $_SESSION['fSession::type'] = 'normal'; } // We store the expiration time for a session to allow for both normal and persistent sessions if ($_SESSION['fSession::type'] == 'persistent' && self::$persistent_timespan) { $_SESSION['fSession::expires'] = $_SERVER['REQUEST_TIME'] + self::$persistent_timespan; } else { $_SESSION['fSession::expires'] = $_SERVER['REQUEST_TIME'] + self::$normal_timespan; } }
/** * Parses a search string into search terms, supports quoted phrases and removes extra punctuation * * @internal * * @param string $terms A text string from a form input to parse into search terms * @param boolean $ignore_stop_words If stop words should be ignored, this setting will be ignored if all words are stop words * @return void */ public static function parseSearchTerms($terms, $ignore_stop_words = FALSE) { $stop_words = array('i', 'a', 'an', 'are', 'as', 'at', 'be', 'by', 'de', 'en', 'en', 'for', 'from', 'how', 'in', 'is', 'it', 'la', 'of', 'on', 'or', 'that', 'the', 'this', 'to', 'was', 'what', 'when', 'where', 'who', 'will'); preg_match_all('#(?:"[^"]+"|[^\\s]+)#', $terms, $matches); $good_terms = array(); $ignored_terms = array(); foreach ($matches[0] as $match) { // Remove phrases from quotes if ($match[0] == '"' && substr($match, -1)) { $match = substr($match, 1, -1); // Trim any punctuation off of the beginning and end of terms } else { if (self::$pcre_supports_unicode_character_properties === NULL) { fCore::startErrorCapture(); preg_match('#\\pC#u', 'test'); self::$pcre_supports_unicode_character_properties = !(bool) fCore::stopErrorCapture(); } if (self::$pcre_supports_unicode_character_properties) { $match = preg_replace('#(^[\\pC\\pC\\pM\\pP\\pS\\pZ]+|[\\pC\\pC\\pM\\pP\\pS\\pZ]+$)#iDu', '', $match); } else { // This just removes ascii non-alphanumeric characters, plus the unicode punctuation and supplemental punctuation blocks $match = preg_replace('#(^[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7F\\x{2000}-\\x{206F}\\x{2E00}-\\x{2E7F}\\x{00A1}-\\x{00A9}\\x{00AB}-\\x{00B1}\\x{00B4}\\x{00B6}-\\x{00B8}\\x{00BB}\\x{00BF}\\x{00D7}\\x{00F7}]+|[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7F\\x{2000}-\\x{206F}\\x{2E00}-\\x{2E7F}\\x{00A1}-\\x{00A9}\\x{00AB}-\\x{00B1}\\x{00B4}\\x{00B6}-\\x{00B8}\\x{00BB}\\x{00BF}\\x{00D7}\\x{00F7}]+$)#iDu', '', $match); } } if ($ignore_stop_words && in_array(strtolower($match), $stop_words)) { $ignored_terms[] = $match; continue; } $good_terms[] = $match; } // If no terms were parsed, that means all words were stop words if ($ignored_terms && !$good_terms) { $good_terms = $ignored_terms; } return $good_terms; }
/** * Encrypts the passed data using symmetric-key encryption * * Since this is symmetric-key cryptography, the same key is used for * encryption and decryption. * * @throws fValidationException When the $secret_key is less than 8 characters long * * @param string $plaintext The content to be encrypted * @param string $secret_key The secret key to use for encryption - must be at least 8 characters * @return string An encrypted and base-64 encoded result containing a Flourish fingerprint and suitable for decryption using ::symmetricKeyDecrypt() */ public static function symmetricKeyEncrypt($plaintext, $secret_key) { if (strlen($secret_key) < 8) { throw new fValidationException('The secret key specified does not meet the minimum requirement of being at least %s characters long', 8); } self::verifySymmetricKeyEnvironment(); // This code uses the Rijndael cipher with a 192 bit block size and a // 256 bit key in cipher feedback mode. Cipher feedback mode is chosen // because no extra padding is added, ensuring we always get the exact // same plaintext out of the decrypt method $module = mcrypt_module_open('rijndael-192', '', 'cfb', ''); $key = substr(sha1($secret_key), 0, mcrypt_enc_get_key_size($module)); srand(); $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); // Finish the main encryption mcrypt_generic_init($module, $key, $iv); fCore::startErrorCapture(E_WARNING); $ciphertext = mcrypt_generic($module, $plaintext); fCore::stopErrorCapture(); // Clean up the main encryption mcrypt_generic_deinit($module); mcrypt_module_close($module); // Here we are generating the HMAC for the encrypted data to ensure data integrity $hmac = self::hashHMAC('sha1', $iv . '#' . $ciphertext, $secret_key); // All of the data is then encoded using base64 to prevent issues with character sets $encoded_iv = base64_encode($iv); $encoded_ciphertext = base64_encode($ciphertext); // Indicate in the resulting encrypted data what the encryption tool was return 'fCryptography::symmetric#' . $encoded_iv . '#' . $encoded_ciphertext . '#' . $hmac; }
/** * Initiates the connection to the server * * @return void */ private function connect() { if ($this->connection) { return; } $fqdn = fEmail::getFQDN(); fCore::startErrorCapture(E_WARNING); $host = $this->secure ? 'tls://' . $this->host : $this->host; $this->connection = fsockopen($host, $this->port, $error_int, $error_string, $this->timeout); foreach (fCore::stopErrorCapture('#ssl#i') as $error) { throw new fConnectivityException('There was an error connecting to the server. A secure connection was requested, but was not available. Try a non-secure connection instead.'); } if (!$this->connection) { throw new fConnectivityException('There was an error connecting to the server'); } stream_set_timeout($this->connection, $this->timeout); $response = $this->read('#^220 #'); if (!$this->find($response, '#^220[ -]#')) { throw new fConnectivityException('Unknown SMTP welcome message, %1$s, from server %2$s on port %3$s', join("\r\n", $response), $this->host, $this->port); } // Try sending the ESMTP EHLO command, but fall back to normal SMTP HELO $response = $this->write('EHLO ' . $fqdn, '#^250 #m'); if ($this->find($response, '#^500#')) { $response = $this->write('HELO ' . $fqdn, 1); } // If STARTTLS is available, use it if (!$this->secure && extension_loaded('openssl') && $this->find($response, '#^250[ -]STARTTLS#')) { $response = $this->write('STARTTLS', '#^220 #'); $affirmative = $this->find($response, '#^220[ -]#'); if ($affirmative) { do { if (isset($res)) { sleep(0.1); } $res = stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); } while ($res === 0); } if (!$affirmative || $res === FALSE) { throw new fConnectivityException('Error establishing secure connection'); } $response = $this->write('EHLO ' . $fqdn, '#^250 #m'); } $this->max_size = 0; if ($match = $this->find($response, '#^250[ -]SIZE\\s+(\\d+)$#')) { $this->max_size = $match[0][1]; } $this->pipelining = (bool) $this->find($response, '#^250[ -]PIPELINING$#'); $auth_methods = array(); if ($match = $this->find($response, '#^250[ -]AUTH[ =](.*)$#')) { $auth_methods = array_map('strtoupper', explode(' ', $match[0][1])); } if (!$auth_methods || !$this->username) { return; } if (in_array('DIGEST-MD5', $auth_methods)) { $response = $this->write('AUTH DIGEST-MD5', 1); $this->handleErrors($response); $match = $this->find($response, '#^334 (.*)$#'); $challenge = base64_decode($match[0][1]); preg_match_all('#(?<=,|^)(\\w+)=("[^"]+"|[^,]+)(?=,|$)#', $challenge, $matches, PREG_SET_ORDER); $request_params = array(); foreach ($matches as $_match) { $request_params[$_match[1]] = $_match[2][0] == '"' ? substr($_match[2], 1, -1) : $_match[2]; } $missing_qop_auth = !isset($request_params['qop']) || !in_array('auth', explode(',', $request_params['qop'])); $missing_nonce = empty($request_params['nonce']); if ($missing_qop_auth || $missing_nonce) { throw new fUnexpectedException('The SMTP server %1$s on port %2$s claims to support DIGEST-MD5, but does not seem to provide auth functionality', $this->host, $this->port); } if (!isset($request_params['realm'])) { $request_params['realm'] = ''; } // Algorithm from http://www.ietf.org/rfc/rfc2831.txt $realm = $request_params['realm']; $nonce = $request_params['nonce']; $cnonce = fCryptography::randomString('32', 'hexadecimal'); $nc = '00000001'; $digest_uri = 'smtp/' . $this->host; $a1 = md5($this->username . ':' . $realm . ':' . $this->password, TRUE) . ':' . $nonce . ':' . $cnonce; $a2 = 'AUTHENTICATE:' . $digest_uri; $response = md5(md5($a1) . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':auth:' . md5($a2)); $response_params = array('charset=utf-8', 'username="******"', 'realm="' . $realm . '"', 'nonce="' . $nonce . '"', 'nc=' . $nc, 'cnonce="' . $cnonce . '"', 'digest-uri="' . $digest_uri . '"', 'response=' . $response, 'qop=auth'); $response = $this->write(base64_encode(join(',', $response_params)), 2); } elseif (in_array('CRAM-MD5', $auth_methods)) { $response = $this->write('AUTH CRAM-MD5', 1); $match = $this->find($response, '#^334 (.*)$#'); $challenge = base64_decode($match[0][1]); $response = $this->write(base64_encode($this->username . ' ' . fCryptography::hashHMAC('md5', $challenge, $this->password)), 1); } elseif (in_array('LOGIN', $auth_methods)) { $response = $this->write('AUTH LOGIN', 1); $this->write(base64_encode($this->username), 1); $response = $this->write(base64_encode($this->password), 1); } elseif (in_array('PLAIN', $auth_methods)) { $response = $this->write('AUTH PLAIN ' . base64_encode($this->username . "" . $this->username . "" . $this->password), 1); } if ($this->find($response, '#^535[ -]#')) { throw new fValidationException('The username and password provided were not accepted for the SMTP server %1$s on port %2$s', $this->host, $this->port); } if (!array_filter($response)) { throw new fConnectivityException('No response was received for the authorization request'); } }
/** * Sets up a prepared statement * * @internal * * @param fDatabase $database The database object this result set was created from * @param string $query The SQL statement to prepare * @param array $placeholders The data type placeholders * @param string $untranslated_query The original untranslated SQL, if applicable * @return fStatement */ public function __construct($database, $query, $placeholders, $untranslated_sql) { if (!$database instanceof fDatabase) { throw new fProgrammerException('The database object provided does not appear to be a descendant of fDatabase'); } $this->database = $database; $this->placeholders = $placeholders; $this->sql = vsprintf($query, $placeholders); $this->untranslated_sql = $untranslated_sql; $extension = $this->database->getExtension(); if ($extension == 'pdo' && $this->database->getType() == 'mssql') { $extension = 'pdo_dblib'; } switch ($extension) { // These database extensions don't have prepared statements case 'mssql': case 'mysql': case 'pdo_dblib': case 'sqlite': $query = vsprintf($query, $placeholders); break; case 'oci8': $named_placeholders = array(); for ($i = 1; $i <= sizeof($placeholders); $i++) { $named_placeholders[] = ':p' . $i; } $query = vsprintf($query, $named_placeholders); break; case 'ibm_db2': case 'mysqli': case 'pdo': case 'sqlsrv': $question_marks = array(); if (sizeof($placeholders)) { $question_marks = array_fill(0, sizeof($placeholders), '?'); } $query = vsprintf($query, $question_marks); break; case 'pgsql': $dollar_placeholders = array(); for ($i = 1; $i <= sizeof($placeholders); $i++) { $dollar_placeholders[] = '$' . $i; } $query = vsprintf($query, $dollar_placeholders); break; } $connection = $this->database->getConnection(); fCore::startErrorCapture(E_WARNING); switch ($extension) { // These database extensions don't have prepared statements case 'mssql': case 'mysql': case 'pdo_dblib': case 'sqlite': $statement = $query; break; case 'ibm_db2': $statement = db2_prepare($connection, $query, array('cursor' => DB2_FORWARD_ONLY)); break; case 'mysqli': $statement = mysqli_prepare($connection, $query); break; case 'oci8': $statement = oci_parse($connection, $query); break; case 'pdo': $statement = $connection->prepare($query); break; case 'pgsql': static $statement_number = 0; $statement_number++; $this->identifier = 'fstmt' . $statement_number; $statement = pg_prepare($connection, $this->identifier, $query); break; case 'sqlsrv': $params = array(); for ($i = 0; $i < sizeof($placeholders); $i++) { if ($placeholders[$i] == '%s') { $this->bound_params[$i] = array(NULL, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('UTF-8')); } else { $this->bound_params[$i] = array(NULL); } $params[$i] =& $this->bound_params[$i]; } $statement = sqlsrv_prepare($connection, $query, $params); break; } fCore::stopErrorCapture(); if (!$statement) { switch ($extension) { case 'ibm_db2': $message = db2_stmt_errormsg($statement); break; case 'mysqli': $message = mysqli_error($connection); break; case 'oci8': $error_info = oci_error($statement); $message = $error_info['message']; break; case 'pgsql': $message = pg_last_error($connection); break; case 'sqlsrv': $error_info = sqlsrv_errors(SQLSRV_ERR_ALL); $message = $error_info[0]['message']; break; case 'pdo': $error_info = $connection->errorInfo(); $message = $error_info[2]; break; } $db_type_map = array('db2' => 'DB2', 'mssql' => 'MSSQL', 'mysql' => 'MySQL', 'oracle' => 'Oracle', 'postgresql' => 'PostgreSQL', 'sqlite' => 'SQLite'); throw new fSQLException('%1$s error (%2$s) in %3$s', $db_type_map[$this->database->getType()], $message, $this->sql); } $this->statement = $statement; }
/** * Gets the dimensions and type of an image stored on the filesystem * * The `'type'` key will have one of the following values: * * - `{null}` (File type is not supported) * - `'jpg'` * - `'gif'` * - `'png'` * - `'tif'` * * @throws fValidationException When the file specified is not an image * * @param string $image_path The path to the image to get stats for * @param string $element The element to retrieve: `'type'`, `'width'`, `'height'` * @return mixed An associative array: `'type' => {mixed}, 'width' => {integer}, 'height' => {integer}`, or the element specified */ protected static function getInfo($image_path, $element = NULL) { $extension = strtolower(fFilesystem::getPathInfo($image_path, 'extension')); if (!in_array($extension, array('jpg', 'jpeg', 'png', 'gif', 'tif', 'tiff'))) { $type = self::getImageType($image_path); if ($type === NULL) { throw new fValidationException('The file specified, %s, does not appear to be an image', $image_path); } } fCore::startErrorCapture(E_WARNING); $image_info = getimagesize($image_path); fCore::stopErrorCapture(); if ($image_info == FALSE) { throw new fValidationException('The file specified, %s, is not an image', $image_path); } $valid_elements = array('type', 'width', 'height'); if ($element !== NULL && !in_array($element, $valid_elements)) { throw new fProgrammerException('The element specified, %1$s, is invalid. Must be one of: %2$s.', $element, join(', ', $valid_elements)); } $types = array(IMAGETYPE_GIF => 'gif', IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png', IMAGETYPE_TIFF_II => 'tif', IMAGETYPE_TIFF_MM => 'tif'); $output = array(); $output['width'] = $image_info[0]; $output['height'] = $image_info[1]; if (isset($types[$image_info[2]])) { $output['type'] = $types[$image_info[2]]; } else { $output['type'] = NULL; } if ($element !== NULL) { return $output[$element]; } return $output; }