/** * DOCUMENT ME * @param mixed $arguments * @param mixed $options */ protected function execute($arguments = array(), $options = array()) { $scriptFile = aFiles::getTemporaryFilename(); $out = fopen($scriptFile, "w"); $server = $arguments['server']; $data = parse_ini_file($this->configuration->getRootDir() . '/config/properties.ini', true); if (!isset($data[$server])) { throw new sfException("{$server} does not exist in config/properties.ini. Examples: staging, production\n"); } $data = $data[$server]; $cmd = "ssh "; if (isset($data['port'])) { $cmd .= "-p " . $data['port']; } if (isset($data['user'])) { $cmd .= " -l " . $data['user']; } $cmd .= " " . $data['host']; $dir = $data['dir']; $user = $data['user']; $host = $data['host']; $escapedDir = escapeshellarg($dir); $cd = escapeshellcmd("cd {$escapedDir}"); fwrite($out, <<<EOM spawn {$cmd} stty -echo expect password: send_user -- "Password for {$user}@{$host}: " expect_user -re "(.*)\\n" send_user "\\n" stty echo set password \$expect_out(1,string) send "\$password\\n" expect "\\\\\$" send "{$cd}\\n" interact EOM ); passthru("expect {$scriptFile}"); unlink($scriptFile); }
public function executeEditVideo(sfRequest $request) { $this->forward404Unless(aMediaTools::userHasUploadPrivilege()); $item = null; $this->slug = false; if ($request->hasParameter('slug')) { $item = $this->getItem(); $this->slug = $item->getSlug(); } if ($item) { $this->forward404Unless($item->userHasPrivilege('edit')); } $this->item = $item; $subclass = 'aMediaVideoYoutubeForm'; $embed = false; $parameters = $request->getParameter('a_media_item'); if (aMediaTools::getOption('embed_codes') && ($item && strlen($item->embed) || isset($parameters['embed']))) { $subclass = 'aMediaVideoEmbedForm'; $embed = true; } $this->form = new $subclass($item); if ($parameters) { $files = $request->getFiles('a_media_item'); $this->form->bind($parameters, $files); do { // first_pass forces the user to interact with the form // at least once. Used when we're coming from a // YouTube search and we already technically have a // valid form but want the user to think about whether // the title is adequate and perhaps add a description, // tags, etc. if ($this->hasRequestParameter('first_pass') || !$this->form->isValid()) { break; } // TODO: this is pretty awful factoring, I should have separate actions // and migrate more of this code into the model layer if ($embed) { $embed = $this->form->getValue("embed"); $thumbnail = $this->form->getValue('thumbnail'); // The base implementation for saving files gets confused when // $file is not set, a situation that our code tolerates as useful // because if you're updating a record containing an image you // often don't need to submit a new one. unset($this->form['thumbnail']); $object = $this->form->getObject(); if ($thumbnail) { $object->preSaveImage($thumbnail->getTempName()); } $this->form->save(); if ($thumbnail) { $object->saveImage($thumbnail->getTempName()); } } else { $url = $this->form->getValue("service_url"); // TODO: migrate this into the model and a // YouTube-specific support class if (!preg_match("/youtube.com.*\\?.*v=([\\w\\-\\+]+)/", $url, $matches)) { $this->serviceError = true; break; } // YouTube thumbnails are always JPEG $format = 'jpg'; $videoid = $matches[1]; $feed = "http://gdata.youtube.com/feeds/api/videos/{$videoid}"; $entry = simplexml_load_file($feed); // get nodes in media: namespace for media information $media = $entry->children('http://search.yahoo.com/mrss/'); // get a more canonical video player URL $attrs = $media->group->player->attributes(); $canonicalUrl = $attrs['url']; // get biggest video thumbnail foreach ($media->group->thumbnail as $thumbnail) { $attrs = $thumbnail->attributes(); if (!isset($widest) || $attrs['width'] + 0 > $widest['width'] + 0) { $widest = $attrs; } } // The YouTube API doesn't report the original width and height of // the video stream, so we use the largest thumbnail, which in practice // is the same thing on YouTube. if (isset($widest)) { $thumbnail = $widest['url']; // Turn them into actual numbers instead of weird XML wrapper things $width = $widest['width'] + 0; $height = $widest['height'] + 0; } if (!isset($thumbnail)) { $this->serviceError = true; break; } // Grab a local copy of the thumbnail, and get the pain // over with all at once in a predictable way if // the service provider fails to give it to us. $thumbnailCopy = aFiles::getTemporaryFilename(); if (!copy($thumbnail, $thumbnailCopy)) { $this->serviceError = true; break; } $object = $this->form->getObject(); $new = !$object->getId(); $object->preSaveImage($thumbnailCopy); $object->setServiceUrl($url); $this->form->save(); $object->saveImage($thumbnailCopy); unlink($thumbnailCopy); } return $this->redirect("aMedia/resumeWithPage"); } while (false); } }
/** * DOCUMENT ME * @param mixed $arguments * @param mixed $options */ protected function execute($arguments = array(), $options = array()) { // We need a basic context so we can call helpers to format text $context = sfContext::createInstance($this->configuration); // initialize the database connection $databaseManager = new sfDatabaseManager($this->configuration); $connection = $databaseManager->getDatabase($options['connection'] ? $options['connection'] : null)->getConnection(); // PDO connection not so useful, get the doctrine one $conn = Doctrine_Manager::connection(); $accounts = Doctrine::getTable('aEmbedMediaAccount')->findAll(); foreach ($accounts as $a) { $perPage = 50; $service = aMediaTools::getEmbedService($a->service); if (!$service) { // An account for a service that has been deconfigured continue; } $total = null; $page = 1; $serviceUrls = array(); while (true) { $results = $service->browseUser($a->username, $page, $perPage); if ($results === false) { // We hit the rate limit, the account is bad, etc. Just // be tolerant and retry later. Would be nice to distinguish // these cases but it's not that hard to figure out an // account is gone break; } foreach ($results['results'] as $result) { $serviceUrls[] = $result['url']; } // We hit the end of the results for this user if (!count($results['results'])) { break; } $page++; } if (count($serviceUrls)) { $existingServiceUrls = Doctrine::getTable('aMediaItem')->createQuery('m')->select('m.service_url')->andWhereIn('m.service_url', $serviceUrls)->execute(array(), Doctrine::HYDRATE_SINGLE_SCALAR); } else { $existingServiceUrls = array(); } $existingServiceUrls = array_flip($existingServiceUrls); foreach ($serviceUrls as $serviceUrl) { if (!isset($existingServiceUrls[$serviceUrl])) { // If Doctrine becomes a performance problem I could use PDO // and set lucene_dirty to let that clean itself up later $id = $service->getIdFromUrl($serviceUrl); $info = $service->getInfo($id); if (!$info) { // We are not actually allowed meaningful access to this video. Password protected for example continue; } $item = new aMediaItem(); $item->setTitle($info['title']); // We want tags to be lower case, and slashes break routes in most server configs. $info['tags'] = str_replace('/', '-', aString::strtolower($info['tags'])); $item->setTags($info['tags']); $item->setDescription(aHtml::textToHtml($info['description'])); $item->setCredit($info['credit']); $item->setServiceUrl($info['url']); $item->setType($service->getType()); // The dance is this: get the thumbnail if there is one; // call preSaveFile to learn the width, height and format // before saving; save; and then saveFile to copy it to a // filename based on the slug, which is unknown until after save $thumbnail = $service->getThumbnail($id); if ($thumbnail) { // Grab a local copy of the thumbnail, and get the pain // over with all at once in a predictable way if // the service provider fails to give it to us. $thumbnailCopy = aFiles::getTemporaryFilename(); if (copy($thumbnail, $thumbnailCopy)) { $item->preSaveFile($thumbnailCopy); } } $item->save(); if ($thumbnail) { $item->saveFile($thumbnailCopy); } $item->free(); } } } }
/** * Retrieves what you really want to know about an image file, PDFs included, * before making calls such as the above based on good information. * Returns as follows: * array('format' => 'file extension: gif, jpg, png or pdf', 'width' => width in pixels, 'height' => height in pixels); * $format is the recommended file extension based on the actual file type, not the user's (possibly totally false or absent) * claimed file extension. * If the file does not have a valid header identifying it as one of these types, false is returned. * If the 'format-only' option is true, only the format field is returned. This is much faster if the * file is a PDF. * @param mixed $file * @param mixed $options * @return mixed */ public static function getInfo($file, $options = array()) { $formatOnly = isset($options['format-only']) && $options['format-only']; $result = array(); $in = fopen($file, "rb"); $data = fread($in, 4); fclose($in); if ($data === '%PDF') { // format-only if ($formatOnly || !aImageConverter::supportsInput('pdf')) { // All we can do is confirm the format and allow // download of the original (which, for PDF, is // usually fine) return array('format' => 'pdf'); } $result['format'] = 'pdf'; $path = sfConfig::get("app_aimageconverter_path", ""); if (strlen($path)) { if (!preg_match("/\\/\$/", $path)) { $path .= "/"; } } // Bounding box goes to stderr, not stdout! Charming // 5 second timeout for reading dimensions. Keeps us from getting stuck on // PDFs that just barely work in Adobe but are noncompliant and hang ghostscript. // Read the output one line at a time so we can catch the happy // bounding box message without hanging // Problem: this doesn't work. We regain control but the process won't die for some reason. It helps // with import but for now go with the simpler standard invocation and hope they fix gs // $cmd = "(PATH=$path:\$PATH; export PATH; gs -sDEVICE=bbox -dNOPAUSE -dFirstPage=1 -dLastPage=1 -r100 -q " . escapeshellarg($file) . " -c quit ) 2>&1"; $cmd = "( PATH={$path}:\$PATH; export PATH; gs -sDEVICE=bbox -dNOPAUSE -dFirstPage=1 -dLastPage=1 -r100 -q " . escapeshellarg($file) . " -c quit & GS=\$!; ( sleep 5; kill \$GS ) & TIMEOUT=\$!; wait \$GS; kill \$TIMEOUT ) 2>&1"; // For some reason system() does not get the same result when killing subshells as I get when executing // $cmd directly. I don't know why this is this the case but it's easily reproduced $script = aFiles::getTemporaryFilename() . '.sh'; file_put_contents($script, $cmd); $cmd = "/bin/sh " . escapeshellarg($script); $in = popen($cmd, "r"); $data = stream_get_contents($in); pclose($in); // Actual nonfatal errors in the bbox output mean it's not safe to just // read this naively with fscanf, look for the good part if (preg_match("/%%BoundingBox: \\d+ \\d+ (\\d+) (\\d+)/", $data, $matches)) { $result['width'] = $matches[1]; $result['height'] = $matches[2]; } if (!isset($result['width'])) { // Bad PDF return false; } return $result; } else { $formats = array(IMAGETYPE_JPEG => "jpg", IMAGETYPE_PNG => "png", IMAGETYPE_GIF => "gif"); $data = getimagesize($file); if (count($data) < 3) { return false; } if (!isset($formats[$data[2]])) { return false; } $format = $formats[$data[2]]; $result['format'] = $format; if ($formatOnly) { return $result; } $result['width'] = $data[0]; $result['height'] = $data[1]; if ($format === 'jpg') { // Some EXIF orientations swap width and height switch (aImageConverter::getRotation($file, $data)) { case 5: // vertical flip + 90 rotate right // vertical flip + 90 rotate right case 6: // 90 rotate right // 90 rotate right case 7: // horizontal flip + 90 rotate right // horizontal flip + 90 rotate right case 8: // 90 rotate left $result['width'] = $data[1]; $result['height'] = $data[0]; break; } } return $result; } }
/** * Finds or adds a video without the overhead of a proper Doctrine save. * @param array $info * @return mixed */ protected function findOrAddVideo($info) { $mediaId = null; $slug = null; if (!isset($info['title'])) { $info['title'] = 'Imported video'; } $slug = aTools::slugify(!empty($info['title']) ? $info['title'] : (!empty($info['service_url']) ? $info['service_url'] : md5($info['embed']))); $result = $this->sql->query('SELECT id FROM a_media_item WHERE slug = :slug', array('slug' => $slug)); if (isset($result[0]['id'])) { $mediaId = $result[0]['id']; } else { $mediaItem = new aMediaItem(); foreach ($info as $key => $value) { if ($key !== 'tags') { $mediaItem[$key] = $value; } } if (empty($mediaItem['title'])) { $mediaItem->setTitle($slug); } else { $mediaItem->setTitle($info['title']); } $mediaItem->setSlug($slug); $mediaItem->setType('video'); if ($mediaItem->service_url) { $service = aMediaTools::getEmbedService($mediaItem->service_url); $id = $service->getIdFromUrl($mediaItem->service_url); if ($service->supports('thumbnail')) { $filename = $service->getThumbnail($id); if ($filename) { // saveFile can't handle a nonlocal file directly, so // copy to a temporary file first $bad = isset($this->failedMedia[$filename]); if (!$bad) { $tmpFile = aFiles::getTemporaryFilename(); try { if (!copy($filename, $tmpFile)) { throw new sfException(sprintf('Could not copy file: %s', $src)); } if (!$mediaItem->saveFile($tmpFile)) { throw new sfException(sprintf('Could not save file: %s', $src)); } } catch (Exception $e) { $this->failedMedia[$filename] = true; } unlink($tmpFile); } } } } $this->sql->fastSaveMediaItem($mediaItem); if (count($info['tags'])) { $this->sql->fastSaveTags('aMediaItem', $mediaItem->id, $info['tags']); } $mediaId = $mediaItem->id; $mediaItem->free(true); } return $mediaId; }
/** * DOCUMENT ME * @param sfWebRequest $request * @return mixed */ public function executeEditVideo(sfWebRequest $request) { $this->forward404Unless(aMediaTools::userHasUploadPrivilege()); $item = null; $this->slug = false; $this->popularTags = PluginTagTable::getPopulars(null, array('sort_by_popularity' => true), false, 10); if (sfConfig::get('app_a_all_tags', true)) { $this->allTags = PluginTagTable::getAllTagNameWithCount(); } else { $this->allTags = array(); } if ($request->hasParameter('slug')) { $item = $this->getItem(); $this->slug = $item->getSlug(); } if ($item) { $this->forward404Unless($item->userHasPrivilege('edit')); } $this->item = $item; $embed = false; $parameters = $request->getParameter('a_media_item'); if ($parameters) { $files = $request->getFiles('a_media_item'); $this->form = new aMediaVideoForm($item); if (isset($parameters['embed'])) { // We need to do some prevalidation of the embed code so we can prestuff the // file, title, tags and description widgets $result = $this->form->classifyEmbed($parameters['embed']); if (isset($result['thumbnail'])) { $thumbnail = $result['thumbnail']; if (!isset($parameters['title']) && !isset($parameters['tags']) && !isset($parameters['description']) && !isset($parameters['credit'])) { $parameters['title'] = $result['serviceInfo']['title']; // We want tags to be lower case, and slashes break routes in most server configs. $parameters['tags'] = str_replace('/', '-', aString::strtolower($result['serviceInfo']['tags'])); $parameters['description'] = aHtml::textToHtml($result['serviceInfo']['description']); $parameters['credit'] = $result['serviceInfo']['credit']; } } } // On the first pass with a youtube video we just make the service's thumbnail the // default thumbnail. We don't force them to use it. This allows more code reuse // (Moving this after the bind is necessary to keep it from being overwritten) if (isset($thumbnail)) { // OMG file widgets can't have defaults! Ah, but our persistent file widget can $tmpFile = aFiles::getTemporaryFilename(); file_put_contents($tmpFile, file_get_contents($thumbnail)); $vfp = new aValidatorFilePersistent(); $guid = aGuid::generate(); $vfp->clean(array('newfile' => array('tmp_name' => $tmpFile), 'persistid' => $guid)); // You can't mess about with widget defaults after a bind, but you // *can* tweak the array you're about to bind with $parameters['file']['persistid'] = $guid; } $this->form->bind($parameters, $files); do { // first_pass forces the user to interact with the form // at least once. Used when we're coming from a // YouTube search and we already technically have a // valid form but want the user to think about whether // the title is adequate and perhaps add a description, // tags, etc. if ($this->hasRequestParameter('first_pass') || !$this->form->isValid()) { break; } $thumbnail = $this->form->getValue('file'); // The base implementation for saving files gets confused when // $file is not set, a situation that our code tolerates as useful // because if you're updating a record containing an image you // often don't need to submit a new one. unset($this->form['file']); $object = $this->form->getObject(); if ($thumbnail) { $object->preSaveFile($thumbnail->getTempName()); } $this->form->save(); if ($thumbnail) { $object->saveFile($thumbnail->getTempName()); } return $this->redirect("aMedia/resumeWithPage"); } while (false); } }