/** * @param $manifestData * @param $handle * * @return null */ public static function rollBackFileChanges($manifestData, $handle) { foreach ($manifestData as $row) { if (static::isManifestVersionInfoLine($row)) { continue; } if (static::isManifestMigrationLine($row)) { continue; } $rowData = explode(';', $row); if ($handle == 'craft') { $directory = craft()->path->getAppPath(); } else { $directory = craft()->path->getPluginsPath() . $handle . '/'; } $file = IOHelper::normalizePathSeparators($directory . $rowData[0]); // It's a folder if (static::isManifestLineAFolder($file)) { $folderPath = static::cleanManifestFolderLine($file); if (IOHelper::folderExists($folderPath . '.bak')) { IOHelper::rename($folderPath, $folderPath . '-tmp'); IOHelper::rename($folderPath . '.bak', $folderPath); IOHelper::clearFolder($folderPath . '-tmp'); IOHelper::deleteFolder($folderPath . '-tmp'); } } else { if (IOHelper::fileExists($file . '.bak')) { IOHelper::rename($file . '.bak', $file); } } } }
/** * Includes resources for the Control Panel from the craft/config/diywidget/ folder. */ protected function includeCustomCpResources() { $templatePaths = []; $folderPath = craft()->path->getConfigPath() . 'diywidget/'; if (IOHelper::folderExists($folderPath)) { $filePaths = glob($folderPath . '*.{twig,html,css,js}', GLOB_BRACE); foreach ($filePaths as $filePath) { $pathInFolder = str_replace($folderPath, '', $filePath); $resourcePath = 'config/diywidget/' . $pathInFolder; switch (IOHelper::getExtension($filePath)) { case 'twig': case 'html': $templatePaths[] = $pathInFolder; break; case 'css': craft()->templates->includeCssResource($resourcePath); break; case 'js': craft()->templates->includeJsResource($resourcePath); break; } } } craft()->diyWidget->templatePaths = $templatePaths; }
/** * Initializes the console app by creating the command runner. * * @return null */ public function init() { // Set default timezone to UTC date_default_timezone_set('UTC'); // Import all the built-in components foreach ($this->componentAliases as $alias) { Craft::import($alias); } // Attach our Craft app behavior. $this->attachBehavior('AppBehavior', new AppBehavior()); // Initialize Cache and LogRouter right away (order is important) $this->getComponent('cache'); $this->getComponent('log'); // So we can try to translate Yii framework strings $this->coreMessages->attachEventHandler('onMissingTranslation', array('Craft\\LocalizationHelper', 'findMissingTranslation')); // Set our own custom runtime path. $this->setRuntimePath(craft()->path->getRuntimePath()); // Attach our own custom Logger Craft::setLogger(new Logger()); // No need for these. craft()->log->removeRoute('WebLogRoute'); craft()->log->removeRoute('ProfileLogRoute'); // Load the plugins craft()->plugins->loadPlugins(); // Validate some basics on the database configuration file. craft()->validateDbConfigFile(); // Call parent::init before the plugin console command logic so craft()->commandRunner will be available to us. parent::init(); foreach (craft()->plugins->getPlugins() as $plugin) { $commandsPath = craft()->path->getPluginsPath() . StringHelper::toLowerCase($plugin->getClassHandle()) . '/consolecommands/'; if (IOHelper::folderExists($commandsPath)) { craft()->commandRunner->addCommands(rtrim($commandsPath, '/')); } } }
public function getInputHtml($name, $value) { // Get site templates path $templatesPath = $siteTemplatesPath = craft()->path->getSiteTemplatesPath(); // Check if the templates path is overriden by configuration // TODO: Normalize path $limitToSubfolder = craft()->config->get('templateselectSubfolder'); if ($limitToSubfolder) { $templatesPath = $templatesPath . rtrim($limitToSubfolder, '/') . '/'; } // Check if folder exists, or give error if (!IOHelper::folderExists($templatesPath)) { throw new \InvalidArgumentException('(Template Select) Folder doesn\'t exist: ' . $templatesPath); } // Get folder contents $templates = IOHelper::getFolderContents($templatesPath, TRUE); // Add placeholder for when there is no template selected $filteredTemplates = array('' => Craft::t('No template selected')); // Turn array into ArrayObject $templates = new \ArrayObject($templates); // Iterate over template list // * Remove full path // * Remove folders from list for ($list = $templates->getIterator(); $list->valid(); $list->next()) { $filename = $list->current(); $filename = str_replace($templatesPath, '', $filename); $filenameIncludingSubfolder = $limitToSubfolder ? $limitToSubfolder . $filename : $filename; $isTemplate = preg_match("/(.html|.twig)\$/u", $filename); if ($isTemplate) { $filteredTemplates[$filenameIncludingSubfolder] = $filename; } } // Render field return craft()->templates->render('_includes/forms/select', array('name' => $name, 'value' => $value, 'options' => $filteredTemplates)); }
protected function addResources() { // Get current language and site translations path $language = craft()->language; $path = craft()->path->getSiteTranslationsPath(); // Look for translation file from least to most specific. For example, nl.php gets loaded before nl_nl.php. $translationFiles = array(); $parts = explode('_', $language); $totalParts = count($parts); // If it's Norwegian Bokmål/Nynorsk, add plain ol' Norwegian as a fallback if ($parts[0] === 'nb' || $parts[0] === 'nn') { $translationFiles[] = 'no'; } for ($i = 1; $i <= $totalParts; $i++) { $translationFiles[] = implode('_', array_slice($parts, 0, $i)); } // Get translations $translations = array(); if (IOHelper::folderExists($path)) { foreach ($translationFiles as $file) { $path = $path . $file . '.php'; if (IOHelper::fileExists($path)) { $temp = (include $path); if (is_array($temp)) { // If this is framework data and we're not on en_us, then do some special processing. if (strpos($path, 'framework/i18n/data') !== false && $file !== 'en_us') { $temp = $this->_processFrameworkData($file); } $translations = array_merge($translations, $temp); } } } } if (empty($translations)) { return false; } craft()->templates->includeJs('(function(window){ if (window.Craft) { Craft.translations = $.extend(Craft.translations, ' . json_encode($translations) . '); var selectors = [ "#page-title h1", // Page titles "#crumbs a", // Segments in breadcrumbs ".fld-field > span", // Field names inside FLD ".fld-tab .tab > span", // Tab names inside FLD "#sidebar .heading > span", // CEI heading "#Assets option", // Options inside Asset field settings ], $el; $(selectors.join(",")).each(function () { $el = $(this); $el.text(Craft.t($el.text())); }); } }(window));'); }
/** * @param $downloadPath * @return bool */ public function downloadUpdate($downloadPath) { $et = new Et(static::DownloadUpdate, 240); if (IOHelper::folderExists($downloadPath)) { $downloadPath .= StringHelper::UUID() . '.zip'; } $et->setDestinationFileName($downloadPath); if (($fileName = $et->phoneHome()) !== null) { return $fileName; } return false; }
/** * Returns the field's settings HTML. * * @return string|null */ public function getSettingsHtml() { $configOptions = array('' => Craft::t('Default')); $configPath = craft()->path->getConfigPath() . 'redactor/'; if (IOHelper::folderExists($configPath)) { $configFiles = IOHelper::getFolderContents($configPath, false, '\\.json$'); if (is_array($configFiles)) { foreach ($configFiles as $file) { $configOptions[IOHelper::getFileName($file)] = IOHelper::getFileName($file, false); } } } return craft()->templates->render('_components/fieldtypes/RichText/settings', array('settings' => $this->getSettings(), 'configOptions' => $configOptions)); }
/** * @param string $downloadPath * @param string $md5 * * @return bool */ public function downloadUpdate($downloadPath, $md5) { if (IOHelper::folderExists($downloadPath)) { $downloadPath .= $md5 . '.zip'; } $updateModel = craft()->updates->getUpdates(); $buildVersion = $updateModel->app->latestVersion . '.' . $updateModel->app->latestBuild; $path = 'http://download.buildwithcraft.com/craft/' . $updateModel->app->latestVersion . '/' . $buildVersion . '/Patch/' . $updateModel->app->localBuild . '/' . $md5 . '.zip'; $et = new Et($path, 240); $et->setDestinationFileName($downloadPath); if (($fileName = $et->phoneHome()) !== null) { return $fileName; } return false; }
/** * @inheritDoc ISavableComponentType::getSettingsHtml() * * @return string|null */ public function getSettingsHtml() { $configOptions = array('' => Craft::t('Default')); $configPath = craft()->path->getConfigPath() . 'redactor/'; if (IOHelper::folderExists($configPath)) { $configFiles = IOHelper::getFolderContents($configPath, false, '\\.json$'); if (is_array($configFiles)) { foreach ($configFiles as $file) { $configOptions[IOHelper::getFileName($file)] = IOHelper::getFileName($file, false); } } } $columns = array('text' => Craft::t('Text (stores about 64K)'), 'mediumtext' => Craft::t('MediumText (stores about 4GB)')); return craft()->templates->render('_components/fieldtypes/RichText/settings', array('settings' => $this->getSettings(), 'configOptions' => $configOptions, 'columns' => $columns, 'existing' => !empty($this->model->id))); }
/** * When installed, this plugin converts RichText fields into BetterRedactor * fields. It also creates a folder, craft/config/redactor_plugins, and * populates it with some starting plugins. */ public function onAfterInstall() { craft()->db->createCommand()->update('fields', array('type' => 'BetterRedactor'), array('type' => 'RichText')); $config_folder = craft()->path->getConfigPath() . '/redactor_plugins'; if (!IOHelper::folderExists($config_folder)) { $initial_folder = craft()->path->getPluginsPath() . '/betterredactor/redactor_plugins'; $files = array_filter(scandir($initial_folder), function ($file) use($initial_folder) { return is_file("{$initial_folder}/{$file}"); }); foreach ($files as $file) { if (preg_match('((.js|.css)$)i', $file)) { IOHelper::copyFile("{$initial_folder}/{$file}", "{$config_folder}/{$file}"); } } } }
/** * @param string $action * @param array $params * @return bool */ public function beforeAction($action, $params) { if ($action == 'create') { // If the 1nd dimension is the 1nd index, then we know it's a plugin. No need to make them specify the path. if (isset($params[0][1])) { $plugin = $params[0][1]; $path = craft()->path->getMigrationsPath($plugin); if (!IOHelper::folderExists($path)) { echo 'The migration folder does not exist at ' . $path . ". Creating...\n"; if (!IOHelper::createFolder($path)) { echo 'Sorry... I tried to create the folder, but could not.'; return 1; } else { echo 'Successfully created.'; } } } } $yiiVersion = Craft::getYiiVersion(); echo "\nCraft Migration Tool (based on Yii v{$yiiVersion})\n\n"; return true; }
public function actionLogs() { craft()->config->maxPowerCaptain(); if (IOHelper::folderExists(craft()->path->getLogPath())) { $dateTimePattern = '/^[0-9]{4}\\/[0-9]{2}\\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/'; $logEntries = array(); $currentLogFileName = 'feedme.log'; $currentFullPath = craft()->path->getLogPath() . $currentLogFileName; if (IOHelper::fileExists($currentFullPath)) { // Split the log file's contents up into arrays of individual logs, where each item is an array of // the lines of that log. $contents = IOHelper::getFileContents(craft()->path->getLogPath() . $currentLogFileName); $requests = explode('******************************************************************************************************', $contents); foreach ($requests as $request) { $logChunks = preg_split('/^(\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[(.*?)\\] \\[(.*?)\\] /m', $request, null, PREG_SPLIT_DELIM_CAPTURE); // Ignore the first chunk array_shift($logChunks); // Loop through them $totalChunks = count($logChunks); for ($i = 0; $i < $totalChunks; $i += 4) { $logEntryModel = new LogEntryModel(); $logEntryModel->dateTime = DateTime::createFromFormat('Y/m/d H:i:s', $logChunks[$i]); $logEntryModel->level = $logChunks[$i + 1]; $logEntryModel->category = $logChunks[$i + 2]; $message = $logChunks[$i + 3]; $rowContents = explode("\n", $message); // This is a non-devMode log entry. $logEntryModel->message = str_replace('[Forced]', '', $rowContents[0]); // And save the log entry. $logEntries[] = $logEntryModel; } } } // Put these logs at the top $logEntries = array_reverse($logEntries); $this->renderTemplate('feedme/logs/index', array('logEntries' => $logEntries)); } }
/** * @inheritDoc ISavableComponentType::getSettingsHtml() * * @return string|null */ public function getSettingsHtml() { $configOptions = array('' => Craft::t('Default')); $configPath = craft()->path->getConfigPath() . 'redactor/'; if (IOHelper::folderExists($configPath)) { $configFiles = IOHelper::getFolderContents($configPath, false, '\\.json$'); if (is_array($configFiles)) { foreach ($configFiles as $file) { $configOptions[IOHelper::getFileName($file)] = IOHelper::getFileName($file, false); } } } $columns = array('text' => Craft::t('Text (stores about 64K)'), 'mediumtext' => Craft::t('MediumText (stores about 4GB)')); $sourceOptions = array(); foreach (craft()->assetSources->getPublicSources() as $source) { $sourceOptions[] = array('label' => $source->name, 'value' => $source->id); } $transformOptions = array(); foreach (craft()->assetTransforms->getAllTransforms() as $transform) { $transformOptions[] = array('label' => $transform->name, 'value' => $transform->id); } return craft()->templates->render('redactori/settings', array('settings' => $this->getSettings(), 'configOptions' => $configOptions, 'assetSourceOptions' => $sourceOptions, 'transformOptions' => $transformOptions, 'columns' => $columns, 'existing' => !empty($this->model->id))); }
/** * @inheritDoc IZip::add() * * @param string $sourceZip * @param string $pathToAdd * @param string $basePath * @param null $pathPrefix * * @return bool */ public function add($sourceZip, $pathToAdd, $basePath, $pathPrefix = null) { $zip = new \ZipArchive(); $zipContents = $zip->open($sourceZip); if ($zipContents !== true) { Craft::log('Unable to open zip file: ' . $sourceZip, LogLevel::Error); return false; } if (IOHelper::fileExists($pathToAdd)) { $folderContents = array($pathToAdd); } else { $folderContents = IOHelper::getFolderContents($pathToAdd, true); } foreach ($folderContents as $itemToZip) { if (IOHelper::isReadable($itemToZip)) { // Figure out the relative path we'll be adding to the zip. $relFilePath = mb_substr($itemToZip, mb_strlen($basePath)); if ($pathPrefix) { $pathPrefix = IOHelper::normalizePathSeparators($pathPrefix); $relFilePath = $pathPrefix . $relFilePath; } if (IOHelper::folderExists($itemToZip)) { if (IOHelper::isFolderEmpty($itemToZip)) { $zip->addEmptyDir($relFilePath); } } elseif (IOHelper::fileExists($itemToZip)) { // We can't use $zip->addFile() here but it's a terrible, horrible, POS method that's buggy on Windows. $fileContents = IOHelper::getFileContents($itemToZip); if (!$zip->addFromString($relFilePath, $fileContents)) { Craft::log('There was an error adding the file ' . $itemToZip . ' to the zip: ' . $itemToZip, LogLevel::Error); } } } } $zip->close(); return true; }
/** * Will add either a file or a folder to an existing zip file. If it is a folder, it will add the contents recursively. * * @param string $sourceZip The zip file to be added to. * @param string $pathToAdd A file or a folder to add. If it is a folder, it will recursively add the contents of the folder to the zip. * @param string $basePath The root path of the file(s) to be added that will be removed before adding. * @param string $pathPrefix A path to be prepended to each file before it is added to the zip. * @return bool */ public function add($sourceZip, $pathToAdd, $basePath, $pathPrefix = null) { $zip = new \PclZip($sourceZip); if (IOHelper::fileExists($pathToAdd)) { $folderContents = array($pathToAdd); } else { $folderContents = IOHelper::getFolderContents($pathToAdd, true); } $filesToAdd = array(); foreach ($folderContents as $itemToZip) { if (IOHelper::isReadable($itemToZip)) { if (IOHelper::folderExists($itemToZip) && IOHelper::isFolderEmpty($itemToZip) || IOHelper::fileExists($itemToZip)) { $filesToAdd[] = $itemToZip; } } } if (!$pathPrefix) { $pathPrefix = ''; } $result = $zip->add($filesToAdd, PCLZIP_OPT_ADD_PATH, $pathPrefix, PCLZIP_OPT_REMOVE_PATH, $basePath); if ($result == 0) { Craft::log('Unable to add to zip file: ' . $sourceZip, LogLevel::Error); return false; } return true; }
/** * Deletes a user's photo. * * @param UserModel $user The user. * * @return null */ public function deleteUserPhoto(UserModel $user) { $folder = craft()->path->getUserPhotosPath() . $user->username; if (IOHelper::folderExists($folder)) { IOHelper::deleteFolder($folder); } $record = UserRecord::model()->findById($user->id); $record->photo = null; $user->photo = null; $record->save(); }
/** * @param string $downloadPath * @param string $md5 * @param string $handle * * @return bool */ public function downloadUpdate($downloadPath, $md5, $handle) { if (IOHelper::folderExists($downloadPath)) { $downloadPath .= $md5 . '.zip'; } $updateModel = craft()->updates->getUpdates(); $buildVersion = $updateModel->app->latestVersion . '.' . $updateModel->app->latestBuild; if ($handle == 'craft') { $path = 'http://download.craftcms.com/craft/' . $updateModel->app->latestVersion . '/' . $buildVersion . '/Patch/' . ($handle == 'craft' ? $updateModel->app->localBuild : $updateModel->app->localVersion . '.' . $updateModel->app->localBuild) . '/' . $md5 . '.zip'; } else { $localVersion = null; $localBuild = null; $latestVersion = null; $latestBuild = null; foreach ($updateModel->plugins as $plugin) { if (strtolower($plugin->class) == $handle) { $parts = explode('.', $plugin->localVersion); $localVersion = $parts[0] . '.' . $parts[1]; $localBuild = $parts[2]; $parts = explode('.', $plugin->latestVersion); $latestVersion = $parts[0] . '.' . $parts[1]; $latestBuild = $parts[2]; break; } } $path = 'http://download.craftcms.com/plugins/' . $handle . '/' . $latestVersion . '/' . $latestVersion . '.' . $latestBuild . '/Patch/' . $localVersion . '.' . $localBuild . '/' . $md5 . '.zip'; } $et = new Et($path, 240); $et->setDestinationFileName($downloadPath); if (($fileName = $et->phoneHome()) !== null) { return $fileName; } return false; }
/** * Perform pre-flight checks to ensure we can run. * * @return this */ protected function flightcheck() { if (!self::$_pluginSettings) { throw new Exception(Craft::t('Minimee is not installed.')); } if (!$this->settings->enabled) { throw new Exception(Craft::t('Minimee has been disabled via settings.')); } if (!$this->settings->validate()) { $exceptionErrors = ''; foreach ($this->settings->getErrors() as $error) { $exceptionErrors .= implode('. ', $error); } throw new Exception(Craft::t('Minimee has detected invalid plugin settings: ') . $exceptionErrors); } if ($this->settings->useResourceCache()) { IOHelper::ensureFolderExists($this->makePathToStorageFolder()); } else { if (!IOHelper::folderExists($this->settings->cachePath)) { throw new Exception(Craft::t('Minimee\'s Cache Folder does not exist: ' . $this->settings->cachePath)); } if (!IOHelper::isWritable($this->settings->cachePath)) { throw new Exception(Craft::t('Minimee\'s Cache Folder is not writable: ' . $this->settings->cachePath)); } } if (!$this->assets) { throw new Exception(Craft::t('Minimee has no assets to operate upon.')); } if (!$this->type) { throw new Exception(Craft::t('Minimee has no value for `type`.')); } return $this; }
/** * Logs * * @param array $variables * * @return null */ public function actionLogs(array $variables = array()) { craft()->config->maxPowerCaptain(); if (IOHelper::folderExists(craft()->path->getLogPath())) { $dateTimePattern = '/^[0-9]{4}\\/[0-9]{2}\\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/'; $logFileNames = array(); // Grab it all. $logFolderContents = IOHelper::getFolderContents(craft()->path->getLogPath()); foreach ($logFolderContents as $logFolderContent) { // Make sure it's a file.` if (IOHelper::fileExists($logFolderContent)) { $logFileNames[] = IOHelper::getFileName($logFolderContent); } } $logEntriesByRequest = array(); $currentLogFileName = isset($variables['currentLogFileName']) ? $variables['currentLogFileName'] : 'craft.log'; $currentFullPath = craft()->path->getLogPath() . $currentLogFileName; if (IOHelper::fileExists($currentFullPath)) { // Different parsing logic for phperrors.log if ($currentLogFileName !== 'phperrors.log') { // Split the log file's contents up into arrays of individual logs, where each item is an array of // the lines of that log. $contents = IOHelper::getFileContents(craft()->path->getLogPath() . $currentLogFileName); $requests = explode('******************************************************************************************************', $contents); foreach ($requests as $request) { $logEntries = array(); $logChunks = preg_split('/^(\\d{4}\\/\\d{2}\\/\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[(.*?)\\] \\[(.*?)\\] /m', $request, null, PREG_SPLIT_DELIM_CAPTURE); // Ignore the first chunk array_shift($logChunks); // Loop through them $totalChunks = count($logChunks); for ($i = 0; $i < $totalChunks; $i += 4) { $logEntryModel = new LogEntryModel(); $logEntryModel->dateTime = DateTime::createFromFormat('Y/m/d H:i:s', $logChunks[$i]); $logEntryModel->level = $logChunks[$i + 1]; $logEntryModel->category = $logChunks[$i + 2]; $message = $logChunks[$i + 3]; $rowContents = explode("\n", $message); // Find a few new markers $cookieStart = array_search('$_COOKIE=array (', $rowContents); $sessionStart = array_search('$_SESSION=array (', $rowContents); $serverStart = array_search('$_SERVER=array (', $rowContents); $postStart = array_search('$_POST=array (', $rowContents); // If we found any of these, we know this is a devMode log. if ($cookieStart || $sessionStart || $serverStart || $postStart) { $cookieStart = $cookieStart ? $cookieStart + 1 : $cookieStart; $sessionStart = $sessionStart ? $sessionStart + 1 : $sessionStart; $serverStart = $serverStart ? $serverStart + 1 : $serverStart; $postStart = $postStart ? $postStart + 1 : $postStart; if (!$postStart) { if (!$cookieStart) { if (!$sessionStart) { $start = $serverStart; } else { $start = $sessionStart; } } else { $start = $cookieStart; } } else { $start = $postStart; } // Check to see if it's GET or POST if (mb_substr($rowContents[0], 0, 5) == '$_GET') { // Grab GET $logEntryModel->get = $this->_cleanUpArray(array_slice($rowContents, 1, $start - 4)); } if (mb_substr($rowContents[0], 0, 6) == '$_POST') { // Grab POST $logEntryModel->post = $this->_cleanUpArray(array_slice($rowContents, 1, $start - 4)); } // We need to do a little more work to find out what element profiling info starts on. $tempArray = array_slice($rowContents, $serverStart, null, true); $profileStart = false; foreach ($tempArray as $key => $tempArrayRow) { if (preg_match($dateTimePattern, $tempArrayRow)) { $profileStart = $key; break; } } // Grab the cookie, session and server sections. if ($cookieStart) { if (!$sessionStart) { $start = $serverStart; } else { $start = $sessionStart; } $logEntryModel->cookie = $this->_cleanUpArray(array_slice($rowContents, $cookieStart, $start - $cookieStart - 3)); } if ($sessionStart) { $logEntryModel->session = $this->_cleanUpArray(array_slice($rowContents, $sessionStart, $serverStart - $sessionStart - 3)); } // Build out the $_SERVER array. Not exactly sure when this should end so just scan through the lines until the array has been closed. $serverArray = []; for ($line = $serverStart; isset($rowContents[$line]); $line++) { if (strncmp($rowContents[$line], ')', 1) === 0) { break; } $serverArray[] = $rowContents[$line]; } $logEntryModel->server = $this->_cleanUpArray($serverArray); // We can't just grab the profile info, we need to do some extra processing on it. $tempProfile = array_slice($rowContents, $profileStart); $profile = array(); $profileArr = array(); foreach ($tempProfile as $tempProfileRow) { if (preg_match($dateTimePattern, $tempProfileRow)) { if (!empty($profileArr)) { $profile[] = $profileArr; $profileArr = array(); } } $profileArr[] = rtrim(trim($tempProfileRow), ','); } // Grab the last one. $profile[] = $profileArr; // Finally save the profile. $logEntryModel->profile = $profile; } else { // This is a non-devMode log entry. $logEntryModel->message = $rowContents[0]; } // And save the log entry. $logEntries[] = $logEntryModel; } if ($logEntries) { // Put these logs at the top array_unshift($logEntriesByRequest, $logEntries); } } } else { $logEntry = new LogEntryModel(); $contents = IOHelper::getFileContents(craft()->path->getLogPath() . $currentLogFileName); $contents = str_replace("\n", "<br />", $contents); $logEntry->message = $contents; $logEntriesByRequest[] = array($logEntry); } } $this->renderTemplate('utils/logs', array('logEntriesByRequest' => $logEntriesByRequest, 'logFileNames' => $logFileNames, 'currentLogFileName' => $currentLogFileName)); } }
/** * Attempt to backup each of the update manifest files by copying them to a file with the same name with a .bak * extension. If there is an exception thrown, we attempt to roll back all of the changes. * * @param string $unzipFolder * @param string $handle * * @return bool */ private function _backupFiles($unzipFolder, $handle) { $manifestData = UpdateHelper::getManifestData($unzipFolder, $handle); try { foreach ($manifestData as $row) { if (UpdateHelper::isManifestVersionInfoLine($row)) { continue; } // No need to back up migration files. if (UpdateHelper::isManifestMigrationLine($row)) { continue; } $rowData = explode(';', $row); $filePath = IOHelper::normalizePathSeparators(($handle == 'craft' ? craft()->path->getAppPath() : craft()->path->getPluginsPath() . $handle . '/') . $rowData[0]); // It's a folder if (UpdateHelper::isManifestLineAFolder($filePath)) { $folderPath = UpdateHelper::cleanManifestFolderLine($filePath); if (IOHelper::folderExists($folderPath)) { Craft::log('Backing up folder ' . $folderPath, LogLevel::Info, true); IOHelper::createFolder($folderPath . '.bak'); IOHelper::copyFolder($folderPath . '/', $folderPath . '.bak/'); } } else { // If the file doesn't exist, it's probably a new file. if (IOHelper::fileExists($filePath)) { Craft::log('Backing up file ' . $filePath, LogLevel::Info, true); IOHelper::copyFile($filePath, $filePath . '.bak'); } } } } catch (\Exception $e) { Craft::log('Error updating files: ' . $e->getMessage(), LogLevel::Error); UpdateHelper::rollBackFileChanges($manifestData, $handle); return false; } return true; }
/** * If 'unverifiedEmail' is set on the UserModel, then this method will transfer it to the official email property * and clear the unverified one. * * @param UserModel $user * * @throws Exception */ public function verifyEmailForUser(UserModel $user) { if ($user->unverifiedEmail) { $userRecord = $this->_getUserRecordById($user->id); $oldEmail = $userRecord->email; $userRecord->email = $user->unverifiedEmail; if (craft()->config->get('useEmailAsUsername')) { $userRecord->username = $user->unverifiedEmail; $oldProfilePhotoPath = craft()->path->getUserPhotosPath() . AssetsHelper::cleanAssetName($oldEmail, false, true); $newProfilePhotoPath = craft()->path->getUserPhotosPath() . AssetsHelper::cleanAssetName($user->unverifiedEmail, false, true); // Update the user profile photo folder name, if it exists. if (IOHelper::folderExists($oldProfilePhotoPath)) { IOHelper::rename($oldProfilePhotoPath, $newProfilePhotoPath); } } $userRecord->unverifiedEmail = null; $userRecord->save(); // If the user status is pending, let's activate them. if ($userRecord->pending == true) { $this->activateUser($user); } } }
/** * @inheritDoc BaseAssetSourceType::insertFileInFolder() * * @param AssetFolderModel $folder * @param string $filePath * @param string $fileName * * @throws Exception * @return AssetOperationResponseModel */ protected function insertFileInFolder(AssetFolderModel $folder, $filePath, $fileName) { // Check if the set file system path exists $basePath = $this->getSourceFileSystemPath(); if (empty($basePath)) { $basePath = $this->getBasePath(); if (!empty($basePath)) { throw new Exception(Craft::t('The file system path “{folder}” set for this source does not exist.', array('folder' => $this->getBasePath()))); } } $targetFolder = $this->getSourceFileSystemPath() . $folder->path; // Make sure the folder exists. if (!IOHelper::folderExists($targetFolder)) { throw new Exception(Craft::t('The folder “{folder}” does not exist.', array('folder' => $targetFolder))); } // Make sure the folder is writable if (!IOHelper::isWritable($targetFolder)) { throw new Exception(Craft::t('The folder “{folder}” is not writable.', array('folder' => $targetFolder))); } $fileName = AssetsHelper::cleanAssetName($fileName); $targetPath = $targetFolder . $fileName; $extension = IOHelper::getExtension($fileName); if (!IOHelper::isExtensionAllowed($extension)) { throw new Exception(Craft::t('This file type is not allowed')); } if (IOHelper::fileExists($targetPath)) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } if (!IOHelper::copyFile($filePath, $targetPath)) { throw new Exception(Craft::t('Could not copy file to target destination')); } IOHelper::changePermissions($targetPath, craft()->config->get('defaultFilePermissions')); $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('filePath', $targetPath); }
/** * @param $sourceZip * @param $pathToAdd * @param $basePath * @param null $pathPrefix * * @return bool */ public static function add($sourceZip, $pathToAdd, $basePath, $pathPrefix = null) { $sourceZip = IOHelper::normalizePathSeparators($sourceZip); $pathToAdd = IOHelper::normalizePathSeparators($pathToAdd); $basePath = IOHelper::normalizePathSeparators($basePath); if (!IOHelper::fileExists($sourceZip) || !IOHelper::fileExists($pathToAdd) && !IOHelper::folderExists($pathToAdd)) { Craft::log('Tried to add ' . $pathToAdd . ' to the zip file ' . $sourceZip . ', but one of them does not exist.', LogLevel::Error); return false; } craft()->config->maxPowerCaptain(); $zip = static::_getZipInstance($sourceZip); if ($zip->add($sourceZip, $pathToAdd, $basePath, $pathPrefix)) { return true; } return false; }
/** * Loads the message translation for the specified language and category. * * @param string $category The message category * @param string $language The target locale * * @return array The loaded messages */ protected function loadMessages($category, $language) { if ($category !== 'craft') { $parentMessages = parent::loadMessages($category, $language); // See if there any craft/translations for Yii's system messages. if (($filePath = IOHelper::fileExists(craft()->path->getSiteTranslationsPath() . $language . '.php')) !== false) { $parentMessages = array_merge($parentMessages, include $filePath); } return $parentMessages; } if (!isset($this->_translations[$language])) { $this->_translations[$language] = array(); // Plugin translations get added first so they always lose out for conflicts if (craft()->isInstalled() && !craft()->isInMaintenanceMode()) { // Don't use PluginService, but go straight to the file system. Who cares if they are disabled. $pluginPaths = IOHelper::getFolders(craft()->path->getPluginsPath()); if ($pluginPaths) { foreach ($pluginPaths as $pluginPath) { $paths[] = $pluginPath . 'translations/'; } } } // Craft's translations are up next $paths[] = craft()->path->getCpTranslationsPath(); // Add in Yii's i18n data, which we're going to do some special parsing on $paths[] = craft()->path->getFrameworkPath() . 'i18n/data/'; // Site translations take the highest precidence, so they get added last $paths[] = craft()->path->getSiteTranslationsPath(); // Look for translation file from least to most specific. For example, nl.php gets loaded before nl_nl.php. $translationFiles = array(); $parts = explode('_', $language); $totalParts = count($parts); // If it's Norwegian Bokmål/Nynorsk, add plain ol' Norwegian as a fallback if ($parts[0] === 'nb' || $parts[0] === 'nn') { $translationFiles[] = 'no'; } for ($i = 1; $i <= $totalParts; $i++) { $translationFiles[] = implode('_', array_slice($parts, 0, $i)); } // Now loop through all of the paths and translation files and import the ones that exist foreach ($paths as $folderPath) { if (IOHelper::folderExists($folderPath)) { foreach ($translationFiles as $file) { $path = $folderPath . $file . '.php'; if (IOHelper::fileExists($path)) { // Load it up. $translations = (include $path); if (is_array($translations)) { // If this is framework data and we're not on en_us, then do some special processing. if (strpos($path, 'framework/i18n/data') !== false && $file !== 'en_us') { $translations = $this->_processFrameworkData($file); } $this->_translations[$language] = array_merge($this->_translations[$language], $translations); } } } } } } return $this->_translations[$language]; }
/** * Creates a new support ticket for the GetHelp widget. * * @return null */ public function actionSendSupportRequest() { $this->requirePostRequest(); craft()->config->maxPowerCaptain(); $success = false; $errors = array(); $zipFile = null; $tempFolder = null; $widgetId = craft()->request->getPost('widgetId'); $namespace = craft()->request->getPost('namespace'); $namespace = $namespace ? $namespace . '.' : ''; $getHelpModel = new GetHelpModel(); $getHelpModel->fromEmail = craft()->request->getPost($namespace . 'fromEmail'); $getHelpModel->message = trim(craft()->request->getPost($namespace . 'message')); $getHelpModel->attachLogs = (bool) craft()->request->getPost($namespace . 'attachLogs'); $getHelpModel->attachDbBackup = (bool) craft()->request->getPost($namespace . 'attachDbBackup'); $getHelpModel->attachTemplates = (bool) craft()->request->getPost($namespace . 'attachTemplates'); $getHelpModel->attachment = UploadedFile::getInstanceByName($namespace . 'attachAdditionalFile'); if ($getHelpModel->validate()) { $user = craft()->userSession->getUser(); // Add some extra info about this install $message = $getHelpModel->message . "\n\n" . "------------------------------\n\n" . 'Craft ' . craft()->getEditionName() . ' ' . craft()->getVersion() . '.' . craft()->getBuild(); $plugins = craft()->plugins->getPlugins(); if ($plugins) { $pluginNames = array(); foreach ($plugins as $plugin) { $pluginNames[] = $plugin->getName() . ' ' . $plugin->getVersion() . ' (' . $plugin->getDeveloper() . ')'; } $message .= "\nPlugins: " . implode(', ', $pluginNames); } $requestParamDefaults = array('sFirstName' => $user->getFriendlyName(), 'sLastName' => $user->lastName ? $user->lastName : 'Doe', 'sEmail' => $getHelpModel->fromEmail, 'tNote' => $message); $requestParams = $requestParamDefaults; $hsParams = array('helpSpotApiURL' => 'https://support.pixelandtonic.com/api/index.php'); try { if ($getHelpModel->attachLogs || $getHelpModel->attachDbBackup) { if (!$zipFile) { $zipFile = $this->_createZip(); } if ($getHelpModel->attachLogs && IOHelper::folderExists(craft()->path->getLogPath())) { // Grab it all. $logFolderContents = IOHelper::getFolderContents(craft()->path->getLogPath()); foreach ($logFolderContents as $file) { // Make sure it's a file. if (IOHelper::fileExists($file)) { Zip::add($zipFile, $file, craft()->path->getStoragePath()); } } } if ($getHelpModel->attachDbBackup && IOHelper::folderExists(craft()->path->getDbBackupPath())) { // Make a fresh database backup of the current schema/data. We want all data from all tables // for debugging. craft()->db->backup(); $backups = IOHelper::getLastModifiedFiles(craft()->path->getDbBackupPath(), 3); foreach ($backups as $backup) { if (IOHelper::getExtension($backup) == 'sql') { Zip::add($zipFile, $backup, craft()->path->getStoragePath()); } } } } if ($getHelpModel->attachment) { // If we don't have a zip file yet, create one now. if (!$zipFile) { $zipFile = $this->_createZip(); } $tempFolder = craft()->path->getTempPath() . StringHelper::UUID() . '/'; if (!IOHelper::folderExists($tempFolder)) { IOHelper::createFolder($tempFolder); } $tempFile = $tempFolder . $getHelpModel->attachment->getName(); $getHelpModel->attachment->saveAs($tempFile); // Make sure it actually saved. if (IOHelper::fileExists($tempFile)) { Zip::add($zipFile, $tempFile, $tempFolder); } } if ($getHelpModel->attachTemplates) { // If we don't have a zip file yet, create one now. if (!$zipFile) { $zipFile = $this->_createZip(); } if (IOHelper::folderExists(craft()->path->getLogPath())) { // Grab it all. $templateFolderContents = IOHelper::getFolderContents(craft()->path->getSiteTemplatesPath()); foreach ($templateFolderContents as $file) { // Make sure it's a file. if (IOHelper::fileExists($file)) { $templateFolderName = IOHelper::getFolderName(craft()->path->getSiteTemplatesPath(), false); $siteTemplatePath = craft()->path->getSiteTemplatesPath(); $tempPath = substr($siteTemplatePath, 0, strlen($siteTemplatePath) - strlen($templateFolderName) - 1); Zip::add($zipFile, $file, $tempPath); } } } } if ($zipFile) { $requestParams['File1_sFilename'] = 'SupportAttachment-' . IOHelper::cleanFilename(craft()->getSiteName()) . '.zip'; $requestParams['File1_sFileMimeType'] = 'application/zip'; $requestParams['File1_bFileBody'] = base64_encode(IOHelper::getFileContents($zipFile)); // Bump the default timeout because of the attachment. $hsParams['callTimeout'] = 120; } // Grab the license.key file. if (IOHelper::fileExists(craft()->path->getLicenseKeyPath())) { $requestParams['File2_sFilename'] = 'license.key'; $requestParams['File2_sFileMimeType'] = 'text/plain'; $requestParams['File2_bFileBody'] = base64_encode(IOHelper::getFileContents(craft()->path->getLicenseKeyPath())); } } catch (\Exception $e) { Craft::log('Tried to attach debug logs to a support request and something went horribly wrong: ' . $e->getMessage(), LogLevel::Warning); // There was a problem zipping, so reset the params and just send the email without the attachment. $requestParams = $requestParamDefaults; } require_once craft()->path->getLibPath() . 'HelpSpotAPI.php'; $hsapi = new \HelpSpotAPI($hsParams); $result = $hsapi->requestCreate($requestParams); if ($result) { if ($zipFile) { if (IOHelper::fileExists($zipFile)) { IOHelper::deleteFile($zipFile); } } if ($tempFolder) { IOHelper::clearFolder($tempFolder); IOHelper::deleteFolder($tempFolder); } $success = true; } else { $hsErrors = array_filter(preg_split("/(\r\n|\n|\r)/", $hsapi->errors)); $errors = array('Support' => $hsErrors); } } else { $errors = $getHelpModel->getErrors(); } $this->renderTemplate('_components/widgets/GetHelp/response', array('success' => $success, 'errors' => JsonHelper::encode($errors), 'widgetId' => $widgetId)); }
/** * Logs * * @param array $variables * * @return null */ public function actionLogs(array $variables = array()) { craft()->config->maxPowerCaptain(); if (IOHelper::folderExists(craft()->path->getLogPath())) { $dateTimePattern = '/^[0-9]{4}\\/[0-9]{2}\\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/'; $logFileNames = array(); // Grab it all. $logFolderContents = IOHelper::getFolderContents(craft()->path->getLogPath()); foreach ($logFolderContents as $logFolderContent) { // Make sure it's a file.` if (IOHelper::fileExists($logFolderContent)) { $logFileNames[] = IOHelper::getFileName($logFolderContent); } } $logEntries = array(); $currentLogFileName = isset($variables['currentLogFileName']) ? $variables['currentLogFileName'] : 'craft.log'; $currentFullPath = craft()->path->getLogPath() . $currentLogFileName; if (IOHelper::fileExists($currentFullPath)) { // Different parsing logic for phperrors.log if ($currentLogFileName !== 'phperrors.log') { $contents = IOHelper::getFileContents(craft()->path->getLogPath() . $currentLogFileName); // Split on the new log entry line. $contents = preg_split('/(\\*){102}/', $contents); foreach ($contents as $rowChunk) { $logEntryModel = new LogEntryModel(); $rowChunk = trim($rowChunk); // Split on the newlines $rowContents = preg_split("/\n/", $rowChunk); // Grab the date and time $logEntryModel->dateTime = rtrim(trim(mb_substr($rowContents[0], 0, 19)), ','); // Grab the level $rowContents[0] = mb_substr($rowContents[0], 21); $stop = mb_strpos($rowContents[0], ']'); $logEntryModel->level = rtrim(trim(mb_substr($rowContents[0], 0, $stop)), ','); // Grab the category. $rowContents[0] = mb_substr($rowContents[0], $stop + 3); $stop = mb_strpos($rowContents[0], ']'); $logEntryModel->category = rtrim(trim(mb_substr($rowContents[0], 0, $stop)), ','); // Find a few new markers $rowContents[0] = mb_substr($rowContents[0], $stop + 2); $cookieStart = array_search('$_COOKIE=array (', $rowContents); $sessionStart = array_search('$_SESSION=array (', $rowContents); $serverStart = array_search('$_SERVER=array (', $rowContents); $postStart = array_search('$_POST=array (', $rowContents); // If we found any of these, we know this is a devMode log. if ($cookieStart || $sessionStart || $serverStart || $postStart) { $cookieStart = $cookieStart ? $cookieStart + 1 : $cookieStart; $sessionStart = $sessionStart ? $sessionStart + 1 : $sessionStart; $serverStart = $serverStart ? $serverStart + 1 : $serverStart; $postStart = $postStart ? $postStart + 1 : $postStart; if (!$postStart) { if (!$cookieStart) { if (!$sessionStart) { $start = $serverStart; } else { $start = $sessionStart; } } else { $start = $cookieStart; } } else { $start = $postStart; } // Check to see if it's GET or POST if (mb_substr($rowContents[0], 0, 5) == '$_GET') { // Grab GET $logEntryModel->get = $this->_cleanUpArray(array_slice($rowContents, 1, $start - 4)); } if (mb_substr($rowContents[0], 0, 6) == '$_POST') { // Grab POST $logEntryModel->post = $this->_cleanUpArray(array_slice($rowContents, 1, $start - 4)); } // We need to do a little more work to find out what element profiling info starts on. $tempArray = array_slice($rowContents, $serverStart, null, true); $profileStart = false; foreach ($tempArray as $key => $tempArrayRow) { if (preg_match($dateTimePattern, $tempArrayRow)) { $profileStart = $key; break; } } // Grab the cookie, session and server sections. if ($cookieStart) { if (!$sessionStart) { $start = $serverStart; } else { $start = $sessionStart; } $logEntryModel->cookie = $this->_cleanUpArray(array_slice($rowContents, $cookieStart, $start - $cookieStart - 3)); } if ($sessionStart) { $logEntryModel->session = $this->_cleanUpArray(array_slice($rowContents, $sessionStart, $serverStart - $sessionStart - 3)); } $logEntryModel->server = $this->_cleanUpArray(array_slice($rowContents, $serverStart, $profileStart - $serverStart - 1)); // We can't just grab the profile info, we need to do some extra processing on it. $tempProfile = array_slice($rowContents, $profileStart); $profile = array(); $profileArr = array(); foreach ($tempProfile as $tempProfileRow) { if (preg_match($dateTimePattern, $tempProfileRow)) { if (!empty($profileArr)) { $profile[] = $profileArr; $profileArr = array(); } } $profileArr[] = rtrim(trim($tempProfileRow), ','); } // Grab the last one. $profile[] = $profileArr; // Finally save the profile. $logEntryModel->profile = $profile; } else { // This is a non-devMode log entry. $logEntryModel->message = $rowContents[0]; } // And save the log entry. $logEntries[] = $logEntryModel; } // Because I'm lazy. array_pop($logEntries); } else { $logEntry = new LogEntryModel(); $contents = IOHelper::getFileContents(craft()->path->getLogPath() . $currentLogFileName); $contents = str_replace("\n", "<br />", $contents); $logEntry->message = $contents; $logEntries[] = $logEntry; } } // Because ascending order is stupid. $logEntries = array_reverse($logEntries); $this->renderTemplate('utils/logs', array('logEntries' => $logEntries, 'logFileNames' => $logFileNames, 'currentLogFileName' => $currentLogFileName)); } }
/** * Makes sure a folder exists. If it does not - creates one with write permissions * * @param string $folderPath The path to the folder. * @param bool $suppressErrors Whether to suppress any PHP Notices/Warnings/Errors (usually permissions related). * * @return null */ public static function ensureFolderExists($folderPath, $suppressErrors = false) { if (!IOHelper::folderExists($folderPath, $suppressErrors)) { IOHelper::createFolder($folderPath, craft()->config->get('defaultFolderPermissions'), $suppressErrors); } }
/** * Creates a new support ticket for the GetHelp widget. */ public function actionSendSupportRequest() { $this->requirePostRequest(); $this->requireAjaxRequest(); craft()->config->maxPowerCaptain(); $getHelpModel = new GetHelpModel(); $getHelpModel->fromEmail = craft()->request->getPost('fromEmail'); $getHelpModel->message = craft()->request->getPost('message'); $getHelpModel->attachDebugFiles = (bool) craft()->request->getPost('attachDebugFiles'); if ($getHelpModel->validate()) { $user = craft()->userSession->getUser(); $requestParamDefaults = array('sFirstName' => $user->getFriendlyName(), 'sLastName' => $user->lastName ? $user->lastName : 'Doe', 'sEmail' => $getHelpModel->fromEmail, 'tNote' => $getHelpModel->message); $requestParams = $requestParamDefaults; $hsParams = array('helpSpotApiURL' => 'https://support.pixelandtonic.com/api/index.php'); try { if ($getHelpModel->attachDebugFiles) { $tempZipFile = craft()->path->getTempPath() . StringHelper::UUID() . '.zip'; IOHelper::createFile($tempZipFile); if (IOHelper::folderExists(craft()->path->getLogPath())) { // Grab the latest log file. Zip::add($tempZipFile, craft()->path->getLogPath() . 'craft.log', craft()->path->getStoragePath()); // Grab the most recent rolled-over log file, if one exists. if (IOHelper::fileExists(craft()->path->getLogPath() . 'craft.log.1')) { Zip::add($tempZipFile, craft()->path->getLogPath() . 'craft.log.1', craft()->path->getStoragePath()); } // Grab the phperrors log file, if it exists. if (IOHelper::fileExists(craft()->path->getLogPath() . 'phperrors.log')) { Zip::add($tempZipFile, craft()->path->getLogPath() . 'phperrors.log', craft()->path->getStoragePath()); } } if (IOHelper::folderExists(craft()->path->getDbBackupPath())) { // Make a fresh database backup of the current schema/data. craft()->db->backup(); $contents = IOHelper::getFolderContents(craft()->path->getDbBackupPath()); rsort($contents); // Only grab the most recent 3 sorted by timestamp. for ($counter = 0; $counter <= 2; $counter++) { if (isset($contents[$counter])) { Zip::add($tempZipFile, $contents[$counter], craft()->path->getStoragePath()); } } } $requestParams['File1_sFilename'] = 'SupportAttachment.zip'; $requestParams['File1_sFileMimeType'] = 'application/zip'; $requestParams['File1_bFileBody'] = base64_encode(IOHelper::getFileContents($tempZipFile)); // Bump the default timeout because of the attachment. $hsParams['callTimeout'] = 120; } } catch (\Exception $e) { Craft::log('Tried to attach debug logs to a support request and something went horribly wrong: ' . $e->getMessage(), LogLevel::Warning); // There was a problem zipping, so reset the params and just send the email without the attachment. $requestParams = $requestParamDefaults; } require_once craft()->path->getLibPath() . 'HelpSpotAPI.php'; $hsapi = new \HelpSpotAPI($hsParams); $result = $hsapi->requestCreate($requestParams); if ($result) { if ($getHelpModel->attachDebugFiles) { if (IOHelper::fileExists($tempZipFile)) { IOHelper::deleteFile($tempZipFile); } } $this->returnJson(array('success' => true)); } else { $hsErrors = array_filter(preg_split("/(\r\n|\n|\r)/", $hsapi->errors)); $this->returnJson(array('errors' => array('Support' => $hsErrors))); } } else { $this->returnJson(array('errors' => $getHelpModel->getErrors())); } }
/** * If the plugin already had a migrations folder with migrations in it, let's save them in the db. * * @param int $pluginId * @param string $pluginHandle * * @throws Exception */ private function _savePluginMigrations($pluginId, $pluginHandle) { $migrationsFolder = craft()->path->getPluginsPath() . mb_strtolower($pluginHandle) . '/migrations/'; if (IOHelper::folderExists($migrationsFolder)) { $migrations = array(); $migrationFiles = IOHelper::getFolderContents($migrationsFolder, false, "(m(\\d{6}_\\d{6})_.*?)\\.php"); if ($migrationFiles) { foreach ($migrationFiles as $file) { if (IOHelper::fileExists($file)) { $migration = new MigrationRecord(); $migration->version = IOHelper::getFileName($file, false); $migration->applyTime = DateTimeHelper::currentUTCDateTime(); $migration->pluginId = $pluginId; $migrations[] = $migration; } } foreach ($migrations as $migration) { if (!$migration->save()) { throw new Exception(Craft::t('There was a problem saving to the migrations table: ') . $this->_getFlattenedErrors($migration->getErrors())); } } } } }
/** * Finds a template on the file system and returns its path. * * All of the following files will be searched for, in this order: * * - TemplateName * - TemplateName.html * - TemplateName.twig * - TemplateName/index.html * - TemplateName/index.twig * * If this is a front-end request, the actual list of file extensions and index filenames are configurable via the * [defaultTemplateExtensions](http://craftcms.com/docs/config-settings#defaultTemplateExtensions) and * [indexTemplateFilenames](http://craftcms.com/docs/config-settings#indexTemplateFilenames) config settings. * * For example if you set the following in config/general.php: * * ```php * 'defaultTemplateExtensions' => array('htm'), * 'indexTemplateFilenames' => array('default'), * ``` * * then the following files would be searched for instead: * * - TemplateName * - TemplateName.htm * - TemplateName/default.htm * * The actual directory that those files will depend on the current {@link setTemplateMode() template mode} * (probably craft/templates/ if it’s a front-end site request, and craft/app/templates/ if it’s a Control * Panel request). * * If this is a front-end site request, a folder named after the current locale ID will be checked first. * * - craft/templates/LocaleID/... * - craft/templates/... * * And finaly, if this is a Control Panel request _and_ the template name includes multiple segments _and_ the first * segment of the template name matches a plugin’s handle, then Craft will look for a template named with the * remaining segments within that plugin’s templates/ subfolder. * * To put it all together, here’s where Craft would look for a template named “foo/bar”, depending on the type of * request it is: * * - Front-end site requests: * * - craft/templates/LocaleID/foo/bar * - craft/templates/LocaleID/foo/bar.html * - craft/templates/LocaleID/foo/bar.twig * - craft/templates/LocaleID/foo/bar/index.html * - craft/templates/LocaleID/foo/bar/index.twig * - craft/templates/foo/bar * - craft/templates/foo/bar.html * - craft/templates/foo/bar.twig * - craft/templates/foo/bar/index.html * - craft/templates/foo/bar/index.twig * * - Control Panel requests: * * - craft/app/templates/foo/bar * - craft/app/templates/foo/bar.html * - craft/app/templates/foo/bar.twig * - craft/app/templates/foo/bar/index.html * - craft/app/templates/foo/bar/index.twig * - craft/plugins/foo/templates/bar * - craft/plugins/foo/templates/bar.html * - craft/plugins/foo/templates/bar.twig * - craft/plugins/foo/templates/bar/index.html * - craft/plugins/foo/templates/bar/index.twig * * @param string $name The name of the template. * * @return string|false The path to the template if it exists, or `false`. */ public function findTemplate($name) { // Normalize the template name $name = trim(preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')), '/'); $key = $this->_templatesPath . ':' . $name; // Is this template path already cached? if (isset($this->_templatePaths[$key])) { return $this->_templatePaths[$key]; } // Validate the template name $this->_validateTemplateName($name); // Look for the template in the main templates folder $basePaths = array(); // Should we be looking for a localized version of the template? if (craft()->request->isSiteRequest() && IOHelper::folderExists($this->_templatesPath . craft()->language)) { $basePaths[] = $this->_templatesPath . craft()->language . '/'; } $basePaths[] = $this->_templatesPath; foreach ($basePaths as $basePath) { if (($path = $this->_findTemplate($basePath, $name)) !== null) { return $this->_templatePaths[$key] = $path; } } // Otherwise maybe it's a plugin template? // Only attempt to match against a plugin's templates if this is a CP or action request. if (craft()->request->isCpRequest() || craft()->request->isActionRequest()) { // Sanitize $name = craft()->request->decodePathInfo($name); $parts = array_filter(explode('/', $name)); $pluginHandle = StringHelper::toLowerCase(array_shift($parts)); if ($pluginHandle && ($plugin = craft()->plugins->getPlugin($pluginHandle)) !== null) { // Get the template path for the plugin. $basePath = craft()->path->getPluginsPath() . StringHelper::toLowerCase($plugin->getClassHandle()) . '/templates/'; // Get the new template name to look for within the plugin's templates folder $tempName = implode('/', $parts); if (($path = $this->_findTemplate($basePath, $tempName)) !== null) { return $this->_templatePaths[$key] = $path; } } } return false; }