public function preSaveImage($file) { // Refactored into aImageConverter for easier reuse of this should-be-in-PHP functionality $info = aImageConverter::getInfo($file); if ($info) { $this->width = $info['width']; $this->height = $info['height']; $this->format = $info['format']; $this->clearImageCache(true); return true; } else { return false; } }
public function preSaveImage($file) { // Refactored into aImageConverter for easier reuse of this should-be-in-PHP functionality $info = aImageConverter::getInfo($file); if ($info) { // Sometimes we store formats we can't get dimensions for on this particular platform if (isset($info['width'])) { $this->width = $info['width']; } if (isset($info['height'])) { $this->height = $info['height']; } $this->format = $info['format']; $this->clearImageCache(true); return true; } else { return false; } }
/** * * Guess the file mime type with aImageConverter's getInfo method, which uses imagesize and * magic numbers to be more robust than relying on a lot of badly configured external tools * @param string $file The absolute path of a file * @return string The mime type of the file (null if not guessable) */ protected function guessFromImageconverter($file) { $info = aImageConverter::getInfo($file); if (!$info) { return null; } $formats = array('jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'pdf' => 'application/pdf'); if (isset($formats[$info['format']])) { return $formats[$info['format']]; } return null; }
public function go() { $dir_iterator = new RecursiveDirectoryIterator($this->dir); $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST); $count = 0; foreach ($iterator as $sfile) { if ($sfile->isFile()) { $file = $sfile->getPathname(); if (preg_match('/(^|\\/)\\./', $file)) { # Silently ignore all dot folders to avoid trouble with svn and friends $this->giveFeedback("info", "Ignoring dotfile", $file); continue; } $pathinfo = pathinfo($file); if ($pathinfo['filename'] === 'Thumbs.db') { continue; } $info = aImageConverter::getInfo($file); if ($info === false) { $this->giveFeedback("warning", "Not supported or corrupt", $file); continue; } $item = new aMediaItem(); if ($info['format'] === 'pdf') { $item->type = 'pdf'; } else { $item->type = 'image'; } // Split it up to make tags out of the portion of the path that isn't dir (i.e. the folder structure they used) $dir = $this->dir; $dir = preg_replace('/\\/$/', '', $dir) . '/'; $relevant = preg_replace('/^' . preg_quote($dir, '/') . '/', '', $file); // TODO: not Microsoft-friendly, might matter in some setting $components = preg_split('/\\//', $relevant); $tags = array_slice($components, 0, count($components) - 1); foreach ($tags as &$tag) { // We don't strictly need to be this harsh, but it's safe and definitely // takes care of some things we definitely can't allow, like periods // (which cause mod_rewrite problems with pretty Symfony URLs). // TODO: clean it up in a nicer way without being UTF8-clueless // (aTools::slugify is UTF8-safe) $tag = aTools::slugify($tag); } $item->title = aTools::slugify($pathinfo['filename']); $item->setTags($tags); if (!strlen($item->title)) { $this->giveFeedback("error", "Files must have a basename", $file); continue; } // The preSaveImage / save / saveImage dance is necessary because // the sluggable behavior doesn't kick in until save and the image file // needs a slug based filename. if (!$item->preSaveImage($file)) { $this->giveFeedback("error", "Save failed", $file); continue; } $item->save(); if (!$item->saveImage($file)) { $this->giveFeedback("error", "Save failed", $file); $item->delete(); continue; } unlink($file); $count++; $this->giveFeedback("completed", $count, $file); } } $this->giveFeedback("total", $count); }
/** * DOCUMENT ME * @param mixed $value * @param mixed $imagePreview * @return mixed */ public function getPreviewUrl($value, $imagePreview = array()) { list($exists, $persistid, $extension) = $this->getExistsPersistidAndExtension($value); // hasOption just verifies that the option is valid, it doesn't check what, // if anything, was passed. Thanks to Lucjan Wilczewski $defaultPreview = $this->hasOption('default-preview') ? $this->getOption('default-preview') : false; if ($exists) { $defaultPreview = false; } if ($exists || $defaultPreview) { // Note change of key $urlStem = sfConfig::get('app_aPersistentFileUpload_preview_url', '/uploads/uploaded_image_preview'); $urlStem = sfContext::getInstance()->getRequest()->getRelativeUrlRoot() . $urlStem; // This is the corresponding directory path. You have to override one // if you override the other. You override this one by setting // app_aToolkit_upload_uploaded_image_preview_dir $dir = aFiles::getUploadFolder("uploaded_image_preview"); // While we're here age off stale previews aValidatorFilePersistent::removeOldFiles($dir); if ($exists) { $info = aValidatorFilePersistent::getFileInfo($persistid); $source = $info['tmp_name']; } else { $source = $defaultPreview; } $info = aImageConverter::getInfo($source, array('format-only' => true)); $previewable = false; if ($info && in_array($info['format'], array('jpg', 'png', 'gif'))) { $previewable = true; $info = aImageConverter::getInfo($source); } if ($previewable) { $iwidth = $info['width']; $iheight = $info['height']; // This is safe - based on sniffed file contents and not a user supplied extension $format = $info['format']; $dimensions = aDimensions::constrain($iwidth, $iheight, $format, $imagePreview); // A simple filename reveals less $imagename = "{$persistid}.{$format}"; $url = "{$urlStem}/{$imagename}"; $output = "{$dir}/{$imagename}"; if (isset($info['newfile']) && $info['newfile'] || !file_exists($output)) { if ($imagePreview['resizeType'] === 'c') { $method = 'cropOriginal'; } else { $method = 'scaleToFit'; } sfContext::getInstance()->getLogger()->info("YY calling converter method {$method} width " . $dimensions['width'] . ' height ' . $dimensions['height']); aImageConverter::$method($source, $output, $dimensions['width'], $dimensions['height']); sfContext::getInstance()->getLogger()->info("YY after converter"); } } else { // Don't try to provide an icon alternative to the preview here, // it's better to do that at the project and/or apostrophePlugin level // where we can style it better... the less we fake templating inside // a widget the better. See getFormat $url = false; } return $url; } return false; }
/** * DOCUMENT ME * @param mixed $width * @param mixed $height * @param mixed $resizeType * @param mixed $format * @param mixed $absolute * @param mixed $wmode * @param mixed $autoplay * @param array $options * @return mixed */ public function getEmbedCode($width, $height, $resizeType, $format = 'jpg', $absolute = false, $wmode = 'opaque', $autoplay = false, $options = array()) { if ($height === false) { // We need to scale the height. That requires knowing the true height if (!$this->height) { // Not known yet. This comes up when previewing a video with a service URL that we haven't saved yet if ($this->service_url) { $service = aMediaTools::getEmbedService($this->service_url); $thumbnail = $service->getThumbnail($service->getIdFromUrl($this->service_url)); if ($thumbnail) { $info = aImageConverter::getInfo($thumbnail); if (isset($info['width'])) { $this->width = $info['width']; $this->height = $info['height']; } } } } $height = floor($width * $this->height / $this->width + 0.5); } // Accessible alt title $title = htmlentities($this->getTitle(), ENT_COMPAT, 'UTF-8'); if ($this->getEmbeddable()) { if ($this->service_url) { $service = aMediaTools::getEmbedService($this->service_url); if (!$service) { // Most likely explanation: this service was configured, now it's not. // Don't crash return '<div>Video Service Not Available</div>'; } return $service->embed($service->getIdFromUrl($this->service_url), $width, $height, $title, $wmode, $autoplay); } elseif ($this->embed) { // Solution for non-YouTube videos based on a manually // provided thumbnail and embed code return str_replace(array('_TITLE_', '_WIDTH_', '_HEIGHT_'), array($title, $width, $height, $wmode), $this->embed); } else { throw new sfException('Media item without an embed code or a service url'); } } elseif ($this->getType() == 'image' || $this->getType() == 'pdf') { // Use named routing rule to ensure the desired result (and for speed) return "<img alt=\"{$title}\" width=\"{$width}\" height=\"{$height}\" src='" . htmlspecialchars($this->getImgSrcUrl($width, $height, $resizeType, $format, $absolute, $options)) . "' />"; } else { throw new Exception("Unknown media type in getEmbedCode: " . $this->getType() . " id is " . $this->id . " is new? " . $this->isNew()); } }
/** * @param string $name The element name * @param string $value The value displayed in this widget * (i.e. the browser-side filename submitted * on a previous partially successful * validation of this form) * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes * @param array $errors An array of errors for the field * * @return string An HTML tag string * * @see sfWidgetForm */ public function render($name, $value = null, $attributes = array(), $errors = array()) { $exists = false; if (isset($value['persistid']) && strlen($value['persistid'])) { $persistid = $value['persistid']; $info = aValidatorFilePersistent::getFileInfo($persistid); if ($info) { $exists = true; } } else { // One implementation, not two (to inevitably drift apart) $persistid = aGuid::generate(); } $result = ''; // hasOption just verifies that the option is valid, it doesn't check what, // if anything, was passed. Thanks to Lucjan Wilczewski $preview = $this->hasOption('image-preview') ? $this->getOption('image-preview') : false; $defaultPreview = $this->hasOption('default-preview') ? $this->getOption('default-preview') : false; if ($exists) { $defaultPreview = false; } if ($exists || $defaultPreview) { if ($preview) { // Note change of key $urlStem = sfConfig::get('app_aPersistentFileUpload_preview_url', '/uploads/uploaded_image_preview'); // This is the corresponding directory path. You have to override one // if you override the other. You override this one by setting // app_aToolkit_upload_uploaded_image_preview_dir $dir = aFiles::getUploadFolder("uploaded_image_preview"); // While we're here age off stale previews aValidatorFilePersistent::removeOldFiles($dir); $imagePreview = $this->getOption('image-preview'); if ($exists) { $source = $info['tmp_name']; } else { $source = $defaultPreview; } $info = aImageConverter::getInfo($source); if ($info) { $iwidth = $info['width']; $height = $info['height']; // This is safe - based on sniffed file contents and not a user supplied extension $format = $info['format']; list($iwidth, $iheight) = getimagesize($source); $dimensions = aDimensions::constrain($iwidth, $iheight, $format, $imagePreview); // A simple filename reveals less $imagename = "{$persistid}.{$format}"; $url = "{$urlStem}/{$imagename}"; $output = "{$dir}/{$imagename}"; if (isset($info['newfile']) && $info['newfile'] || !file_exists($output)) { if ($imagePreview['resizeType'] === 'c') { $method = 'cropOriginal'; } else { $method = 'scaleToFit'; } sfContext::getInstance()->getLogger()->info("YY calling converter method {$method} width " . $dimensions['width'] . ' height ' . $dimensions['height']); aImageConverter::$method($source, $output, $dimensions['width'], $dimensions['height']); sfContext::getInstance()->getLogger()->info("YY after converter"); } } if (isset($imagePreview['markup'])) { $markup = $imagePreview['markup']; } else { $markup = '<img src="%s" />'; } $result .= sprintf($markup, $url); } $result .= $this->getOption('existing-html'); } return $result . $this->renderTag('input', array_merge(array('type' => $this->getOption('type'), 'name' => $name . '[newfile]'), $attributes)) . $this->renderTag('input', array('type' => 'hidden', 'name' => $name . '[persistid]', 'value' => $persistid)); }
/** * * preValidateEmbed * @param $value * @return array * @author Thomas Boutell * / */ public function classifyEmbed($value) { // If it is a URL or embed code recognized by one of the services we support, use that service $service = aMediaTools::getEmbedService($value); if ($service) { $id = $service->getIdFromUrl($value); if (!$id) { // Not every service considers URLs and embed codes interchangeable $id = $service->getIdFromEmbed($value); } $serviceInfo = $service->getInfo($id); if (!$serviceInfo) { $this->classifyEmbedResult = array('ok' => false, 'error' => 'That video does not exist or you cannot access it.'); return $this->classifyEmbedResult; } $thumbnail = $service->getThumbnail($id); $info = aImageConverter::getInfo($thumbnail); if (!isset($info['width'])) { $this->classifyEmbedResult = array('ok' => false, 'error' => 'That video exists but the service provider does not allow you to embed it.'); return $this->classifyEmbedResult; } $this->classifyEmbedResult = array('ok' => true, 'thumbnail' => $thumbnail, 'serviceInfo' => $serviceInfo, 'embed' => $service->embed($id, $info['width'], $info['height']), 'width' => $info['width'], 'height' => $info['height'], 'format' => $info['format'], 'serviceUrl' => $service->getUrlFromId($id)); return $this->classifyEmbedResult; } // Don't let this become a way to embed arbitrary HTML $value = trim(strip_tags($value, "<embed><object><param><applet><iframe>")); // Kill any text outside of tags if (preg_match_all("/<.*?>/", $value, $matches)) { $value = implode("", $matches[0]); } else { $value = ''; } if (!strlen($value)) { $this->classifyEmbedResult = array('ok' => false, 'error' => 'A valid embed code or recognized media service URL is required.'); return $this->classifyEmbedResult; } // For existing objects the embed code will already be parameterized, in that situation // we don't try (and fail) to extract the dimensions again if (strpos($value, '_WIDTH_') === false) { // If the width or height is not available, we can't process it correctly if (!preg_match("/width\\s*=\\s*([\"'])(\\d+)\\1/i", $value) || !preg_match("/height\\s*=\\s*([\"'])(\\d+)\\1/i", $value, $matches)) { $this->classifyEmbedResult = array('ok' => false, 'error' => 'No width and height in embed code'); return $this->classifyEmbedResult; } if (preg_match("/width\\s*=\\s*([\"'])(\\d+)\\1/i", $value, $matches)) { $result['width'] = $matches[2]; } if (preg_match("/height\\s*=\\s*([\"'])(\\d+)\\1/i", $value, $matches)) { $result['height'] = $matches[2]; } } else { $result['width'] = $this->getObject()->width; $result['height'] = $this->getObject()->height; } // Put placeholders in the embed/applet/object tags $value = preg_replace(array("/width\\s*=\\s*([\"'])\\d+%?\\1/i", "/height\\s*=\\s*([\"'])\\d+%?\\1/i", "/alt\\s*\\s*([\"']).*?\\1/i"), array("width=\"_WIDTH_\"", "height=\"_HEIGHT_\"", "alt=\"_TITLE_\""), $value); $result['ok'] = true; $result['embed'] = $value; $this->classifyEmbedResult = $result; return $this->classifyEmbedResult; }