/** * Make a copy of a source Filestore\File into this File. * * (Generally only useful internally) * * @param Filestore\File $src Source file backend * @param bool $overwrite true to overwrite existing file * * @throws \Exception * @return bool True or False if succeeded. */ public function copyFrom(Filestore\File $src, $overwrite = false) { // Don't overwrite existing files unless told otherwise... if (!$overwrite) { $c = 0; $ext = $this->getExtension(); $base = $this->getBaseFilename(true); $dir = dirname($this->_filename); $prefix = $dir . '/' . $base; $suffix = (($ext == '') ? '' : '.' . $ext); $thathash = $src->getHash(); $f = $prefix . $suffix; while(file_exists($f) && md5_file($f) != $thathash){ $f = $prefix . '-' . ++$c . '' . $suffix; } $this->_filename = $f; } // And do the actual copy! // To save memory, try to use as low-level functions as possible. $localfilename = $src->getLocalFilename(); // I also want to know when this file was modified so I can set the new version to have the same datestamp. $modifiedtime = $src->getMTime(); $ftp = \Core\ftp(); $tmpdir = TMP_DIR; if ($tmpdir{0} != '/') $tmpdir = ROOT_PDIR . $tmpdir; // Needs to be fully resolved // Resolve it from its default. // This is provided from a config define, (probably). $mode = (defined('DEFAULT_FILE_PERMS') ? DEFAULT_FILE_PERMS : 0644); // Make sure the directory exists first! // This has to be done regardless of FTP mode or not. self::_Mkdir(dirname($this->_filename), null, true); if ( !$ftp || // FTP not enabled or (strpos($this->_filename, $tmpdir) === 0) // Destination is a temporary file. ) { // Read in only so much data at a time. This is to prevent // PHP from trying to read a full 2GB file into memory at once :S $maxbuffer = (1024 * 1024 * 10); $handlein = fopen($localfilename, 'r'); $handleout = fopen($this->_filename, 'w'); // Couldn't get a lock on both input and output files. if(!$handlein){ throw new \Exception('Unable to open file ' . $localfilename . ' for reading.'); } if(!$handleout){ throw new \Exception('Unable to open file ' . $this->_filename . ' for writing.'); } while(!feof($handlein)){ fwrite($handleout, fread($handlein, $maxbuffer)); } // yayz fclose($handlein); fclose($handleout); chmod($this->_filename, $mode); // Don't forget the mtime ;) touch($this->_filename, $modifiedtime); return true; } else { // Trim off the ROOT_PDIR since it'll be relative to the ftp root set in the config. if (strpos($this->_filename, ROOT_PDIR) === 0){ $filename = substr($this->_filename, strlen(ROOT_PDIR)); } else{ $filename = $this->_filename; } // Re-acquire the FTP connection. Core will reset the cwd back to root upon doing this. // This is required because mkdir may change directories. $ftp = \Core\ftp(); // FTP requires a filename, not data... // WELL how bout that! I happen to have a local filename ;) if (!ftp_put($ftp, $filename, $localfilename, FTP_BINARY)) { throw new \Exception(error_get_last()['message']); } if (!ftp_chmod($ftp, $mode, $filename)){ throw new \Exception(error_get_last()['message']); } // woot... return true; } }
/** * Make a copy of a source Filestore\File into this Filestore\File. * * (Generally only useful internally) * * @param Filestore\File $src Source file backend * @param bool $overwrite true to overwrite existing file * * @throws \Exception * @return bool True or False if succeeded. */ public function copyFrom(Filestore\File $src, $overwrite = false) { // Don't overwrite existing files unless told otherwise... if (!$overwrite) { $c = 0; $ext = $this->getExtension(); $base = $this->getBaseFilename(true); $dir = dirname($this->_filename); $prefix = $dir . '/' . $base; $suffix = (($ext == '') ? '' : '.' . $ext); $thathash = $src->getHash(); $f = $prefix . $suffix; while(file_exists($f) && md5_file($f) != $thathash){ $f = $prefix . ' (' . ++$c . ')' . $suffix; } $this->_filename = $f; } // And do the actual copy! // To save memory, try to use as low-level functions as possible. $localfilename = $src->getLocalFilename(); $localhash = $src->getHash(); $localmodified = $src->getMTime(); $localsize = $src->getFilesize(); // Resolve it from its default. // This is provided from a config define, (probably). $mode = (defined('DEFAULT_FILE_PERMS') ? DEFAULT_FILE_PERMS : 0644); // Make sure the directory exists first! $this->_mkdir(dirname($this->_filename), null, true); // FTP requires a filename, not data... // WELL how bout that! I happen to have a local filename ;) if (!ftp_put($this->_ftp->getConn(), $this->_filename, $localfilename, FTP_BINARY)) { throw new \Exception(error_get_last()['message']); } if (!ftp_chmod($this->_ftp->getConn(), $mode, $this->_filename)){ throw new \Exception(error_get_last()['message']); } // Don't forget to save the metadata for this file! $filename = $this->getFilename(); $this->_ftp->setFileHash($filename, $localhash); $this->_ftp->setFileModified($filename, $localmodified); $this->_ftp->setFileSize($filename, $localsize); // woot... return true; }
/** * Get an array of the various resize components from a given dimension set. * These include: width, height, mode, key. * * @param string|int $dimensions * @param File $file * * @return array */ function get_resized_key_components($dimensions, $file){ // The legacy support for simply a number. if (is_numeric($dimensions)) { $width = $dimensions; $height = $dimensions; $mode = ''; } elseif ($dimensions === null) { $width = 300; $height = 300; $mode = ''; } elseif($dimensions === false){ $width = false; $height = false; $mode = ''; } else { // Allow some special modifiers. if(strpos($dimensions, '^') !== false){ // Fit the smallest dimension instead of the largest, (useful for overflow tricks) $mode = '^'; $dimensions = str_replace('^', '', $dimensions); } elseif(strpos($dimensions, '!') !== false){ // Absolutely resize, regardless of aspect ratio $mode = '!'; $dimensions = str_replace('!', '', $dimensions); } elseif(strpos($dimensions, '>') !== false){ // Only increase images. $mode = '>'; $dimensions = str_replace('>', '', $dimensions); } elseif(strpos($dimensions, '<') !== false){ // Only decrease images. $mode = '<'; $dimensions = str_replace('<', '', $dimensions); } else{ // Default mode $mode = ''; } // New method. Split on the "x" and that should give me the width/height. $vals = explode('x', strtolower($dimensions)); $width = (int)$vals[0]; $height = (int)$vals[1]; } $ext = $file->getExtension(); // Ensure that an extension is used if none present, (may happen with temporary files). if(!$ext){ $ext = mimetype_to_extension($file->getMimetype()); } // The basename is for SEO purposes, that way even resized images still contain the filename. // The hash is just to ensure that no two files conflict, ie: /public/a/file1.png and /public/b/file1.png // might conflict without this hash. // Finally, the width and height dimensions are there just because as well; it gives more of a human // touch to the file. :p // Also, keep the original file extension, this way PNGs remain PNGs, GIFs remain GIFs, JPEGs remain JPEGs. // This is critical particularly when it comes to animated GIFs. $key = str_replace(' ', '-', $file->getBasename(true)) . '-' . $file->getHash() . '-' . $width . 'x' . $height . $mode . '.' . $ext; // The directory can be used with the new File backend to create this file in a correctly nested subdirectory. $dir = dirname($file->getFilename(false)) . '/'; if(substr($dir, 0, 7) == 'public/'){ // Replace the necessary prefix with a more useful one. // Anything within public/ needs to be remapped to public/tmp $dir = 'public/tmp/' . substr($dir, 7); } else{ // Everything else gets prepended to public/tmp/ // so if the original file is in themes/blah/imgs/blah.jpg, // it will be copied to public/tmp/blah.jpg $dir = 'public/tmp/'; } return array( 'width' => $width, 'height' => $height, 'mode' => $mode, 'key' => $key, 'ext' => $ext, 'dir' => $dir, ); }