/** * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like * operating systems. * @throws InvalidConfigException */ public function init() { if (DIRECTORY_SEPARATOR === '\\') { throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.'); } $this->mutexPath = Leaps::getAlias($this->mutexPath); if (!is_dir($this->mutexPath)) { FileHelper::createDirectory($this->mutexPath, $this->dirMode, true); } }
/** * This method is invoked right before an action is to be executed (after all possible filters.) * It checks the existence of the [[migrationPath]]. * @param \yii\base\Action $action the action to be executed. * @throws Exception if directory specified in migrationPath doesn't exist and action isn't "create". * @return boolean whether the action should continue to be executed. */ public function beforeAction($action) { if (parent::beforeAction($action)) { $path = Leaps::getAlias($this->migrationPath); if (!is_dir($path)) { if ($action->id !== 'create') { throw new Exception("Migration failed. Directory specified in migrationPath doesn't exist: {$this->migrationPath}"); } FileHelper::createDirectory($path); } $this->migrationPath = $path; $version = Leaps::getVersion(); $this->stdout("Leaps Migration Tool (based on Leaps v{$version})\n\n"); return true; } else { return false; } }
/** * 发布文件夹 * * @param string $src the asset directory to be published * @param array $options the options to be applied when publishing a directory. * The following options are supported: * * - only: array, list of patterns that the file paths should match if they want to be copied. * - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied. * - caseSensitive: boolean, whether patterns specified at "only" or "except" should be case sensitive. Defaults to true. * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file. * This overrides [[beforeCopy]] if set. * - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied. * This overrides [[afterCopy]] if set. * - forceCopy: boolean, whether the directory being published should be copied even if * it is found in the target directory. This option is used only when publishing a directory. * This overrides [[forceCopy]] if set. * * @return array the path directory and the URL that the asset is published as. * @throws InvalidParamException if the asset to be published does not exist. */ protected function publishDirectory($src, $options) { $dir = $this->hash($src); $dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir; if ($this->linkAssets) { if (!is_dir($dstDir)) { symlink($src, $dstDir); } } elseif (!empty($options['forceCopy']) || $this->forceCopy && !isset($options['forceCopy']) || !is_dir($dstDir)) { $opts = array_merge($options, ['dirMode' => $this->dirMode, 'fileMode' => $this->fileMode]); if (!isset($opts['beforeCopy'])) { if ($this->beforeCopy !== null) { $opts['beforeCopy'] = $this->beforeCopy; } else { $opts['beforeCopy'] = function ($from, $to) { return strncmp(basename($from), '.', 1) !== 0; }; } } if (!isset($opts['afterCopy']) && $this->afterCopy !== null) { $opts['afterCopy'] = $this->afterCopy; } FileHelper::copyDirectory($src, $dstDir, $opts); } return [$dstDir, $this->baseUrl . '/' . $dir]; }
/** * Writes messages into POT file * * @param array $messages * @param string $dirName name of the directory to write to * @param string $catalog message catalog * @since 2.0.6 */ protected function saveMessagesToPOT($messages, $dirName, $catalog) { $file = str_replace("\\", '/', "{$dirName}/{$catalog}.pot"); FileHelper::createDirectory(dirname($file)); $this->stdout("Saving messages to {$file}...\n"); $poFile = new GettextPoFile(); $merged = []; $hasSomethingToWrite = false; foreach ($messages as $category => $msgs) { $msgs = array_values(array_unique($msgs)); sort($msgs); foreach ($msgs as $message) { $merged[$category . chr(4) . $message] = ''; } ksort($merged); $this->stdout("Category \"{$category}\" merged.\n"); $hasSomethingToWrite = true; } if ($hasSomethingToWrite) { $poFile->save($file, $merged); $this->stdout("Translation saved.\n", Console::FG_GREEN); } else { $this->stdout("Nothing to save.\n", Console::FG_GREEN); } }
/** * Stores a value identified by a key in cache. * This is the implementation of the method declared in the parent class. * * @param string $key the key identifying the value to be cached * @param string $value the value to be cached * @param integer $duration the number of seconds in which the cached value will expire. 0 means never expire. * @return boolean true if the value is successfully stored into cache, false otherwise */ protected function setValue($key, $value, $duration) { $this->gc(); $cacheFile = $this->getCacheFile($key); if ($this->directoryLevel > 0) { @FileHelper::createDirectory(dirname($cacheFile), $this->dirMode, true); } if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) { if ($this->fileMode !== null) { @chmod($cacheFile, $this->fileMode); } if ($duration <= 0) { $duration = 31536000; // 1 year } return @touch($cacheFile, $duration + time()); } else { $error = error_get_last(); Leaps::warning("Unable to write cache file '{$cacheFile}': {$error['message']}", __METHOD__); return false; } }
/** * Builds output asset bundle. * @param \yii\web\AssetBundle $target output asset bundle * @param string $type either 'js' or 'css'. * @param \yii\web\AssetBundle[] $bundles source asset bundles. * @throws Exception on failure. */ protected function buildTarget($target, $type, $bundles) { $inputFiles = []; foreach ($target->depends as $name) { if (isset($bundles[$name])) { if (!$this->isBundleExternal($bundles[$name])) { foreach ($bundles[$name]->{$type} as $file) { $inputFiles[] = $bundles[$name]->basePath . '/' . $file; } } } else { throw new Exception("Unknown bundle: '{$name}'"); } } if (empty($inputFiles)) { $target->{$type} = []; } else { FileHelper::createDirectory($target->basePath, $this->getAssetManager()->dirMode); $tempFile = $target->basePath . '/' . strtr($target->{$type}, ['{hash}' => 'temp']); if ($type === 'js') { $this->compressJsFiles($inputFiles, $tempFile); } else { $this->compressCssFiles($inputFiles, $tempFile); } $targetFile = strtr($target->{$type}, ['{hash}' => md5_file($tempFile)]); $outputFile = $target->basePath . '/' . $targetFile; rename($tempFile, $outputFile); $target->{$type} = [$targetFile]; } }
/** * Converts a file to a themed file if possible. * If there is no corresponding themed file, the original file will be returned. * * @param string $path the file to be themed * @return string the themed file, or the original file if the themed version is not available. * @throws InvalidConfigException if [[basePath]] is not set */ public function applyTo($path) { $pathMap = $this->pathMap; if (empty($pathMap)) { if (($basePath = $this->getBasePath()) === null) { throw new InvalidConfigException('The "basePath" property must be set.'); } $pathMap = [Leaps::$app->getBasePath() => [$basePath]]; } $path = FileHelper::normalizePath($path); foreach ($pathMap as $from => $tos) { $from = FileHelper::normalizePath(Leaps::getAlias($from)) . DIRECTORY_SEPARATOR; if (strpos($path, $from) === 0) { $n = strlen($from); foreach ((array) $tos as $to) { $to = FileHelper::normalizePath(Leaps::getAlias($to)) . DIRECTORY_SEPARATOR; $file = $to . substr($path, $n); if (is_file($file)) { return $file; } } } } return $path; }
/** * Sends existing file to a browser as a download using x-sendfile. * * X-Sendfile is a feature allowing a web application to redirect the request for a file to the webserver * that in turn processes the request, this way eliminating the need to perform tasks like reading the file * and sending it to the user. When dealing with a lot of files (or very big files) this can lead to a great * increase in performance as the web application is allowed to terminate earlier while the webserver is * handling the request. * * The request is sent to the server through a special non-standard HTTP-header. * When the web server encounters the presence of such header it will discard all output and send the file * specified by that header using web server internals including all optimizations like caching-headers. * * As this header directive is non-standard different directives exists for different web servers applications: * * - Apache: [X-Sendfile](http://tn123.org/mod_xsendfile) * - Lighttpd v1.4: [X-LIGHTTPD-send-file](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) * - Lighttpd v1.5: [X-Sendfile](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) * - Nginx: [X-Accel-Redirect](http://wiki.nginx.org/XSendfile) * - Cherokee: [X-Sendfile and X-Accel-Redirect](http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile) * * So for this method to work the X-SENDFILE option/module should be enabled by the web server and * a proper xHeader should be sent. * * **Note** * * This option allows to download files that are not under web folders, and even files that are otherwise protected * (deny from all) like `.htaccess`. * * **Side effects** * * If this option is disabled by the web server, when this method is called a download configuration dialog * will open but the downloaded file will have 0 bytes. * * **Known issues** * * There is a Bug with Internet Explorer 6, 7 and 8 when X-SENDFILE is used over an SSL connection, it will show * an error message like this: "Internet Explorer was not able to open this Internet site. The requested site * is either unavailable or cannot be found.". You can work around this problem by removing the `Pragma`-header. * * **Example** * * ~~~ * Leaps::$app->response->xSendFile('/home/user/Pictures/picture1.jpg'); * ~~~ * * @param string $filePath file name with full path * @param string $attachmentName file name shown to the user. If null, it will be determined from `$filePath`. * @param array $options additional options for sending the file. The following options are supported: * * - `mimeType`: the MIME type of the content. If not set, it will be guessed based on `$filePath` * - `inline`: boolean, whether the browser should open the file within the browser window. Defaults to false, * meaning a download dialog will pop up. * - xHeader: string, the name of the x-sendfile header. Defaults to "X-Sendfile". * * @return $this the response object itself */ public function xSendFile($filePath, $attachmentName = null, $options = []) { if ($attachmentName === null) { $attachmentName = basename($filePath); } if (isset($options['mimeType'])) { $mimeType = $options['mimeType']; } elseif (($mimeType = FileHelper::getMimeTypeByExtension($filePath)) === null) { $mimeType = 'application/octet-stream'; } if (isset($options['xHeader'])) { $xHeader = $options['xHeader']; } else { $xHeader = 'X-Sendfile'; } $disposition = empty($options['inline']) ? 'attachment' : 'inline'; $this->getHeaders()->setDefault($xHeader, $filePath)->setDefault('Content-Type', $mimeType)->setDefault('Content-Disposition', "{$disposition}; filename=\"{$attachmentName}\""); $this->format = self::FORMAT_RAW; return $this; }
/** * Finds fixtures to be loaded, for example "User", if no fixtures were specified then all of them * will be searching by suffix "Fixture.php". * @param array $fixtures fixtures to be loaded * @return array Array of found fixtures. These may differ from input parameter as not all fixtures may exists. */ private function findFixtures(array $fixtures = []) { $fixturesPath = $this->getFixturePath(); $filesToSearch = ['*Fixture.php']; $findAll = $fixtures == []; if (!$findAll) { $filesToSearch = []; foreach ($fixtures as $fileName) { $filesToSearch[] = $fileName . 'Fixture.php'; } } $files = FileHelper::findFiles($fixturesPath, ['only' => $filesToSearch]); $foundFixtures = []; foreach ($files as $fixture) { $foundFixtures[] = basename($fixture, 'Fixture.php'); } return $foundFixtures; }
/** * Initializes the route. * This method is invoked after the route is created by the route manager. */ public function init() { parent::init(); if ($this->logFile === null) { $this->logFile = Leaps::$app->getRuntimePath() . '/logs/app.log'; } else { $this->logFile = Leaps::getAlias($this->logFile); } $logPath = dirname($this->logFile); if (!is_dir($logPath)) { FileHelper::createDirectory($logPath, $this->dirMode, true); } if ($this->maxLogFiles < 1) { $this->maxLogFiles = 1; } if ($this->maxFileSize < 1) { $this->maxFileSize = 1; } }
/** * Checks if given uploaded file have correct type (extension) according current validator settings. * @param UploadedFile $file * @return boolean */ protected function validateExtension($file) { $extension = mb_strtolower($file->extension, 'utf-8'); if ($this->checkExtensionByMimeType) { $mimeType = FileHelper::getMimeType($file->tempName, null, false); if ($mimeType === null) { return false; } $extensionsByMimeType = FileHelper::getExtensionsByMimeType($mimeType); if (!in_array($extension, $extensionsByMimeType, true)) { return false; } } if (!in_array($extension, $this->extensions, true)) { return false; } return true; }
/** * Renders a view file. * * If [[theme]] is enabled (not null), it will try to render the themed version of the view file as long * as it is available. * * The method will call [[FileHelper::localize()]] to localize the view file. * * If [[renderers|renderer]] is enabled (not null), the method will use it to render the view file. * Otherwise, it will simply include the view file as a normal PHP file, capture its output and * return it as a string. * * @param string $viewFile the view file. This can be either an absolute file path or an alias of it. * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. * @param object $context the context that the view should use for rendering the view. If null, * existing [[context]] will be used. * @return string the rendering result * @throws InvalidParamException if the view file does not exist */ public function renderFile($viewFile, $params = [], $context = null) { $viewFile = Leaps::getAlias($viewFile); if ($this->theme !== null) { $viewFile = $this->theme->applyTo($viewFile); } if (is_file($viewFile)) { $viewFile = FileHelper::localize($viewFile); } else { throw new InvalidParamException("The view file does not exist: {$viewFile}"); } $oldContext = $this->context; if ($context !== null) { $this->context = $context; } $output = ''; $this->_viewFiles[] = $viewFile; if ($this->beforeRender($viewFile, $params)) { Leaps::trace("Rendering view file: {$viewFile}", __METHOD__); $ext = pathinfo($viewFile, PATHINFO_EXTENSION); if (isset($this->renderers[$ext])) { if (is_array($this->renderers[$ext]) || is_string($this->renderers[$ext])) { $this->renderers[$ext] = Leaps::createObject($this->renderers[$ext]); } /* @var $renderer ViewRenderer */ $renderer = $this->renderers[$ext]; $output = $renderer->render($this, $viewFile, $params); } else { $output = $this->renderPhpFile($viewFile, $params); } $this->afterRender($viewFile, $params, $output); } array_pop($this->_viewFiles); $this->context = $oldContext; return $output; }