public function testAppendRollback() { fFilesystem::begin(); $file = new fFile('output/fFile/one.txt'); $file->append('+one=two'); $this->assertEquals('one+one=two', file_get_contents('output/fFile/one.txt')); fFilesystem::rollback(); $this->assertEquals('one', file_get_contents('output/fFile/one.txt')); }
/** * Generates a new filename in an attempt to create a unique name * * @param string $filename The filename to generate another name for * @return string The newly generated filename */ private function generateNewFilename($filename) { $filename_info = fFilesystem::getPathInfo($filename); if (preg_match('#_copy(\\d+)($|\\.)#D', $filename_info['filename'], $match)) { $i = $match[1] + 1; } else { $i = 1; } $extension = $filename_info['extension'] ? '.' . $filename_info['extension'] : ''; return preg_replace('#_copy\\d+$#D', '', $filename_info['filename']) . '_copy' . $i . $extension; }
/** * @dataProvider convertToBytesProvider */ public function testConvertToBytes($input, $output) { $this->assertEquals($output, fFilesystem::convertToBytes($input)); }
/** * Rolls back a filesystem transaction, it is safe to rollback when no transaction is in progress * * @return void */ public static function rollback() { if (self::$rollback_operations === NULL) { return; } self::$rollback_operations = array_reverse(self::$rollback_operations); foreach (self::$rollback_operations as $operation) { switch ($operation['action']) { case 'append': $current_length = filesize($operation['filename']); $handle = fopen($operation['filename'], 'r+'); ftruncate($handle, $current_length - $operation['length']); fclose($handle); break; case 'delete': self::updateDeletedMap($operation['filename'], debug_backtrace()); unlink($operation['filename']); fFilesystem::updateFilenameMap($operation['filename'], '*DELETED at ' . time() . ' with token ' . uniqid('', TRUE) . '* ' . $operation['filename']); break; case 'write': file_put_contents($operation['filename'], $operation['old_data']); break; case 'rename': fFilesystem::updateFilenameMap($operation['new_name'], $operation['old_name']); rename($operation['new_name'], $operation['old_name']); break; } } // All files to be deleted should have their backtraces erased foreach (self::$commit_operations as $operation) { if (isset($operation['object'])) { self::updateDeletedMap($operation['object']->getPath(), NULL); fFilesystem::updateFilenameMap($operation['object']->getPath(), preg_replace('#*DELETED at \\d+ with token [\\w.]+* #', '', $operation['filename'])); } } self::$commit_operations = NULL; self::$rollback_operations = NULL; }
<?php define('MY_ROOT', realpath(dirname(__FILE__) . '/../')); include MY_ROOT . '/inc/init.php'; //header('Content-type: application/json; charset=utf-8'); ///////////////// PACHUBE /////////////////// // create a new cURL resource $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, "http://radiation.crowdmap.com/feed/"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // grab URL and pass it to the browser $output = curl_exec($ch); try { $file = new fFile(DOC_ROOT . '/feeds/crowdmapStatic.xml'); } catch (fExpectedException $e) { $file = fFilesystem::createObject(DOC_ROOT . '/feeds/crowdmapStatic.xml'); } $file->write($output); // close cURL resource, and free up system resources curl_close($ch); echo $output; ?>
/** * Performs a [http://php.net/scandir scandir()] on a directory, removing the `.` and `..` entries * * If the `$filter` looks like a valid PCRE pattern - matching delimeters * (a delimeter can be any non-alphanumeric, non-backslash, non-whitespace * character) followed by zero or more of the flags `i`, `m`, `s`, `x`, * `e`, `A`, `D`, `S`, `U`, `X`, `J`, `u` - then * [http://php.net/preg_match `preg_match()`] will be used. * * Otherwise the `$filter` will do a case-sensitive match with `*` matching * zero or more characters and `?` matching a single character. * * On all OSes (even Windows), directories will be separated by `/`s when * comparing with the `$filter`. * * @param string $filter A PCRE or glob pattern to filter files/directories by path - directories can be detected by checking for a trailing / (even on Windows) * @return array The fFile (or fImage) and fDirectory objects for the files/directories in this directory */ public function scan($filter = NULL) { $this->tossIfDeleted(); $files = array_diff(scandir($this->directory), array('.', '..')); $objects = array(); if ($filter && !preg_match('#^([^a-zA-Z0-9\\\\\\s]).*\\1[imsxeADSUXJu]*$#D', $filter)) { $filter = '#^' . strtr(preg_quote($filter, '#'), array('\\*' => '.*', '\\?' => '.')) . '$#D'; } natcasesort($files); foreach ($files as $file) { if ($filter) { $test_path = is_dir($this->directory . $file) ? $file . '/' : $file; if (!preg_match($filter, $test_path)) { continue; } } $objects[] = fFilesystem::createObject($this->directory . $file); } return $objects; }
/** * Performs a [http://php.net/scandir scandir()] on a directory, removing the `.` and `..` entries * * @param string $regex_filter A PCRE to filter files/directories by path, directories can be detected by checking for a trailing / (even on Windows) * @return array The fFile (or fImage) and fDirectory objects for the files/directories in this directory */ public function scan($regex_filter = NULL) { $this->tossIfException(); $files = array_diff(scandir($this->directory), array('.', '..')); $objects = array(); foreach ($files as $file) { $file = $this->directory . $file; if ($regex_filter) { $test_path = is_dir($file) ? $file . '/' : $file; if (!preg_match($regex_filter, $test_path)) { continue; } } $objects[] = fFilesystem::createObject($file); } return $objects; }
/** * Validates a $_FILES array against the upload configuration * * @param array $file_array The $_FILES array for a single file * @return string The validation error message */ private function validateField($file_array) { if (empty($file_array['name'])) { if ($this->required) { return self::compose('Please upload a file'); } return NULL; } if ($file_array['error'] == UPLOAD_ERR_FORM_SIZE || $file_array['error'] == UPLOAD_ERR_INI_SIZE) { $max_size = !empty($_POST['MAX_FILE_SIZE']) ? $_POST['MAX_FILE_SIZE'] : ini_get('upload_max_filesize'); $max_size = !is_numeric($max_size) ? fFilesystem::convertToBytes($max_size) : $max_size; return self::compose('The file uploaded is over the limit of %s', fFilesystem::formatFilesize($max_size)); } if ($this->max_size && $file_array['size'] > $this->max_size) { return self::compose('The file uploaded is over the limit of %s', fFilesystem::formatFilesize($this->max_size)); } if (empty($file_array['tmp_name']) || empty($file_array['size'])) { if ($this->required) { return self::compose('Please upload a file'); } return NULL; } if (!empty($this->mime_types) && file_exists($file_array['tmp_name'])) { $contents = file_get_contents($file_array['tmp_name'], FALSE, NULL, 0, 4096); if (!in_array(fFile::determineMimeType($file_array['name'], $contents), $this->mime_types)) { return self::compose($this->mime_type_message); } } if (!$this->allow_php) { $file_info = fFilesystem::getPathInfo($file_array['name']); if (in_array(strtolower($file_info['extension']), array('php', 'php4', 'php5'))) { return self::compose('The file uploaded is a PHP file, but those are not permitted'); } } if (!$this->allow_dot_files) { if (substr($file_array['name'], 0, 1) == '.') { return self::compose('The name of the uploaded file may not being with a .'); } } }
/** * Writes the provided data to the file * * Requires all previous data to be stored in memory if inside a * transaction, use with caution on large files! * * If a filesystem transaction is in progress and is rolled back, the * previous data will be restored. * * @param mixed $data The data to write to the file * @return fFile The file object, to allow for method chaining */ public function write($data) { $this->tossIfDeleted(); if (!$this->isWritable()) { throw new fEnvironmentException('This file, %s, can not be written to because it is not writable', $this->file); } // Allow filesystem transactions if (fFilesystem::isInsideTransaction()) { fFilesystem::recordWrite($this); } file_put_contents($this->file, $data); return $this; }
/** * Validates the uploaded file, ensuring a file was actually uploaded and that is matched the restrictions put in place * * @throws fValidationException When no file is uploaded or the uploaded file violates the options set for this object * * @param string $field The field the file was uploaded through * @param integer $index If the field was an array of file uploads, this specifies which one to validate * @return void */ public function validate($field, $index = NULL) { if (!self::check($field)) { throw new fProgrammerException('The field specified, %s, does not appear to be a file upload field', $field); } $file_array = $this->extractFileUploadArray($field, $index); // Do some validation of the file provided if (empty($file_array['name'])) { throw new fValidationException('Please upload a file'); } if ($file_array['error'] == UPLOAD_ERR_FORM_SIZE || $file_array['error'] == UPLOAD_ERR_INI_SIZE) { $max_size = !empty($_POST['MAX_FILE_SIZE']) ? $_POST['MAX_FILE_SIZE'] : ini_get('upload_max_filesize'); $max_size = !is_numeric($max_size) ? fFilesystem::convertToBytes($max_size) : $max_size; $msg = $this->max_message != "" ? $this->max_message : 'The file uploaded is over the limit of %s'; throw new fValidationException($msg, fFilesystem::formatFilesize($max_size)); } if ($this->max_file_size && $file_array['size'] > $this->max_file_size) { $msg = $this->max_message != "" ? $this->max_message : 'The file uploaded is over the limit of %s'; throw new fValidationException($msg, fFilesystem::formatFilesize($this->max_file_size)); } if (empty($file_array['tmp_name']) || empty($file_array['size'])) { throw new fValidationException('Please upload a file'); } if (!empty($this->mime_types) && file_exists($file_array['tmp_name']) && !in_array(fFile::determineMimeType($file_array['tmp_name']), $this->mime_types)) { throw new fValidationException($this->mime_type_message); } if (!$this->allow_php) { $file_info = fFilesystem::getPathInfo($file_array['name']); if (in_array(strtolower($file_info['extension']), array('php', 'php4', 'php5'))) { throw new fValidationException('The file uploaded is a PHP file, but those are not permitted'); } } return $file_array; }
/** * Adds an attachment to the email * * If a duplicate filename is detected, it will be changed to be unique. * * @param string $filename The name of the file to attach * @param string $mime_type The mime type of the file * @param string $contents The contents of the file * @return void */ public function addAttachment($filename, $mime_type, $contents) { if (!self::stringlike($filename)) { throw new fProgrammerException('The filename specified, %s, does not appear to be a valid filename', $filename); } $filename = (string) $filename; $i = 1; while (isset($this->attachments[$filename])) { $filename_info = fFilesystem::getPathInfo($filename); $extension = $filename_info['extension'] ? '.' . $filename_info['extension'] : ''; $filename = preg_replace('#_copy\\d+$#D', '', $filename_info['filename']) . '_copy' . $i . $extension; $i++; } $this->attachments[$filename] = array('mime-type' => $mime_type, 'contents' => $contents); }
/** * Rolls back a filesystem transaction, it is safe to rollback when no transaction is in progress * * @return void */ public static function rollback() { self::$rollback_operations = array_reverse(self::$rollback_operations); foreach (self::$rollback_operations as $operation) { switch ($operation['action']) { case 'delete': self::updateExceptionMap($operation['filename'], new fProgrammerException('The action requested can not be performed because the file has been deleted')); unlink($operation['filename']); break; case 'write': file_put_contents($operation['filename'], $operation['old_data']); break; case 'rename': fFilesystem::updateFilenameMap($operation['new_name'], $operation['old_name']); rename($operation['new_name'], $operation['old_name']); break; } } // All files to be deleted should have their exceptions erased foreach (self::$commit_operations as $operation) { if (isset($operation['object'])) { self::updateExceptionMap($operation['object']->getPath(), NULL); } } self::$commit_operations = NULL; self::$rollback_operations = NULL; }
/** * Sends a message via the SMTP server * * @internal * * @throws fValidationException When the message is too large for the server * * @param string $from The email address being sent from - this will be used as the `Return-Path` header * @param array $to All of the To, Cc and Bcc email addresses to send the message to - this does not affect the message headers in any way * @param string $headers The message headers - the Bcc header will be removed if present * @param string $body The mail body * @return void */ public function send($from, $to, $headers, $body) { $this->connect(); // Lines starting with . need to start with two .s because the leading // . will be stripped $body = preg_replace('#^\\.#m', '..', $body); // Removed the Bcc header incase the SMTP server doesn't $headers = preg_replace('#^Bcc:(.*?)\\r\\n([^ ])#mi', '\\2', $headers); // Add the Date header $headers = "Date: " . date('D, j M Y H:i:s O') . "\r\n" . $headers; $data = $headers . "\r\n\r\n" . $body; if ($this->max_size && strlen($data) > $this->max_size) { throw new fValidationException('The email provided is %1$s, which is larger than the maximum size of %2$s that the server supports', fFilesystem::formatFilesize(strlen($data)), fFilesystem::formatFilesize($this->max_size)); } $mail_from = "MAIL FROM:<" . $from . ">"; if ($this->pipelining) { $expect = 2; $rcpt_to = ''; foreach ($to as $email) { $rcpt_to .= "RCPT TO:<" . $email . ">\r\n"; $expect++; } $rcpt_to = trim($rcpt_to); $this->write($mail_from . "\r\n" . $rcpt_to . "\r\nDATA\r\n", $expect); } else { $this->write($mail_from, 1); foreach ($to as $email) { $this->write("RCPT TO:<" . $email . ">", 1); } $this->write('DATA', 1); } $this->write($data . "\r\n.\r\n", 1); $this->write('RSET', 1); }
foreach ($flickrFeeds as $feed) { $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, $feed); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); $data = curl_exec($ch); // execute curl session $data = str_replace('jsonFlickrApi(', '', $data); $data = substr($data, 0, strlen($data) - 1); //strip out last paren $object = json_decode($data); // stdClass object $items = $object->photos->photo; foreach ($items as $item) { $newFeed .= '{"title": "' . $item->title . '","title_jp": "","description": "' . $item->tags . '","creator": "probe","feed": "http://api.flickr.com/services/rest","location": {"lon":' . $item->longitude . ', "lat":' . $item->latitude . ', "name": ""},"id":"' . $item->owner . '","datastreams": [{"at": "' . $item->datetaken . '","max_value": "0","min_value": "0","current_value": "' . $item->url_m . '","id": "1","unit": {"type": "photo","label": "photo","symbol": "photo"}}]},'; } curl_close($ch); $total += count($items); } $newFeed = substr($newFeed, 0, strlen($newFeed) - 1); //strip out last comma $newFeed .= '], "itemsPerPage": ' . $total . ', "startIndex": 0, "totalResults": ' . $total . '}'; try { $file = new fFile(DOC_ROOT . '/feeds/probe002.json'); } catch (fExpectedException $e) { $file = fFilesystem::createObject(DOC_ROOT . '/feeds/probe002.json'); } $file->write($newFeed); // close cURL resource, and free up system resources print_r($newFeed);
/** * Uploads a file * * @internal * * @param fActiveRecord $object The fActiveRecord instance * @param array &$values The current values * @param array &$old_values The old values * @param array &$related_records Any records related to this record * @param array &$cache The cache array for the record * @param string $method_name The method that was called * @param array $parameters The parameters passed to the method * @return fFile The uploaded file */ public static function upload($object, &$values, &$old_values, &$related_records, &$cache, $method_name, $parameters) { $class = get_class($object); list($action, $column) = fORM::parseMethod($method_name); $existing_temp_file = FALSE; // Try to upload the file putting it in the temp dir incase there is a validation problem with the record try { $upload_dir = self::$file_upload_columns[$class][$column]; $temp_dir = self::prepareTempDir($upload_dir); if (!fUpload::check($column)) { throw new fExpectedException('Please upload a file'); } $uploader = self::setUpFUpload($class, $column); $file = $uploader->move($temp_dir, $column); // If there was an eror, check to see if we have an existing file } catch (fExpectedException $e) { // If there is an existing file and none was uploaded, substitute the existing file $existing_file = fRequest::get('existing-' . $column); $delete_file = fRequest::get('delete-' . $column, 'boolean'); $no_upload = $e->getMessage() == self::compose('Please upload a file'); if ($existing_file && $delete_file && $no_upload) { $file = NULL; } elseif ($existing_file) { $file_path = $upload_dir->getPath() . $existing_file; $file = fFilesystem::createObject($file_path); $current_file = $values[$column]; // If the existing file is the same as the current file, we can just exit now if ($current_file && $file->getPath() == $current_file->getPath()) { return; } $existing_temp_file = TRUE; } else { $file = NULL; } } // Assign the file fActiveRecord::assign($values, $old_values, $column, $file); // Perform the file upload inheritance if (!empty(self::$column_inheritence[$class][$column])) { foreach (self::$column_inheritence[$class][$column] as $other_column) { if ($file) { // Image columns will only inherit if it is an fImage object if (!$file instanceof fImage && isset(self::$image_upload_columns[$class][$other_column])) { continue; } $other_upload_dir = self::$file_upload_columns[$class][$other_column]; $other_temp_dir = self::prepareTempDir($other_upload_dir); if ($existing_temp_file) { $other_file = fFilesystem::createObject($other_temp_dir->getPath() . $file->getName()); } else { $other_file = $file->duplicate($other_temp_dir, FALSE); } } else { $other_file = $file; } fActiveRecord::assign($values, $old_values, $other_column, $other_file); if (!$existing_temp_file && $other_file) { self::processImage($class, $other_column, $other_file); } } } // Process the file if (!$existing_temp_file && $file) { self::processImage($class, $column, $file); } return $file; }
/** * Combines an array of CSS or JS files and places them as a single file * * @param string $type The type of compilation, 'css' or 'js' * @param string $element The element name * @param array $values An array of file paths * @return void */ protected function handleMinified($type, $element, $values) { $paths = array(); $media = NULL; foreach ($values as $value) { if (is_array($value)) { $paths[] = $this->minification_prefix . $value['path']; if ($type == 'css') { $media = !empty($value['media']) ? $value['media'] : NULL; } } else { $paths[] = $this->minification_prefix . $value; } } $hash = sha1(join('|', $paths)); $cache_file = $this->minification_directory . $hash . '.' . $type; $regenerate = FALSE; $checked_paths = FALSE; if (!file_exists($cache_file)) { $regenerate = TRUE; } elseif ($this->minification_mode == 'development') { $cache_mtime = filemtime($cache_file); $checked_paths = TRUE; foreach ($paths as $path) { if (!file_exists($path)) { throw new fEnvironmentException('The file specified, %s, does not exist under the $path_prefix specified', preg_replace('#^' . preg_quote($this->minification_prefix, '#') . '#', '', $path)); } if (filemtime($path) > $cache_mtime) { $regenerate = TRUE; break; } } } if ($regenerate) { $minified = ''; foreach ($paths as $path) { $path_cache_file = $this->minification_directory . sha1($path) . '.' . $type; if ($checked_paths && !file_exists($path)) { throw new fEnvironmentException('The file specified, %s, does not exist under the $path_prefix specified', preg_replace('#^' . preg_quote($this->minification_prefix, '#') . '#', '', $path)); } // Checks if this path has been cached if (file_exists($path_cache_file) && filemtime($path_cache_file) >= filemtime($path)) { $minified_path = file_get_contents($path_cache_file); } else { $minified_path = trim($this->minify(file_get_contents($path), $type)); file_put_contents($path_cache_file, $minified_path); } $minified .= "\n" . $minified_path; } file_put_contents($cache_file, substr($minified, 1)); } $version = filemtime($cache_file); $compiled_value = fFilesystem::translateToWebPath($cache_file) . '?v=' . $version; if ($type == 'css' && $media) { $compiled_value = array('path' => $compiled_value, 'media' => $media); } $method = 'place' . strtoupper($type); $this->{$method}($compiled_value); }
/** * Validates a $_FILES array against the upload configuration * * @param array $file_array The $_FILES array for a single file * @return string The validation error message */ private function validateField($file_array) { if (empty($file_array['name'])) { if ($this->required) { return self::compose('Please upload a file'); } return NULL; } if ($file_array['error'] == UPLOAD_ERR_FORM_SIZE || $file_array['error'] == UPLOAD_ERR_INI_SIZE) { $max_size = !empty($_POST['MAX_FILE_SIZE']) ? $_POST['MAX_FILE_SIZE'] : ini_get('upload_max_filesize'); $max_size = !is_numeric($max_size) ? fFilesystem::convertToBytes($max_size) : $max_size; return self::compose('The file uploaded is over the limit of %s', fFilesystem::formatFilesize($max_size)); } if ($this->max_size && $file_array['size'] > $this->max_size) { return self::compose('The file uploaded is over the limit of %s', fFilesystem::formatFilesize($this->max_size)); } if (empty($file_array['tmp_name']) || empty($file_array['size'])) { if ($this->required) { return self::compose('Please upload a file'); } return NULL; } if (!empty($this->mime_types) && file_exists($file_array['tmp_name'])) { $contents = file_get_contents($file_array['tmp_name'], FALSE, NULL, 0, 4096); if (!in_array(fFile::determineMimeType($file_array['name'], $contents), $this->mime_types)) { return self::compose($this->mime_type_message); } } if (!$this->allow_php) { $file_info = fFilesystem::getPathInfo($file_array['name']); if (in_array(strtolower($file_info['extension']), array('php', 'php4', 'php5'))) { return self::compose('The file uploaded is a PHP file, but those are not permitted'); } } if (!$this->allow_dot_files) { if (substr($file_array['name'], 0, 1) == '.') { return self::compose('The name of the uploaded file may not being with a .'); } } if ($this->image_dimensions && file_exists($file_array['tmp_name'])) { if (fImage::isImageCompatible($file_array['tmp_name'])) { list($width, $height, $other) = getimagesize($file_array['tmp_name']); if ($this->image_dimensions['min_width'] && $width < $this->image_dimensions['min_width']) { return self::compose('The uploaded image is narrower than the minimum width of %spx', $this->image_dimensions['min_width']); } if ($this->image_dimensions['min_height'] && $height < $this->image_dimensions['min_height']) { return self::compose('The uploaded image is shorter than the minimum height of %spx', $this->image_dimensions['min_height']); } if ($this->image_dimensions['max_width'] && $width > $this->image_dimensions['max_width']) { return self::compose('The uploaded image is wider than the maximum width of %spx', $this->image_dimensions['max_width']); } if ($this->image_dimensions['max_height'] && $height > $this->image_dimensions['max_height']) { return self::compose('The uploaded image is taller than the maximum height of %spx', $this->image_dimensions['max_height']); } } } if ($this->image_ratio && file_exists($file_array['tmp_name'])) { if (fImage::isImageCompatible($file_array['tmp_name'])) { list($width, $height, $other) = getimagesize($file_array['tmp_name']); if ($this->image_ratio['allow_excess_dimension'] == 'width' && $width / $height < $this->image_ratio['width'] / $this->image_ratio['height']) { return self::compose('The uploaded image is too narrow for its height. The required ratio is %1$sx%2$s or wider.', $this->image_ratio['width'], $this->image_ratio['height']); } if ($this->image_ratio['allow_excess_dimension'] == 'height' && $width / $height > $this->image_ratio['width'] / $this->image_ratio['height']) { return self::compose('The uploaded image is too short for its width. The required ratio is %1$sx%2$s or taller.', $this->image_ratio['width'], $this->image_ratio['height']); } } } }
/** * Saves any changes to the image * * If the file type is different than the current one, removes the current * file once the new one is created. * * This operation will be reverted by a filesystem transaction being rolled * back. If a transaction is in progress and the new image type causes a * new file to be created, the old file will not be deleted until the * transaction is committed. * * @param string $new_image_type The new file format for the image: 'NULL` (no change), `'jpg'`, `'gif'`, `'png'` * @param integer $jpeg_quality The quality setting to use for JPEG images - this may be ommitted * @param boolean $overwrite If an existing file with the same name and extension should be overwritten * @param string :$new_image_type * @param boolean :$overwrite * @return fImage The image object, to allow for method chaining */ public function saveChanges($new_image_type = NULL, $jpeg_quality = 90, $overwrite = FALSE) { // This allows ommitting the $jpeg_quality parameter, which is very useful for non-jpegs $args = func_get_args(); if (count($args) == 2 && is_bool($args[1])) { $overwrite = $args[1]; $jpeg_quality = 90; } $this->tossIfDeleted(); self::determineProcessor(); if (self::$processor == 'none') { throw new fEnvironmentException("The changes to the image can't be saved because neither the GD extension or ImageMagick appears to be installed on the server"); } $type = self::getImageType($this->file); if ($type == 'tif' && self::$processor == 'gd') { throw new fEnvironmentException('The image specified, %s, is a TIFF file and the GD extension can not handle TIFF files. Please install ImageMagick if you wish to manipulate TIFF files.', $this->file); } $valid_image_types = array('jpg', 'gif', 'png'); if ($new_image_type !== NULL && !in_array($new_image_type, $valid_image_types)) { throw new fProgrammerException('The new image type specified, %1$s, is invalid. Must be one of: %2$s.', $new_image_type, join(', ', $valid_image_types)); } if (is_numeric($jpeg_quality)) { $jpeg_quality = (int) round($jpeg_quality); } if (!is_integer($jpeg_quality) || $jpeg_quality < 1 || $jpeg_quality > 100) { throw new fProgrammerException('The JPEG quality specified, %1$s, is either not an integer, less than %2$s or greater than %3$s.', $jpeg_quality, 1, 100); } if ($new_image_type && fFilesystem::getPathInfo($this->file, 'extension') != $new_image_type) { if ($overwrite) { $path_info = fFilesystem::getPathInfo($this->file); $output_file = $path_info['dirname'] . $path_info['filename'] . '.' . $new_image_type; } else { $output_file = fFilesystem::makeUniqueName($this->file, $new_image_type); } if (file_exists($output_file)) { if (!is_writable($output_file)) { throw new fEnvironmentException('Changes to the image can not be saved because the file, %s, is not writable', $output_file); } } else { $output_dir = dirname($output_file); if (!is_writable($output_dir)) { throw new fEnvironmentException('Changes to the image can not be saved because the directory to save the new file, %s, is not writable', $output_dir); } } } else { $output_file = $this->file; if (!is_writable($output_file)) { throw new fEnvironmentException('Changes to the image can not be saved because the file, %s, is not writable', $output_file); } } // If we don't have any changes and no name change, just exit if (!$this->pending_modifications && $output_file == $this->file) { return $this; } // Wrap changes to the image into the filesystem transaction if ($output_file == $this->file && fFilesystem::isInsideTransaction()) { fFilesystem::recordWrite($this); } if (self::$processor == 'gd') { $this->processWithGD($output_file, $jpeg_quality); } elseif (self::$processor == 'imagemagick') { $this->processWithImageMagick($output_file, $jpeg_quality); } $old_file = $this->file; fFilesystem::updateFilenameMap($this->file, $output_file); // If we created a new image, delete the old one if ($output_file != $old_file) { $old_image = new fImage($old_file); $old_image->delete(); } $this->pending_modifications = array(); return $this; }