Česky
Kamil Dudka

Web components

File detail

Name:DownloadScriptServer.class.php [Download]
Location: src > lib
Size:4.2 KB
Last modification:2007-12-11 16:08

Source code

<?php
/**
 * @file ScriptServer.class.php
 * Definition of ScriptServer class.
 * @author Kamil Dudka <xdudka00@gmail.com>
 */
 
/**
 * ScriptServer sends JavaScript files to client.
 * Files are packed at server's side. This can take some time,
 * so packed script files are cached at server's side.
 * This class is not instantiable for now.
 */
class ScriptServer {
  /**
   * Send script to client. Script can be red from script cache
   * if cache is actual. If not, script will be generated autamatically.
   * @param scriptName Name of script to send. Script has to be placed in scriptDir directory.
   * @return Return true on success, false if script does not exist.
   * @note This method will crash if cacheDir directory is not writeable.
   */
  public static function sendScript($scriptName) {
    if (false === ereg('^[A-Za-z_][A-Za-z0-9_\.]*.js$', $scriptName))
      return false;
 
    // Read paths from Config singleton
    $config = Config::instance();
    $docRoot = $config->documentRoot();
    $scriptDir = $docRoot.$config->scriptDir();
    $cacheDir = $docRoot.$config->cacheDir();
 
    // Build file names
    $sourceScript = $scriptDir.'/'.$scriptName;
    $cachedScript = $cacheDir.'/'.$scriptName;
 
    // Check if script (re)generation is needed
    if (!file_exists($sourceScript))
      return false;
    if (!file_exists($cachedScript) ||
        filemtime($sourceScript) > filemtime($cachedScript))
      self::generate($sourceScript, $cachedScript);
 
    // Send script
    Header('Content-type: text/javascript; charset=utf-8');
    readfile($cachedScript);
    return true;
  }
  private static function generate($src, $dest) {
    $fSrc = fopen ($src, 'r');
    $fDest = fopen ($dest, 'w');
 
    // Record timestamp
    $startTS = microtime(true);
    fwrite($fDest, '// This file was generated by ScriptServer.class.php at '.date("Y-m-d H:i:s", time())."\n");
    fwrite($fDest, '// Source file\'s mtime was '.date("Y-m-d H:i:s", filemtime($src))."\n");
 
    // State set of FA
    define('ST_INIT', 0);
    define('ST_LONG_COMMENT', 1);
    define('ST_INLINE_COMMENT', 2);
    define('ST_SLASH_READED', 3);
    define('ST_ASTERIX_READED', 4);
    define('ST_LINE_BEGIN', 5);
    $state = ST_INIT;                 // FA's initial state
    $last = '';                       // Last char writen
    $ignoreInlineComment = false;     // Patch for \// sequence
    while (false !== ($c = fgetc($fSrc))) {
      switch ($state) {
        case ST_INIT:
          if ($c == '/') {
            $state = ST_SLASH_READED;
            $ignoreInlineComment = false;
          } else {
            if ($c == "\n")
              $state = ST_LINE_BEGIN;
            if ($c != "\n" || $last != "\n")
              fwrite($fDest, $last = $c);
            }
          break;
        case ST_LINE_BEGIN:
          if ($c == '/') {
            $state = ST_SLASH_READED;
            $ignoreInlineComment = true;
          }
          else if (trim($c)==$c) {
            $state = ST_INIT;
            if ($c != "\n" || $last != "\n")
              fwrite($fDest, $last = $c);
          }
          break;
        case ST_SLASH_READED:
          if ($ignoreInlineComment && $c == '/')
            $state = ST_INLINE_COMMENT;
          else if ($c == '*')
            $state = ST_LONG_COMMENT;
          else {
            if ($c == "\n")
              $state = ST_LINE_BEGIN;
            else
              $state = ST_INIT;
            fwrite($fDest, '/'.($last=$c));
          }
          break;
        case ST_INLINE_COMMENT:
          if ($c == "\n") {
            $state = ST_LINE_BEGIN;
            if ($last != "\n")
              fwrite($fDest, $last = "\n");
          }
          break;
        case ST_LONG_COMMENT:
          if ($c == '*')
            $state = ST_ASTERIX_READED;
          break;
        case ST_ASTERIX_READED:
          if ($c == '/')
            $state = ST_INIT;
          else if ($c != '*')
            $state = ST_LONG_COMMENT;
          break;
      }
    }
    // Compute time elapsed
    $timeElapsed = microtime(true)-$startTS;
    fprintf($fDest, "\n// File generated in %.3f s\n", $timeElapsed);
 
    fclose($fSrc);
    fclose($fDest);
  }
  // Avoid class instantiation
  private function __construct() { }
}