/** * Accepts: * string - a filename (e.g. application.css), or * File object * * Compiles, minifies and gz-compresses files. Also updates the * manifest index file. * Note that files with same name will be deleted. */ public function compileFile($filename) { if (!$this->compilePath()) { throw new Exception\RuntimeException("Missing asset configuration 'compile_path'"); } elseif (!$this->manifestFileName) { throw new Exception\RuntimeException(sprintf("Property %s::\$manifestFileName must not be empty", __CLASS__)); } if (is_string($filename)) { $file = $this->findFile($filename); if (!$file) { throw new Exception\RuntimeException(sprintf("Asset file not found: %s", $filename)); } } elseif ($filename instanceof File) { $file = $filename; } else { throw new Exception\InvalidArgumentException(sprintf("Argument must be string or Rails\\Assets\\File, %s passed", gettype($filename))); } $this->console("Compiling file " . $file->full_path()); $basePath = $this->compilePath() . $this->prefix(); $ext = $file->type(); $relativeDir = $file->relative_dir(); if ($relativeDir) { $relativeDir .= '/'; } $fileroot = $basePath . '/' . $relativeDir . $file->file_root(); $compiledFileDir = dirname($fileroot); if (!is_dir($compiledFileDir)) { try { mkdir($compiledFileDir, 0755, true); } catch (\Exception $e) { throw new Exception\RuntimeException(sprintf("Couldn't create dir %s: %s", $compiledFileDir, $e->getMessage())); } } set_time_limit(360); $parser = new Parser\Base($file); $parser->parse(Parser\Base::PARSE_TYPE_FULL); $fileContents = $parser->parsed_file(); if ($this->config()->compress) { $fileContents = $this->compressFile($fileContents, $ext); } $compileFiles = [$fileroot . '.' . $ext]; if ($this->config()->digest) { $md5 = md5($fileContents); $compileFiles[] = $fileroot . '-' . $md5 . '.' . $ext; } foreach ($compileFiles as $compileFile) { $this->createCompiledFile($compileFile, $fileContents); } $relativePath = $relativeDir . $file->file_root(); if ($this->config()->digest) { # Delete previous md5 files $pattern = $fileroot . '-*.' . $ext . '*'; if ($mfiles = glob($pattern)) { $regexp = '/-' . $md5 . '\\.' . $ext . '(\\.gz)?$/'; foreach ($mfiles as $mfile) { if (!preg_match($regexp, $mfile)) { unlink($mfile); } } } $this->updateManifestIndex($relativePath . '.' . $ext, $relativePath . '-' . $md5 . '.' . $ext); } return true; }
/** * Returns not only the URL for the file, but also the URLs * of the files it requires (if it's a manifest file). */ public function getFileUrls($filename) { if ($file = $this->findFile($filename)) { $parser = new Rails\Assets\Parser\Base($file); $parser->parse(Rails\Assets\Parser\Base::PARSE_TYPE_GET_PATHS); $urls = []; foreach ($parser->urlPaths() as $url) { $urls[] = $url . '?body=1'; } return $urls; } return false; }
public function serve_file($file_path) { $file = Rails::assets()->findFile($file_path); if (!$file) { $this->set_404_headers(); return; } $ext = $file->type(); $parser = null; switch ($ext) { case 'js': $parser = new Parser\Base($file); $this->set_javascript_headers(); break; case 'css': $parser = new Parser\Base($file); $this->set_stylesheet_headers(); break; case 'jpeg': $this->headers()->contentType('image/jpeg'); break; case 'jpg': $this->headers()->contentType('image/jpeg'); break; case 'png': $this->headers()->contentType('image/png'); break; case 'gif': $this->headers()->contentType('image/gif'); break; case 'svg': $this->headers()->contentType('image/svg+xml'); break; case 'ttf': $this->headers()->contentType('application/x-font-ttf'); break; case 'woff': $this->headers()->contentType('application/font-woff'); break; default: $this->headers()->contentType('application/octet-stream'); return; } if ($parser) { if ($this->params()->body) { $parseType = Parser\Base::PARSE_TYPE_NONE; } else { $parseType = Parser\Base::PARSE_TYPE_FULL; } $parser->parse($parseType); $file_contents = $parser->parsed_file(); } else { $file_contents = file_get_contents($file->full_path()); } $etag = md5($file_contents); $date = date('D, d M Y H:i:s e'); $last_modified = Rails::cache()->fetch('assets.last_mod.' . $file->full_path(), function () use($date) { return $date; }); if ($this->file_modified($etag, $last_modified)) { $this->headers()->add("Last-Modified", $last_modified); $this->headers()->add("Cache-Control", 'public, max-age=31536000'); $this->headers()->add("ETag", $etag); Rails::application()->dispatcher()->response()->body($file_contents); } else { $this->headers()->status('HTTP/1.1 304 Not Modified'); Rails::application()->dispatcher()->response()->body(''); } }