/**
  * Test requesting an invalid output format.
  * @expectedException TimestampException
  * @covers ConvertibleTimestamp::getTimestamp
  */
 public function testInvalidOutput()
 {
     $timestamp = new ConvertibleTimestamp('1343761268');
     $timestamp->getTimestamp(98);
 }
Пример #2
0
 /**
  * Set the cached stat info for a file path.
  * Negatives (404s) are not cached. By not caching negatives, we can skip cache
  * salting for the case when a file is created at a path were there was none before.
  *
  * @param string $path Storage path
  * @param array $val Stat information to cache
  */
 protected final function setFileCache($path, array $val)
 {
     $path = FileBackend::normalizeStoragePath($path);
     if ($path === null) {
         return;
         // invalid storage path
     }
     $mtime = ConvertibleTimestamp::convert(TS_UNIX, $val['mtime']);
     $ttl = $this->memCache->adaptiveTTL($mtime, 7 * 86400, 300, 0.1);
     $key = $this->fileCacheKey($path);
     // Set the cache unless it is currently salted.
     $this->memCache->set($key, $val, $ttl);
 }
Пример #3
0
 public function timestamp($ts = 0)
 {
     $ct = new ConvertibleTimestamp($ts);
     return $ct->getTimestamp(TS_POSTGRES);
 }
Пример #4
0
 public function decodeExpiry($expiry, $format = TS_MW)
 {
     if ($expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity()) {
         return 'infinity';
     }
     return ConvertibleTimestamp::convert($format, $expiry);
 }
Пример #5
0
 protected function doGetFileStat(array $params)
 {
     $source = $this->resolveToFSPath($params['src']);
     if ($source === null) {
         return false;
         // invalid storage path
     }
     $this->trapWarnings();
     // don't trust 'false' if there were errors
     $stat = is_file($source) ? stat($source) : false;
     // regular files only
     $hadError = $this->untrapWarnings();
     if ($stat) {
         $ct = new ConvertibleTimestamp($stat['mtime']);
         return ['mtime' => $ct->getTimestamp(TS_MW), 'size' => $stat['size']];
     } elseif (!$hadError) {
         return false;
         // file does not exist
     } else {
         return null;
         // failure
     }
 }
Пример #6
0
 /**
  * Stream a file to the browser, adding all the headings and fun stuff.
  * Headers sent include: Content-type, Content-Length, Last-Modified,
  * and Content-Disposition.
  *
  * @param array $headers Any additional headers to send if the file exists
  * @param bool $sendErrors Send error messages if errors occur (like 404)
  * @param array $optHeaders HTTP request header map (e.g. "range") (use lowercase keys)
  * @param integer $flags Bitfield of STREAM_* constants
  * @throws MWException
  * @return bool Success
  */
 public function stream($headers = [], $sendErrors = true, $optHeaders = [], $flags = 0)
 {
     // Don't stream it out as text/html if there was a PHP error
     if ((($flags & self::STREAM_HEADLESS) == 0 || $headers) && headers_sent()) {
         echo "Headers already sent, terminating.\n";
         return false;
     }
     $headerFunc = $flags & self::STREAM_HEADLESS ? function ($header) {
         // no-op
     } : function ($header) {
         is_int($header) ? HttpStatus::header($header) : header($header);
     };
     MediaWiki\suppressWarnings();
     $info = stat($this->path);
     MediaWiki\restoreWarnings();
     if (!is_array($info)) {
         if ($sendErrors) {
             self::send404Message($this->path, $flags);
         }
         return false;
     }
     // Send Last-Modified HTTP header for client-side caching
     $mtimeCT = new ConvertibleTimestamp($info['mtime']);
     $headerFunc('Last-Modified: ' . $mtimeCT->getTimestamp(TS_RFC2822));
     if (($flags & self::STREAM_ALLOW_OB) == 0) {
         call_user_func($this->obResetFunc);
     }
     $type = call_user_func($this->streamMimeFunc, $this->path);
     if ($type && $type != 'unknown/unknown') {
         $headerFunc("Content-type: {$type}");
     } else {
         // Send a content type which is not known to Internet Explorer, to
         // avoid triggering IE's content type detection. Sending a standard
         // unknown content type here essentially gives IE license to apply
         // whatever content type it likes.
         $headerFunc('Content-type: application/x-wiki');
     }
     // Don't send if client has up to date cache
     if (isset($optHeaders['if-modified-since'])) {
         $modsince = preg_replace('/;.*$/', '', $optHeaders['if-modified-since']);
         if ($mtimeCT->getTimestamp(TS_UNIX) <= strtotime($modsince)) {
             ini_set('zlib.output_compression', 0);
             $headerFunc(304);
             return true;
             // ok
         }
     }
     // Send additional headers
     foreach ($headers as $header) {
         header($header);
         // always use header(); specifically requested
     }
     if (isset($optHeaders['range'])) {
         $range = self::parseRange($optHeaders['range'], $info['size']);
         if (is_array($range)) {
             $headerFunc(206);
             $headerFunc('Content-Length: ' . $range[2]);
             $headerFunc("Content-Range: bytes {$range[0]}-{$range[1]}/{$info['size']}");
         } elseif ($range === 'invalid') {
             if ($sendErrors) {
                 $headerFunc(416);
                 $headerFunc('Cache-Control: no-cache');
                 $headerFunc('Content-Type: text/html; charset=utf-8');
                 $headerFunc('Content-Range: bytes */' . $info['size']);
             }
             return false;
         } else {
             // unsupported Range request (e.g. multiple ranges)
             $range = null;
             $headerFunc('Content-Length: ' . $info['size']);
         }
     } else {
         $range = null;
         $headerFunc('Content-Length: ' . $info['size']);
     }
     if (is_array($range)) {
         $handle = fopen($this->path, 'rb');
         if ($handle) {
             $ok = true;
             fseek($handle, $range[0]);
             $remaining = $range[2];
             while ($remaining > 0 && $ok) {
                 $bytes = min($remaining, 8 * 1024);
                 $data = fread($handle, $bytes);
                 $remaining -= $bytes;
                 $ok = $data !== false;
                 print $data;
             }
         } else {
             return false;
         }
     } else {
         return readfile($this->path) !== false;
         // faster
     }
     return true;
 }
Пример #7
0
 /**
  * function to validate date properties, and convert to (partial) Exif format.
  *
  * Dates can be one of the following formats:
  * YYYY
  * YYYY-MM
  * YYYY-MM-DD
  * YYYY-MM-DDThh:mmTZD
  * YYYY-MM-DDThh:mm:ssTZD
  * YYYY-MM-DDThh:mm:ss.sTZD
  *
  * @param array $info Information about current property
  * @param mixed &$val Current value to validate. Converts to TS_EXIF as a side-effect.
  *    in cases where there's only a partial date, it will give things like
  *    2011:04.
  * @param bool $standalone If this is a simple property or array
  */
 public function validateDate($info, &$val, $standalone)
 {
     if (!$standalone) {
         // this only validates standalone properties, not arrays, etc
         return;
     }
     $res = [];
     // @codingStandardsIgnoreStart Long line that cannot be broken
     if (!preg_match('/^([0-3]\\d{3})(?:-([01]\\d)(?:-([0-3]\\d)(?:T([0-2]\\d):([0-6]\\d)(?::([0-6]\\d)(?:\\.\\d+)?)?([-+]\\d{2}:\\d{2}|Z)?)?)?)?$/D', $val, $res)) {
         // @codingStandardsIgnoreEnd
         $this->logger->info(__METHOD__ . " Expected date but got {$val}");
         $val = null;
     } else {
         /*
          * $res is formatted as follows:
          * 0 -> full date.
          * 1 -> year, 2-> month, 3-> day, 4-> hour, 5-> minute, 6->second
          * 7-> Timezone specifier (Z or something like +12:30 )
          * many parts are optional, some aren't. For example if you specify
          * minute, you must specify hour, day, month, and year but not second or TZ.
          */
         /*
          * First of all, if year = 0000, Something is wrongish,
          * so don't extract. This seems to happen when
          * some programs convert between metadata formats.
          */
         if ($res[1] === '0000') {
             $this->logger->info(__METHOD__ . " Invalid date (year 0): {$val}");
             $val = null;
             return;
         }
         if (!isset($res[4])) {
             // hour
             // just have the year month day (if that)
             $val = $res[1];
             if (isset($res[2])) {
                 $val .= ':' . $res[2];
             }
             if (isset($res[3])) {
                 $val .= ':' . $res[3];
             }
             return;
         }
         if (!isset($res[7]) || $res[7] === 'Z') {
             // if hour is set, then minute must also be or regex above will fail.
             $val = $res[1] . ':' . $res[2] . ':' . $res[3] . ' ' . $res[4] . ':' . $res[5];
             if (isset($res[6]) && $res[6] !== '') {
                 $val .= ':' . $res[6];
             }
             return;
         }
         // Extra check for empty string necessary due to TZ but no second case.
         $stripSeconds = false;
         if (!isset($res[6]) || $res[6] === '') {
             $res[6] = '00';
             $stripSeconds = true;
         }
         // Do timezone processing. We've already done the case that tz = Z.
         // We know that if we got to this step, year, month day hour and min must be set
         // by virtue of regex not failing.
         $unix = ConvertibleTimestamp::convert(TS_UNIX, $res[1] . $res[2] . $res[3] . $res[4] . $res[5] . $res[6]);
         $offset = intval(substr($res[7], 1, 2)) * 60 * 60;
         $offset += intval(substr($res[7], 4, 2)) * 60;
         if (substr($res[7], 0, 1) === '-') {
             $offset = -$offset;
         }
         $val = ConvertibleTimestamp::convert(TS_EXIF, $unix + $offset);
         if ($stripSeconds) {
             // If seconds weren't specified, remove the trailing ':00'.
             $val = substr($val, 0, -3);
         }
     }
 }