/** * Verify the signature on a given file * * If only one argument is provided, it is expected that file contains both the file and signature as an attached sig. * * If two arguments are provided, the detached signature is the first argument and the content to verify is the second. * * @throws \Exception * * @param string|\Core\Filestore\File $file Filename or File object of the file to verify * @param string|\Core\Filestore\File $verifyFile Filename or File object of any detached signature * * @return Signature */ public function verifyFileSignature($file, $verifyFile = null){ if($file instanceof \Core\Filestore\File){ $filename = $file->getFilename(); } else{ $filename = $file; } if(!file_exists($filename)){ throw new \Exception('Requested file does not exist, unable to verify signature!'); } if($verifyFile === null){ // Standard attached sig $result = $this->_exec('--with-fingerprint --batch --no-tty --verify ' . escapeshellarg($filename)); } else{ // Detached signature if($verifyFile instanceof \Core\Filestore\File){ $sourceFilename = $verifyFile->getFilename(); } else{ $sourceFilename = $verifyFile; } $result = $this->_exec('--with-fingerprint --batch --no-tty --verify ' . escapeshellarg($filename) . ' ' . escapeshellarg($sourceFilename)); } // If the result failed, then nothing else to do here. if($result['return'] !== 0){ throw new \Exception($result['error']); } // Else, the calling script may want to know the results of the verification, eg: the key and date. // The metadata here is send to STDERR. _Shrugs_ $sig = new Signature(); $sig->_parseOutputText($result['error']); return $sig; }
/** * Add a file as an attachment! * * @param \Core\Filestore\File $file * * @throws phpmailerException */ public function addAttachment(\Core\Filestore\File $file){ $this->getMailer()->AddAttachment( $file->getFilename(), // Full Path $file->getBasename(), // Base Filename (to be exposed in client) 'base64', // Yup, just do this $file->getMimetype() // Mimetype, try to use correct hinting for client ); }
/** * 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, ); }
/** * Resize this image and save the output as another File object. * * This is used on conjunction with getPreview* and getQuickPreview. * QuickPreview creates the destination file in the correct directory * and getPreview* methods request the actual resizing. * * @param Filestore\File $file The destination file * @param int $width Width of the final image (in px) * @param int $height Height of the final image (in px) * @param string $mode Mode (part of the geometry) */ private function _resizeTo(Filestore\File $file, $width, $height, $mode){ if(!$this->isImage()){ // :/ return; } \Core\Utilities\Logger\write_debug('Resizing image ' . $this->getFilename('') . ' to ' . $width . 'x' . $height . $mode); $m = $this->getMimetype(); // Make sure the directory of the destination file exists! // By touching the file, Core will create all parent directories as necessary. $file->putContents(''); if($m == 'image/gif' && exec('which convert 2>/dev/null')){ // The GIF resizer handles EVERYTHING :) // Granted of course, that imagemagick's convert is available on the server. $resize = escapeshellarg($mode . $width . 'x' . $height); exec('convert ' . escapeshellarg($this->getFilename()) . ' -resize ' . $resize . ' ' . escapeshellarg($file->getFilename())); \Core\Utilities\Logger\write_debug('Resizing complete (via convert)'); return; } // Traditional resizing logic. switch ($m) { case 'image/jpeg': $thumbType = 'JPEG'; $thumbWidth = $width; $thumbHeight = $height; if($width <= 200 && $height <= 200 && function_exists('exif_thumbnail')){ // Try to write out from the thumbnail img instead of the full size. // This is done to increase server performance. // eg: resizing a 5MB JPEG can take upwards of 50-100ms, // whereas the embedded thumbnail will take only 2-10ms. // Not to mention professional JPEG management tools such as PS and Gimp // produce marginally higher-quality thumbnails than GD will. // (The resulting filesize is negligible.) // Of course if the requested image is larger than a thumbnail size, (200x200 in this case), // using the thumbnail is counter-productive! $img = exif_thumbnail($this->getFilename(), $thumbWidth, $thumbHeight, $thumbType); if($img){ \Core\Utilities\Logger\write_debug('JPEG has thumbnail data of ' . $thumbWidth . 'x' . $thumbHeight . '!'); $file->putContents($img); $img = imagecreatefromjpeg($file->getFilename()); } else{ $img = imagecreatefromjpeg($this->getFilename()); } } else{ $img = imagecreatefromjpeg($this->getFilename()); } break; case 'image/png': $img = imagecreatefrompng($this->getFilename()); break; case 'image/gif': $img = imagecreatefromgif($this->getFilename()); break; default: // Hmmm... \Core\Utilities\Logger\write_debug('Resizing complete (failed, not sure what it was)'); return; } if ($img) { $sW = imagesx($img); $sH = imagesy($img); $nW = $sW; $nH = $sH; switch($mode){ // Standard mode, images are scaled down (only) while preserving aspect ratio case '': case '<': if ($nW > $width) { $nH = $width * $sH / $sW; $nW = $width; } if ($nH > $height) { $nW = $height * $sW / $sH; $nH = $height; } break; // Only resize up case '>': if ($nW < $width) { $nH = $width * $sH / $sW; $nW = $width; } if ($nH < $height) { $nW = $height * $sW / $sH; $nH = $height; } break; // Resize to new size, regardless about aspect ratio case '!': $nW = $width; $nH = $height; break; // Resize image based on smallest dimension case '^': $ratioheight = $sW / $height; $ratiowidth = $sH / $width; if($ratioheight > 1 && $ratiowidth > 1){ // The image is larger than any of the dimensions, I can use the reduction logic. if(($width * $sH / $sW) > ($height * $sW / $sH)){ $nH = $width * $sH / $sW; $nW = $width; } else{ $nH = $height; $nW = $height * $sW / $sH; } } elseif($ratiowidth > $ratioheight){ // The image needs to be increased in size, this logic is slightly different. $nW = $width; $nH = round($width * $sH / $sW); } else{ $nH = $height; $nW = round($height * $sW / $sH); } } // If it's a JPEG, try to find the original thumbnail. /*if(false && $m == 'image/jpeg'){ $type = 'JPEG'; $img = exif_thumbnail($this->getFilename(), $nW, $nH, $type); $file->putContents($img); return; }*/ $img2 = imagecreatetruecolor($nW, $nH); imagealphablending($img2, false); imagesavealpha($img2, true); imagealphablending($img, true); // Assign a transparency color. //$trans = imagecolorallocatealpha($img2, 0, 0, 0, 0); //imagefill($img2, 0, 0, $trans); imagecopyresampled($img2, $img, 0, 0, 0, 0, $nW, $nH, $sW, $sH); imagedestroy($img); switch ($m) { case 'image/jpeg': imagejpeg($img2, $file->getFilename(), 60); \Core\Utilities\Logger\write_debug('Resizing complete (via imagejpeg)'); break; case 'image/png': imagepng($img2, $file->getFilename(), 9); \Core\Utilities\Logger\write_debug('Resizing complete (via imagepng)'); break; case 'image/gif': imagegif($img2, $file->getFilename()); \Core\Utilities\Logger\write_debug('Resizing complete (via imagegif)'); break; default: // Hmmm... \Core\Utilities\Logger\write_debug('Resizing complete (failed, not sure what it was)'); return; } } }
/** * Save this component metadata back to its XML file. * Useful in packager scripts. */ public function save($minified = false) { // Set the schema version to the newest API version. $this->_xmlloader->setSchema('http://corepl.us/api/2_4/component.dtd'); // Ensure there's a required namespace on the root node. $this->_xmlloader->getRootDOM()->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); // Hack // If there is an empty smartydir set, don't let that get saved. if(!$this->getSmartyPluginDirectory()){ $this->_xmlloader->removeElements('//smartyplugins'); } /* /////////////// Handle the hard-set pages, ie: admin ones \\\\\\\\\\\\\ if(!isset($viewclasses)) $viewclasses = array(); foreach($viewclasses as $c){ // Should end in Controller. if(strlen($c) - strpos($c, 'Controller') == 10) $c = substr($c, 0, -10); $data = Dataset::Init()->table('page')->select('*')->where("baseurl = /$c", 'admin=1', 'fuzzy=0')->execute(); //$rs = DB::Execute("SELECT * FROM " . DB_PREFIX . "page WHERE ( `baseurl` = '/$c' OR `baseurl` LIKE '/$c/%' ) AND `fuzzy` = '0' AND `admin` = '1'"); foreach($data as $row){ $node = $this->_xmlloader->getElement('/pages/page[@baseurl="' . $row['baseurl'] . '"]'); $node->setAttribute('admin', $row['admin']); $node->setAttribute('widget', $row['widget']); $node->setAttribute('access', $row['access']); $node->setAttribute('title', $row['title']); } $data = Dataset::Init()->table('page')->select('*')->where("baseurl LIKE /$c/%", 'admin=1', 'fuzzy=0')->execute(); //$rs = DB::Execute("SELECT * FROM " . DB_PREFIX . "page WHERE ( `baseurl` = '/$c' OR `baseurl` LIKE '/$c/%' ) AND `fuzzy` = '0' AND `admin` = '1'"); foreach($data as $row){ $node = $this->_xmlloader->getElement('/pages/page[@baseurl="' . $row['baseurl'] . '"]'); $node->setAttribute('admin', $row['admin']); $node->setAttribute('widget', $row['widget']); $node->setAttribute('access', $row['access']); $node->setAttribute('title', $row['title']); } } */ /* /////////////////////// Handle the config options \\\\\\\\\\\\\\\\\\\\\ $data = Dataset::Init()->table('config')->select('*')->where('key LIKE /' . $this->getName() . '/%')->execute(); //$rs = DB::Execute("SELECT * FROM " . DB_PREFIX . "config WHERE `key` LIKE '/" . $this->getName() . "/%'"); foreach($data as $row){ $node = $this->_xmlloader->getElement('/configs/config[@key="' . $row['key'] . '"]'); $node->setAttribute('type', $row['type']); $node->setAttribute('default', $row['default_value']); $node->setAttribute('description', $row['description']); if($row['options']) $node->setAttribute('options', $row['options']); else $node->removeAttribute('options'); } */ // This needs to be the final step... write the XML doc back to the file. $XMLFilename = $this->_file->getFilename(); //echo $this->asPrettyXML(); // DEBUG // if ($minified) { file_put_contents($XMLFilename, $this->_xmlloader->asMinifiedXML()); } else { file_put_contents($XMLFilename, $this->_xmlloader->asPrettyXML()); } }