<?php
/*
 * Copyright (c) 2015 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.1.0
 */
namespace Peach\DF;
use Exception;

/**
 * UTF-8 文字列を Unicode 符号点に変換します.
 * このクラスは Utf8Codec からのみ使用されることを想定しています.
 * エンドユーザーがこのクラスのインスタンスを直接操作する機会はありません.
 *
 * @ignore
 */
class Utf8Context
{
    /**
     * decode 対象の UTF-8 文字列です.
     * @var string
     */
    private $text;

    /**
     * decode 対象の文字列のバイト長です.
     * @var int
     */
    private $length;

    /**
     * 現在のバイト位置です. (0 以上 $length 以下)
     * @var int
     */
    private $index;

    /**
     * 指定された UTF-8 文字列を処理する Utf8Context インスタンスを構築します.
     * @param string $text 解析対象の UTF-8 文字列
     */
    public function __construct($text)
    {
        $this->text   = $text;
        $this->length = strlen($text);
        $this->index  = 0;
    }

    /**
     * index を 1 進めると同時に次の文字を返します.
     * 次の index が存在しない場合は null を返します.
     *
     * @return int 現在の文字の Unicode 符号点
     */
    public function next()
    {
        if (!$this->hasNext()) {
            return null;
        }

        $first = substr($this->text, $this->index, 1);
        $byte  = ord($first);

        // ASCII の範囲の文字はそのまま返します
        if ($byte < 128) {
            $this->index++;
            return $byte;
        }

        // ビットが 10xxxxxx または 1111111* の文字は NG なのでスキップして次の文字に進みます
        if ($byte < 192 || 254 <= $byte) {
            $this->index++;
            return $this->next();
        }

        return $this->nextMultibyteChar($byte);
    }

    /**
     * 次の文字の Unicode 符号点を返します.
     * 解析対象の文字列が途中で切れている場合
     * (例えば次の 1 文字が 3 バイトであるにも関わらず, 解析対象の文字列が残り 2 バイトしかない等)
     * 足りないバイト列を 0x80 で補います.
     *
     * @param  int $byte 現在の文字のはじめの 1 byte
     * @return int 現在の文字の Unicode 符号点
     */
    private function nextMultibyteChar($byte)
    {
        $count  = $this->getCharCount($byte);
        $next   = substr($this->text, $this->index, $count);
        $length = strlen($next);
        if ($length < $count) {
            $next .= str_repeat(chr(0x80), $count - $length);
        }

        $code = $this->getUnicodeNumber($next);
        if ($code === null) {
            $this->index++;
            return $this->next();
        }
        $this->index += $length;
        return $code;
    }

    /**
     * 次の文字が存在するかどうかを調べます.
     *
     * @return bool 次の文字が存在する場合は true
     */
    public function hasNext()
    {
        return ($this->index < $this->length);
    }

    /**
     * 次の 1 文字が何バイトで構成されているかを計算します.
     * 引数に応じて以下の結果を返します. (以下 2 進数表示)
     *
     * <pre>
     * 1111110* => 6
     * 111110** => 5
     * 11110*** => 4
     * 1110**** => 3
     * 110***** => 2
     * </pre>
     *
     * @param  int $byte 次の文字の最初の 1 バイト
     * @return int       次の文字のバイト数
     */
    private function getCharCount($byte)
    {
        for ($i = 0; $i < 7; $i ++) {
            $bit = pow(2, 7 - $i); // 128, 64, 32, 16 ...
            if ($byte < $bit) {
                return max(1, $i);
            }
            $byte %= $bit;
        }

        // @codeCoverageIgnoreStart
        throw new Exception("Invalid State Error");
        // @codeCoverageIgnoreEnd
    }

    /**
     * 指定されたバイト列を Unicode 符号点に変換します.
     * 引数が不正なバイト列だった場合は null を返します.
     *
     * @param  string $str 次の 1 文字のバイト列
     * @return int         次の文字の Unicode 符号点
     */
    private function getUnicodeNumber($str)
    {
        $first  = ord($str);
        $length = strlen($str);
        $div    = pow(2, 7 - $length);

        // UNICODE の数値
        $bit = $first % $div;
        for ($i = 0; $i < $length - 1; $i ++) {
            $code = ord(substr($str, $i + 1, 1));
            // 2バイト目以降のビットが 10xxxxxx でない場合は不正なパターンとする
            if (intval($code / 64) !== 2) {
                return null;
            }
            $bit *= 64;
            $bit += $code % 64;
        }

        return $bit;
    }
}


<?php
/*
 * Copyright (c) 2014 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.0
 */
namespace Peach\DT;
use Peach\Util\Equator;
use Peach\Util\Values;

/**
 * 時間オブジェクトの比較を行うための Equator です.
 * このクラスは, 時間オブジェクトをキーとした {@link \Peach\Util\HashMap}
 * を構築する際に使用してください.
 */
class TimeEquator implements Equator
{
    /**
     * 比較対象のフィールドの配列です.
     * array("year", "month", "date")
     * のような文字列型の配列となります.
     *
     * @var array
     */
    private $fields;

    /**
     * 比較対象のフィールドを指定して, 新しい TimeEquator オブジェクトを作成します.
     * 引数の指定方法には以下の方法があります.
     *
     * <code>
     * new TimeEquator();
     * new TimeEquator(array("hour", "minute", "second"));
     * new TimeEquator("date");
     * new TimeEquator(Time::TYPE_DATE);
     * </code>
     *
     * 引数なしでオブジェクトを生成した場合, このオブジェクトは
     * {@link Time::equals()} を使って比較を行います.
     * 通常は, 引数なしのコンストラクタを使う代わりに
     * {@link TimeEquator::getDefault()} を使用してください.
     *
     * 引数に比較対象のフィールドを配列で指定した場合,
     * 指定されたフィールドすべてが等しい場合に等価とみなします.
     *
     * 比較対象のフィールドが 1 つだけの場合, そのフィールドを文字列で指定することもできます.
     *
     * また, 以下の定数を使用することもできます.
     *
     * - {@link Time::TYPE_DATE}
     * - {@link Time::TYPE_DATETIME}
     * - {@link Time::TYPE_TIMESTAMP}
     *
     * それぞれ
     *
     * - array("year", "month", "date")
     * - array("year", "month", "date", "hour", "minute")
     * - array("year", "month", "date", "hour", "minute", "second")
     *
     * を指定した場合と同じになります.
     *
     * @param mixed $fields 比較対象のフィールド一覧
     */
    public function __construct($fields = null)
    {
        $this->fields = $this->initFields($fields);
    }

    /**
     * このオブジェクトの比較対象フィールド一覧を初期化します.
     *
     * @param  mixed $fields
     * @return array
     */
    private function initFields($fields)
    {
        switch ($fields) {
            case Time::TYPE_DATE:
                return $this->initFields(array("year", "month", "date"));
            case Time::TYPE_DATETIME:
                return $this->initFields(array("year", "month", "date", "hour", "minute"));
            case Time::TYPE_TIMESTAMP:
                return $this->initFields(array("year", "month", "date", "hour", "minute", "second"));
        }

        if (is_array($fields)) {
            return count($fields) ? $fields : null;
        }
        if (is_string($fields)) {
            return array($fields);
        }

        return null;
    }

    /**
     * デフォルトの Equator オブジェクトを返します.
     * このオブジェクトは {@link Time::equals()} を使って等値性を調べます.
     * @return TimeEquator
     */
    public static function getDefault()
    {
        static $instance = null;
        if (!isset($instance)) {
            $instance = new self();
        }
        return $instance;
    }

    /**
     * 指定された 2 つの時間オブジェクトが等しいかどうか調べます.
     * この Equator に設定されているフィールドについて比較を行い,
     * 全て等しい場合のみ TRUE を返します.
     *
     * @param  Time $var1 比較対象の時間オブジェクト
     * @param  Time $var2 比較対象の時間オブジェクト
     * @return bool       2 つの時間オブジェクトが等しいと判断された場合のみ TRUE
     * @throws \InvalidArgumentException 引数に Time インスタンス以外の値が指定された場合
     */
    public function equate($var1, $var2)
    {
        if (!($var1 instanceof Time) || !($var2 instanceof Time)) {
            $arg1 = Values::getType($var1);
            $arg2 = Values::getType($var2);
            throw new \InvalidArgumentException("arguments must be Time instance.({$arg1}, {$arg2})");
        }

        $fields = $this->fields;
        if (isset($fields)) {
            foreach ($fields as $field) {
                if ($var1->get($field) !== $var2->get($field)) {
                    return false;
                }
            }
            return true;
        } else {
            return $var1->equals($var2);
        }
    }

    /**
     * 年・月・日・時・分・秒の各フィールドからハッシュ値を算出します.
     *
     * @param  mixed $var
     * @return int        ハッシュ値
     * @throws \InvalidArgumentException 引数が Time インスタンスでなかった場合
     */
    public function hashCode($var)
    {
        if (!($var instanceof Time)) {
            $type = Values::getType($var);
            throw new \InvalidArgumentException("The value must be Time instance.({$type})");
        }

        return
            $var->get("year")              +
            $var->get("month")  *       31 +  // 31^1
            $var->get("date")   *      961 +  // 31^2
            $var->get("hour")   *    29791 +  // 31^3
            $var->get("minute") *   923521 +  // 31^4
            $var->get("second") * 28629151;   // 31^5
    }
}


<?php

namespace sndsgd\fs\entity;

class FileEntity extends EntityAbstract
{
    /**
     * @inheritDoc
     */
    public function test(int $opts): bool
    {
        return parent::test($opts | \sndsgd\Fs::FILE);
    }

    /**
     * @inheritDoc
     */
    public function canWrite(): bool
    {
        if (file_exists($this->path)) {
            return $this->test(\sndsgd\Fs::WRITABLE);
        }
        return (($dir = $this->getParent()) !== null && $dir->canWrite());
    }

    /**
     * @inheritDoc
     */
    public function prepareWrite($mode = 0775): bool
    {
        if (file_exists($this->path)) {
            return $this->test(\sndsgd\Fs::WRITABLE);
        }

        $dir = $this->getParent();
        if ($dir->prepareWrite($mode) === false) {
            $this->error =
                "failed to prepare '{$this->path}' for writing; ".$dir->getError();
            return false;
        }
        return true;
    }

    /**
     * Get the file's parent directory
     *
     * @aliasof ::getParent
     * @return \sndsgd\fs\entity\DirEntity
     */
    public function getDir(): DirEntity
    {
        return $this->getParent();
    }

    /**
     * Determine if the entity has a given extension
     *
     * @param string $extension
     * @return bool
     */
    public function hasExtension(string $extension): bool
    {
        $test = $this->getExtension();
        return (strcasecmp($extension, $test) === 0);
    }

    /**
     * @param string $default The value to return when no extension exists
     * @return string
     */
    public function getExtension(string $default = ""): string
    {
        $extension = $this->splitName()[1];
        return ($extension === "") ? $default : $extension;
    }

    /**
     * Retrieve the file name with or without an extension
     *
     * @return string
     */
    public function getName(bool $includeExtension = false): string
    {
        $filename = basename($this->path);
        if ($includeExtension) {
            return $filename;
        }

        return $this->splitName()[0];
    }

    /**
     * Separate a filename and extension
     *
     * bug (??) with pathinfo():
     * [http://bugs.php.net/bug.php?id=67048](http://bugs.php.net/bug.php?id=67048)
     *
     * Example Usage:
     * <code>
     * $path = '/path/to/file.txt';
     * list($name, $ext) = File::splitName($path);
     * // => ['file', 'txt']
     * $ext = File::splitName($path)[1];
     * // => 'txt'
     * </code>
     *
     * @param string $defaultExtension
     * @return array
     * - [0] string name
     * - [1] string|null extension
     */
    public function splitName(string $defaultExtension = ""): array
    {
        $filename = basename($this->path);
        $extpos = strrpos($filename, ".");
        if ($extpos === false || $extpos === 0) {
            $name = $filename;
            $ext = $defaultExtension;
        }
        else {
            $name = substr($filename, 0, $extpos);
            $ext = substr($filename, $extpos + 1);
        }
        return [$name, $ext];
    }

    /**
     * Get the byte size of the file
     *
     * @return int `-1` if the size could not be determined
     */
    public function getByteSize(): int
    {
        if ($this->test(\sndsgd\Fs::READABLE) !== true) {
            $this->error = "failed to stat filesize; {$this->error}";
            return -1;
        }
        $bytes = @filesize($this->path);
        if ($bytes === false) {
            $this->setError("failed to stat filesize for '{$this->path}'");
            return -1;
        }
        return $bytes;
    }

    /**
     * Get the filesize as a formatted string
     *
     * @param int $precision The number of decimal places to return
     * @param string $point The decimal point
     * @param string $sep The thousands separator
     * @return string An empty string if the size could not be determined
     */
    public function getSize(
        int $precision = 0,
        string $point = ".",
        string $sep = ","
    ): string
    {
        $bytes = $this->getByteSize();
        if ($bytes === -1) {
            return "";
        }
        return \sndsgd\Fs::formatSize($bytes, $precision, $point, $sep);
    }

    /**
     * Prepare and write to the file
     *
     * @param string $contents
     * @param int $opts Bitmask options to pass to `file_put_contents`
     * @return bool
     */
    public function write(string $contents, int $opts = 0): bool
    {
        if ($this->prepareWrite() !== true) {
            $this->error = "failed to write '{$this->path}; {$this->error}";
            return false;
        }
        return $this->writeFile($contents, $opts);
    }

    /**
     * @param string $contents
     * @param int $opts
     * @return bool
     */
    private function writeFile(string $contents, int $opts = 0): bool
    {
        if (@file_put_contents($this->path, $contents, $opts) === false) {
            $this->setError("file to write '{$this->path}'");
            return false;
        }
        return true;
    }

    /**
     * Prepend contents to a file
     *
     * @param string $contents The content to prepend to the file
     * @param int $maxMemory The max number of bytes to consume
     * @return bool
     */
    public function prepend(string $contents, int $maxMemory = 8096): bool
    {
        $test = \sndsgd\Fs::EXISTS | \sndsgd\Fs::READABLE | \sndsgd\Fs::WRITABLE;
        if ($this->test($test) === false) {
            $this->error = "failed to prepend file; {$this->error}";
            return false;
        }

        $len = strlen($contents);
        $size = filesize($this->path);
        $endsize = $len + $size;

        # if the overall filesize is greater than `maxMemory`, write efficiently
        if ($endsize > $maxMemory) {
            return $this->prependFileInPlace($contents, $len, $endsize);
        }

        # use file_get/put_contents to handle the operation
        if (($tmp = $this->readFile(0)) === false) {
            return false;
        }

        if ($this->writeFile($contents.$tmp, 0) === false) {
            return false;
        }

        return true;
    }

    /**
     * @param string $contents
     * @param int $len
     * @param int $endsize
     * @return bool
     */
    private function prependFileInPlace(
        string $contents,
        int $len,
        int $endsize
    ): bool
    {
        $fh = fopen($this->path, "r+");
        $oldcontent = fread($fh, $len);
        rewind($fh);

        $i = 1;
        while (ftell($fh) < $endsize) {
            fwrite($fh, $contents);
            $contents = $oldcontent;
            $oldcontent = fread($fh, $len);
            fseek($fh, $i * $len);
            $i++;
        }
        return true;
    }

    /**
     * Convenience method for appending to a file
     *
     * @param string $contents The contents to append
     * @return bool
     */
    public function append(string $contents): bool
    {
        return $this->write($contents, FILE_APPEND);
    }

    /**
     * Read the contents of the file
     *
     * @param int $offset The position to start reading from
     * @return bool|string
     * @return string The contents of the file on success
     * @return false If the file could not be read
     */
    public function read(int $offset = 0)
    {
        if ($this->test(\sndsgd\Fs::EXISTS | \sndsgd\Fs::READABLE) === false) {
            $this->error = "failed to read file; {$this->error}";
            return false;
        }
        return $this->readFile($offset);
    }

    /**
     * @param int $offset
     * @return string|false
     */
    private function readFile(int $offset)
    {
        $ret = @file_get_contents($this->path, false, null, $offset);
        if ($ret === false) {
            $this->setError("read operation failed on '{$this->path}'");
            return false;
        }
        return $ret;
    }

    /**
     * Delete the file
     *
     * @return bool
     */
    public function remove(): bool
    {
        if (@unlink($this->path) === false) {
            $this->setError("failed to delete '{$this->path}");
            return false;
        }
        return true;
    }

    /**
     * Get the number of lines in the file
     *
     * @return int
     */
    public function getLineCount(): int
    {
        $ret = 0;
        $fh = fopen($this->path, "r");
        while (!feof($fh)) {
            $buffer = fread($fh, 8192);
            $ret += substr_count($buffer, PHP_EOL);
        }
        fclose($fh);
        return $ret;
    }
}


<?php
/*
This is part of Wedeto, the WEb DEvelopment TOolkit.
It is published under the MIT Open Source License.

Copyright 2017, Egbert van der Wal

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Wedeto\Application\Dispatch;

use Wedeto\Util\Functions as WF;
use Wedeto\HTTP\URL;
use Wedeto\HTTP\Accept;
use Wedeto\I18n\Locale;

/**
 * A VirtualHost is one site location managed by this Wedeto setup.
 * It can be different domain names but can also be several paths
 * on the same host.
 *
 * Each site can have multiple VirtualHosts that serve the same content,
 * but with different locales.
 */
class VirtualHost
{
    /** The base URL of this virtualhost */
    protected $url;

    /** The site this virtual host belongs to */
    protected $site = null;

    /** A redirect target if this virtual host should redirect to somewhere else */
    protected $redirect;

    /** The locales provided by this virtual host */
    protected $locales;

    /**
     * Set up a VirtualHost using a hostname and one or more languages
     * Languages can also be null to support any locale.
     * @param string $hostname The hostname to construct
     * @param mixed $locale null, a locale or an array of locales
     */
    public function __construct($hostname, $locale)
    {
        $this->url = new URL($hostname);
        $this->locales = array();
        $this->setLocale($locale);
    }

    /**
     * Set the site where this virtual host belongs to
     * @param Wedeto\Application\Site $site The site
     * @return Wedeto\Application\VirtualHost Provides fluent interface
     */
    public function setSite(Site $site)
    {
        $this->site = $site;
    }

    /**
     * @return Wedeto\Application\Site The site this VirtualHost belongs to
     */
    public function getSite()
    {
        return $this->site;
    }

    /**
     * Check if this VirtualHost matches the locale. A VirtualHost that is
     * a redirect will never match.
     *
     * @param string $locale The locale to match
     * @return boolean True if it matches, false if not
     */
    public function matchLocale($locale)
    {
        $locale = Locale::create($locale);
        if (!empty($this->redirect))
            return false;

        if ($locale === null)
            return true;

        foreach ($this->locales as $l)
            if ($l->getLocale() == $locale->getLocale())
                return true;

        return false;
    }

    /**
     * Find the best match between the locales this virtual host supports
     * and the locales the client accepts.
     *
     * @param Accept $header The HTTP Accept header
     * @return string The best matching locale
     */
    public function selectLocaleFromAcceptHeader(Accept $header)
    {
        // Collect a list of all supported locales
        $my_locales = [];

        foreach ($this->locales as $supported_locale)
        {
            $list = $supported_locale->getFallbackList();
            foreach ($list as $locale)
                $my_locales[$locale->getLocale()] = $supported_locale->getLocale();
        }

        $best = $header->getBestResponseType(array_keys($my_locales));
        return empty($best) ? null : ($my_locales[$best] ?? null);
    }

    /**
     * @return array The locales supported by this VirtualHost
     */
    public function getLocales()
    {
        return $this->locales;
    }

    /**
     * Set the locales supported by this VirtualHost.
     * @param mixed $locale Can be one locale or an array of locales
     * @return Wedeto\Application\VirtualHost Provides fluent interface
     */
    public function setLocale($locale)
    {
        $locale = WF::cast_array($locale);
        foreach ($locale as $l)
            $this->locales[] = new Locale($l);

        // Remove duplicate locales
        $this->locales = array_unique($this->locales);
        return $this;
    }

    /**
     * Configure this VirtualHost to be a redirect to another location
     * @param mixed $hostname A string or a URL object where to redirect to. Can be empty to disable redirecting
     * @return Wedeto\Application\VirtualHost Provides fluent interface
     */
    public function setRedirect($hostname)
    {
        if (!empty($hostname))
        {
            $this->redirect = new URL($hostname);
            $this->redirect->set('path', rtrim($this->redirect->path, '/'));
        }
        else
            $this->redirect = false;
        return $this;
    }

    /**
     * Return a URL on the current VirtualHost with the path appended.
     * @param string $path The path to resolve
     * @param mixed $current_url The current URL. If this is provided and the
     *                           host and scheme match, they are omitted in the result.
     * @return Wedeto\HTTP\URL The resolved URL
     */
    public function URL($path = '', $current_url = null)
    {
        $url = new URL($this->url);
        $path = ltrim($path, '/');
        $url->set('path', $url->path . $path);

        if ($current_url instanceof URL)
        {
            if ($url->host === $current_url->host && $url->scheme === $current_url->scheme && $url->port === $current_url->port)
            {
                $url->host = null;
                $url->scheme = null;
            }
        }
        return $url;
    }

    /**
     * @return Wedeto\HTTP\URL The URL of this VirtualHost
     */
    public function getHost()
    {
        return $this->url;
    }

    /**
     * Extract the path of the provided URL that is below the webroot of this VirtualHost
     *
     * @param string $url The URL to get the path from
     * @return string The path relative to this VirtualHost
     */
    public function getPath($url)
    {
        $url = new URL($url);
        $to_replace = $this->url->path;
        $path = $url->path;

        if (strpos($path, $to_replace) === 0)
            $path = substr($path, strlen($to_replace));

        $path = '/' . urldecode($path);
        return $path;
    }

    /**
     * @return bool If the VirtualHost uses https
     */
    public function isSecure()
    {
        return $this->url->scheme === "https";
    }

    /**
     * @return bool If the VirtualHost is prefixed with www
     */
    public function hasWWW()
    {
        return strtolower(substr($this->url->host, 0, 4)) === "www.";
    }

    /**
     * @param string $webroot The current webroot
     * @return bool If the VirtualHost matches the provided URL
     */
    public function match($webroot)
    {
        $url = new URL($webroot);
        if ($url->host !== $this->url->host || $url->scheme !== $this->url->scheme)
            return false;

        $path = $this->url->path;
        $wrpath = $url->path;
        return substr($wrpath, 0, strlen($path)) === $path;
    }

    /**
     * @param string $url The visited URL
     * @return Wedeto\HTTP\URL The URL to redirect to, or null if no redirect is needed
     */
    public function getRedirect($url)
    {
        if (empty($this->redirect))
            return null;

        $url = new URL($url);
        $path = $this->getPath($url);

        $target = new URL($this->redirect);
        $target->setPath($path);

        return $target;
    }
}


<?php

namespace Maduser\Minimal\Paths;

use Maduser\Minimal\Config\Contracts\ConfigInterface;
use Maduser\Minimal\Http\Contracts\RequestInterface;

/**
 * Class PathGenerator
 *
 * @package Maduser\Minimal\Paths
 */
class PathGenerator
{
    /**
     * @var ConfigInterface|null
     */
    private $config;

    /**
     * @var RequestInterface|null
     */
    private $request;

    /**
     * @return ConfigInterface
     */
    public function getConfig(): ConfigInterface
    {
        return $this->config;
    }

    /**
     * @param ConfigInterface $config
     *
     * @return PathGenerator
     */
    public function setConfig(ConfigInterface $config): PathGenerator
    {
        $this->config = $config;

        return $this;
    }

    /**
     * @return RequestInterface
     */
    public function getRequest(): RequestInterface
    {
        return $this->request;
    }

    /**
     * @param RequestInterface $request
     *
     * @return PathGenerator
     */
    public function setRequest(RequestInterface $request): PathGenerator
    {
        $this->request = $request;

        return $this;
    }

    /**
     * PathGenerator constructor.
     *
     * @param ConfigInterface|null  $config
     * @param RequestInterface|null $request
     */
    public function __construct(
        ConfigInterface $config = null,
        RequestInterface $request = null
    ) {
        $this->config = $config;
        $this->request = $request;
    }

    /**
     * @param string|null $item
     * @param bool        $fromRoot
     *
     * @return string
     */
    public function path(string $item = null, bool $fromRoot = true): string
    {
        $system = rtrim($this->config->item('paths.system'), '/') . '/';

        if (is_null($item)) {
            return $system;
        }

        $path = '';

        switch ($item) {
            case 'app':
                $path = rtrim($this->config->item('paths.app'), '/') . '/';
                break;
            case 'modules':
                $path = rtrim($this->config->item('paths.modules'), '/') . '/';
                break;
            case 'resources':
                $path = rtrim($this->config->item('paths.resources'),
                        '/') . '/';
                break;
            case 'views':
                $path = rtrim($this->config->item('paths.views'), '/') . '/';
                break;
            case 'storage':
                $path = rtrim($this->config->item('paths.storage'), '/') . '/';
                break;
            case 'translations':
                $path = $this->config->item('paths.translations');
                break;
            default:
                $path = $this->config->item('paths.' . $item);
                break;
        }

        ! $fromRoot || $path = $system . $path;

        return $path;
    }

    /**
     * @param null|string $item
     *
     * @return string
     */
    public function http(string $item = null): string
    {
        $base = $this->request->getBaseUri();
        empty($base) || $base = $base . '/';

        $base = '/' . ltrim($base, '/');

        if (is_null($item)) {
            return $base;
        }

        $host = $this->request->getHttp();
        $path = '';

        $_host = $this->config->item('paths.host');

        !empty($_host) || $_host = $this->request->getHost();

        switch ($item) {
            case 'host':
                $host .= rtrim($_host, '/') . '/';
                break;
            case 'base':
                $host .= rtrim($_host, '/') . $base;
                break;
            default:
                $path = path($item, false);
                break;
        }

        return $host . $path;
    }

}


<?php
//
// +---------------------------------------------------------------------+
// | CODE INC. SOURCE CODE                                               |
// +---------------------------------------------------------------------+
// | Copyright (c) 2017 - Code Inc. SAS - All Rights Reserved.           |
// | Visit https://www.codeinc.fr for more information about licensing.  |
// +---------------------------------------------------------------------+
// | NOTICE:  All information contained herein is, and remains the       |
// | property of Code Inc. SAS. The intellectual and technical concepts  |
// | contained herein are proprietary to Code Inc. SAS are protected by  |
// | trade secret or copyright law. Dissemination of this information or |
// | reproduction of this material  is strictly forbidden unless prior   |
// | written permission is obtained from Code Inc. SAS.                  |
// +---------------------------------------------------------------------+
//
// Author:   Joan Fabrégat <joan@codeinc.fr>
// Date:     07/03/2018
// Time:     02:05
// Project:  Psr15Middlewares
//
declare(strict_types = 1);
namespace CodeInc\Psr15Middlewares\HttpHeaders\Security;
use CodeInc\Psr15Middlewares\HttpHeaders\AbstractHttpHeaderMiddleware;
use CodeInc\Psr15Middlewares\MiddlewareException;
use CodeInc\Psr15Middlewares\Tests\HttpHeaders\Security\ContentSecurityPolicyMiddlewareTest;

/**
 * Class ContentSecurityPolicyMiddleware
 *
 * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy
 * @see ContentSecurityPolicyMiddlewareTest
 * @package CodeInc\Psr15Middlewares\HttpHeaders\Security
 * @author Joan Fabrégat <joan@codeinc.fr>
 */
class ContentSecurityPolicyMiddleware extends AbstractHttpHeaderMiddleware
{
	public const SRC_SELF  = '\'self\'';
	public const SRC_NONE  = '\'none\'';

	// values for the referer policy
	public const REFERER_POLICY_NONE = 'none';
	public const REFERER_POLICY_NO_REFERRER = 'no-referrer';
	public const REFERER_POLICY_NONE_WHEN_DOWNGRADE = 'none-when-downgrade';
	public const REFERER_POLICY_ORIGIN = 'origin';
	public const REFERER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN = 'origin-when-cross-origin';
	public const REFERER_POLICY_ORIGIN_WHEN_CROSSORIGIN = 'origin-when-crossorigin';
	public const REFERER_POLICY_UNSAFE_URL = 'unsafe-url';
	public const REFERER_POLICY_VALUES = [
        self::REFERER_POLICY_NONE, self::REFERER_POLICY_NO_REFERRER, self::REFERER_POLICY_NONE_WHEN_DOWNGRADE,
        self::REFERER_POLICY_ORIGIN, self::REFERER_POLICY_ORIGIN_WHEN_CROSS_ORIGIN,
        self::REFERER_POLICY_ORIGIN_WHEN_CROSSORIGIN, self::REFERER_POLICY_UNSAFE_URL,
    ];

	// values for the sandbox
    public const SANDBOX_ALLOW_FORMS = 'allow-forms';
    public const SANDBOX_ALLOW_MODALS = 'allow-modals';
    public const SANDBOX_ALLOW_ORIENTATION_LOCK = 'allow-orientation-lock';
    public const SANDBOX_ALLOW_POINTER_LOCK = 'allow-pointer-lock';
    public const SANDBOX_ALLOW_POPUPS = 'allow-popups';
    public const SANDBOX_ALLOW_POPUPS_TO_ESCAPE_SANDBOX = 'allow-popups-to-escape-sandbox';
    public const SANDBOX_ALLOW_PRESENTATION = 'allow-presentation';
    public const SANDBOX_ALLOW_SAME_ORIGIN = 'allow-same-origin';
    public const SANDBOX_ALLOW_SCRIPTS = 'allow-scripts';
    public const SANDBOX_ALLOW_TOP_NAVIGATION = 'allow-top-navigation';
    public const SANDBOX_VALUES = [
        self::SANDBOX_ALLOW_FORMS, self::SANDBOX_ALLOW_MODALS, self::SANDBOX_ALLOW_ORIENTATION_LOCK,
        self::SANDBOX_ALLOW_POINTER_LOCK, self::SANDBOX_ALLOW_POPUPS, self::SANDBOX_ALLOW_POPUPS_TO_ESCAPE_SANDBOX,
        self::SANDBOX_ALLOW_PRESENTATION, self::SANDBOX_ALLOW_SAME_ORIGIN, self::SANDBOX_ALLOW_SCRIPTS,
        self::SANDBOX_ALLOW_TOP_NAVIGATION
    ];

    /**
     * CSP tags.
     *
     * @var string[][]|string[]|bool[]|null[]
     */
	private $tags = [
        'default-src' => [],
	    'base-uri' => [],
        'child-src' => [],
        'connect-src' => [],
        'font-src' => [],
	    'form-action' => [],
	    'frame-ancestors' => [],
	    'frame-src' => [],
	    'img-src' => [],
	    'manifest-src' => [],
	    'media-src' => [],
	    'object-src' => [],
	    'script-src' => [],
	    'style-src' => [],
	    'worker-src' => [],
        'referer' => null,
        'plugin-types' => [],
        'report-uri' => [],
        'require-sri-for' => [],
        'sandbox' => null,
        'upgrade-insecure-requests' => false,
        'block-all-mixed-content' => false,

    ];

    /**
     * ContentSecurityPolicyMiddleware constructor.
     */
	public function __construct()
	{
        parent::__construct('Content-Security-Policy');
	}

    /**
     * Enable the 'upgrade-insecure-requests' flag or the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests
     */
	public function upgradeInsecureRequests():void
    {
        $this->tags['upgrade-insecure-requests'] = true;
    }

    /**
     * Enable the 'block-all-mixed-content' flag of the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content
     */
    public function blockAllMixedContent():void
    {
        $this->tags['block-all-mixed-content'] = true;
    }

    /**
     * Sets the 'sandbox' value of the CSP. See the SANDBOX_XYZ class constants for the possible values.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
     * @param string $sandbox
     * @throws MiddlewareException
     */
    public function setSandbox(string $sandbox):void
    {
        if (!in_array($sandbox, self::SANDBOX_VALUES)) {
            throw new MiddlewareException(
                $this,
                sprintf(
                    "%s is not a correct value for the CSP sandbox, correct values are: %s (see %s)",
                    $sandbox, implode(', ', self::SANDBOX_VALUES),
                    'https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox'
                )
            );
        }
        $this->tags['sandbox'] = $sandbox;
    }

    /**
     * Sets the 'referrer' value of the CSP. See the REFERER_POLICY_XYZ class constants for the possible values.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/referrer
     * @param string $refererPolicy
     * @throws MiddlewareException
     */
    public function setRefererPolicy(string $refererPolicy):void
    {
        if (!in_array($refererPolicy, self::REFERER_POLICY_VALUES)) {
            throw new MiddlewareException(
                $this,
                sprintf(
                    "%s is not a valid CSP referer policy, correct values are: %s (see %s)",
                    $refererPolicy, implode(', ', self::REFERER_POLICY_VALUES),
                    'https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/referrer'
                )
            );
        }
        $this->tags['referer'] = $refererPolicy;
    }

    /**
     * Sets the 'require-sri-for' value of the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/require-sri-for
     * @param bool $script
     * @param bool $style
     */
    public function requireSriFor(bool $script, bool $style):void
    {
        if ($script && $style) {
            $this->tags['require-sri-for'] = ['script', 'style'];
        }
        else if ($script) {
            $this->tags['require-sri-for'] = ['script'];
        }
        else if ($style) {
            $this->tags['require-sri-for'] = ['style'];
        }
    }

    /**
     * Sets the CSP's report URI.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri
     * @param string $reportUri
     * @throws MiddlewareException
     * @return bool
     */
    public function addReportUri(string $reportUri):bool
    {
        if (!filter_var($reportUri, FILTER_VALIDATE_URL)) {
            throw new MiddlewareException(
                $this,
                sprintf(
                    "'%s' is not a valid URI and can not be set as the CSP report URI",
                    $reportUri
                )
            );
        }
        if (!in_array($reportUri, $this->tags['report-uri'])) {
            $this->tags['report-uri'][] = $reportUri;
            return true;
        }
        return false;
    }

    /**
     * Add a new plugin media type ot the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/plugin-types
     * @param string $mediaType
     * @throws MiddlewareException
     * @return bool
     */
    public function addPluginType(string $mediaType):bool
    {
        if (!preg_match('#^[-\w]+/[-\w]+$#ui', $mediaType)) {
            throw new MiddlewareException(
                $this,
                sprintf(
                    "'%s' is not a valid media type and can not be used as a CSP plugin type",
                    $mediaType
                )
            );
        }
        if (!in_array($mediaType, $this->tags['plugin-types'])) {
            $this->tags['plugin-types'][] = $mediaType;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'default-src' source to the CSP.
     *
     * @param string $source
     * @return bool
     */
    public function addDefaultSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['default-src'])) {
            $this->tags['default-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'base-uri' to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri
     * @param string $source
     * @return bool
     */
    public function addBaseUri(string $source):bool
    {
        if (!in_array($source, $this->tags['base-uri'])) {
            $this->tags['base-uri'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'child-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/child-src
     * @param string $source
     * @return bool
     */
    public function addChildSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['child-src'])) {
            $this->tags['child-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'connect-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src
     * @param string $source
     * @return bool
     */
    public function addConnectSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['connect-src'])) {
            $this->tags['connect-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'font-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/font-src
     * @param string $source
     * @return bool
     */
    public function addFontSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['font-src'])) {
            $this->tags['font-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'form-action' to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/form-action
     * @param string $source
     * @return bool
     */
    public function addFormAction(string $source):bool
    {
        if (!in_array($source, $this->tags['form-action'])) {
            $this->tags['form-action'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'frame-ancestors' to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
     * @param string $source
     * @return bool
     */
    public function addFrameAncestors(string $source):bool
    {
        if (!in_array($source, $this->tags['frame-ancestors'])) {
            $this->tags['frame-ancestors'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'frame-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src
     * @param string $source
     * @return bool
     */
    public function addFrameSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['frame-src'])) {
            $this->tags['frame-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'img-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/img-src
     * @param string $source
     * @return bool
     */
    public function addImgSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['img-src'])) {
            $this->tags['img-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'manifest-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/manifest-src
     * @param string $source
     * @return bool
     */
    public function addManifestSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['manifest-src'])) {
            $this->tags['manifest-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'media-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/media-src
     * @param string $source
     * @return bool
     */
    public function addMediaSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['media-src'])) {
            $this->tags['media-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'object-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/object-src
     * @param string $source
     * @return bool
     */
    public function addObjectSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['object-src'])) {
            $this->tags['object-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'script-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
     * @param string $source
     * @return bool
     */
    public function addScriptSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['script-src'])) {
            $this->tags['script-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'style-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
     * @param string $source
     * @return bool
     */
    public function addStyleSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['style-src'])) {
            $this->tags['style-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Adds a 'worker-src' source to the CSP.
     *
     * @link https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src
     * @param string $source
     * @return bool
     */
    public function addWorkerSrc(string $source):bool
    {
        if (!in_array($source, $this->tags['worker-src'])) {
            $this->tags['worker-src'][] = $source;
            return true;
        }
        return false;
    }

    /**
     * Returns the CSP header value.
     *
     * @return string|null
     */
    public function getHeaderValue():?string
    {
        $headerValue = [];
        foreach ($this->tags as $name => $tagValue) {
            if (is_array($tagValue) && !empty($tagValue)) {
                $headerValue[] = $name.' '.implode(' ', $tagValue).';';
            }
            elseif (is_string($tagValue) && !empty($tagValue)) {
                $headerValue[] = $name.' '.$tagValue.';';
            }
            elseif (is_bool($tagValue) && $tagValue) {
                $headerValue[] = $name.';';
            }
        }
        return $headerValue ? implode(' ', $headerValue) : null;
    }
}


<?php

declare(strict_types=1);

namespace Netgen\Bundle\SiteInstallerBundle\Installer;

use EzSystems\PlatformInstallerBundle\Installer\DbBasedInstaller;
use EzSystems\PlatformInstallerBundle\Installer\Installer;

abstract class BaseInstaller extends DbBasedInstaller implements Installer
{
    /**
     * Handle inserting of schema, schema should ideally be in ISO SQL format.
     *
     * Schema file is created with: mysqldump ngsite --no-data > schema.sql
     */
    protected function importSchemaFile(string $schemaFile, string $controlTableName = null): void
    {
        if ($controlTableName !== null) {
            if ($this->db->getSchemaManager()->tablesExist([$controlTableName])) {
                $this->output->writeln('<comment>Schema already exists in the database, skipping schema import for file <info>' . $schemaFile . '</info></comment>');

                return;
            }
        }

        $this->runQueriesFromFile($schemaFile);
    }

    /**
     * Handle inserting of sql dump, sql dump should ideally be in ISO SQL format.
     *
     * Data file is created with: mysqldump ngsite --no-create-info --extended-insert=false > data.sql
     */
    protected function importDataFile(string $dataFile, string $controlTableName = null): void
    {
        if ($controlTableName !== null) {
            $query = $this->db->createQueryBuilder();
            $query->select('count(*) AS count')
                ->from($controlTableName);

            $data = $query->execute()->fetchAll();

            $contentCount = (int) $data[0]['count'];
            if ($contentCount > 0) {
                $this->output->writeln('<comment>Data already exists in the database, skipping data import for file <info>' . $dataFile . '</info></comment>');

                return;
            }
        }

        $this->runQueriesFromFile($dataFile);
    }
}


<?php

namespace Data\Type;

use SplSubject;
use Data\Type\Traits\SplSubject as SplSubjectTrait;

abstract class Type implements SplSubject
{
    use SplSubjectTrait;

    /**
     * @var mixed
     */
    protected $value;

    /**
     * Constructor
     *
     * @param mixed $value
     */
    public function __construct($value = null)
    {
        $this->set($value);
    }

    /**
     * Set the value
     *
     * @param  mixed $value
     * @return this
     */
    public function set($value)
    {
        if ($value !== null) {
            $value = $this->check($value);
        }

        if ($value !== $this->value) {
            $this->value = $value;
            $this->notify();
        }

        return $this;
    }

    /**
     * Get the value
     *
     * @return mixed
     */
    public function value()
    {
        return $this->value;
    }

    /**
     * Check the value
     *
     * @param  mixed $value
     * @return mixed
     */
    protected function check($value)
    {
        if ($value instanceof Type) {
            $value = $value->value;
        }

        return $value;
    }

    /**
     * Cast instance to string
     *
     * @return string
     */
    public function __toString()
    {
        if ($this->value === false) {
            return '0';
        }

        return (string) $this->value;
    }
}


<?php
/*
 * Copyright (c) 2014 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.0
 */
namespace Peach\DT;
use Peach\Util\Values;
use Peach\Util\Strings;
use Peach\Util\Map;
use Peach\Util\ArrayMap;

/**
 * 時間を表す抽象基底クラスです.
 * {@link Date}, {@link Datetime}, {@link Timestamp}
 * の共通部分の実装です.
 */
abstract class AbstractTime implements Time
{
    /**
     * 年フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $YEAR   = 0;

    /**
     * 月フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $MONTH  = 1;

    /**
     * 日フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $DATE   = 2;

    /**
     * 時フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $HOUR   = 3;

    /**
     * 分フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $MINUTE = 4;

    /**
     * 秒フィールドのキーです
     * @var int
     * @ignore
     */
    protected static $SECOND = 5;

    /**
     * 年・月・日などの各種フィールドです.
     *
     * @var Map
     * @ignore
     */
    protected $fields;

    /**
     * 指定されたフィールドの値を取得します.
     * @param  string $field フィールド名
     * @return int           対象フィールドの値. ただしフィールド名が不正な場合は NULL
     */
    public final function get($field)
    {
        $index = $this->getFieldIndex($field);
        return $this->fields->get($index);
    }

    /**
     * この時間オブジェクトの指定されたフィールドを上書きします.
     *
     * @param  string $field フィールド名
     * @param  int    $value 設定する値
     * @return Time          設定後の時間オブジェクト
     */
    public final function set($field, $value)
    {
        $index     = $this->getFieldIndex($field);
        $newFields = new ArrayMap($this->fields);
        $newFields->put($index, $value);
        return $this->newInstance($newFields);
    }

    /**
     * この時間オブジェクトの複数のフィールドを一度に上書きします.
     * 引数には,
     * <code>
     * array("year" => 2010, "month" => 8, "date" => 31)
     * </code>
     * などの配列か, または同様の Map オブジェクトを指定してください.
     *
     * @param  Map|array $subject フィールドと値の一覧
     * @return Time               設定後の時間オブジェクト
     * @throws \InvalidArgumentException 引数の型が不正な場合
     */
    public final function setAll($subject)
    {
        if (is_array($subject)) {
            $subject = new ArrayMap($subject);
        }
        if (!($subject instanceof Map)) {
            throw new \InvalidArgumentException("Argument (" . Values::getType($subject) . ") must be array or \\Peach\\Util\\Map");
        }
        $newFields = new ArrayMap($this->fields);
        $entryList = $subject->entryList();
        foreach ($entryList as $entry) {
            $index = $this->getFieldIndex($entry->getKey());
            $newFields->put($index, $entry->getValue());
        }
        return $this->newInstance($newFields);
    }

    /**
     * 引数のフィールドを, $amount だけ増加 (負の場合は減少) させます.
     * @param  string $field  対象のフィールド
     * @param  int    $amount 加算する量. マイナスの場合は過去方向に移動する.
     * @return Time           設定後の時間オブジェクト
     */
    public final function add($field, $amount)
    {
        $newFields = new ArrayMap($this->fields);
        $key       = $this->getFieldIndex($field);
        $current   = $this->fields->get($key);
        $newFields->put($key, $current + $amount);
        return $this->newInstance($newFields);
    }

    /**
     * この時間と指定された時間を比較します.
     * このメソッドは, 自身と引数の時間オブジェクトが共通で持っているフィールドについて比較を行います.
     * 比較の結果すべてのフィールドの値が等しかった場合,
     * より多くの時間フィールドを持つほうが「後」となります.
     *
     * 例: 2012-05-21 (Date) < 2012-05-21T00:00 (Datetime) < 2012-05-21T00:00:00 (Timestamp)
     *
     * @param  mixed $obj 比較対象のオブジェクト
     * @return int        この時間のほうが過去の場合は負の値, 未来の場合は正の値, 等しい場合は 0.
     *                    ただし, 引数が時間オブジェクトでない場合は NULL
     */
    public final function compareTo($obj)
    {
        if ($obj instanceof Time) {
            $c = $this->compareFields($obj);
            return ($c !== 0) ? $c : $this->getType() - $obj->getType();
        } else {
            return null;
        }
    }

    /**
     * 指定されたフォーマットを使ってこの時間オブジェクトを書式化します.
     * フォーマットを指定しない場合はデフォルトの方法 (SQL などで使われる慣用表現) で書式化を行ないます.
     * @param  Format $format
     * @return string 時間オブジェクトの文字列表現 (例: "YYYY-MM-DD" など)
     */
    public final function format(Format $format = null)
    {
        return isset($format) ? $this->handleFormat($format) : $this->__toString();
    }

    /**
     * 指定されたオブジェクトとこのオブジェクトを比較します.
     * compareTo による比較結果が 0 を返し, かつクラスが同じ場合に TRUE を返します.
     *
     * @param  mixed   $obj 比較対象のオブジェクト
     * @return bool         二つのオブジェクトが等しい場合に TRUE, それ以外は FALSE
     */
    public function equals($obj)
    {
        if (get_class($this) !== get_class($obj)) {
            return false;
        }
        return $this->compareTo($obj) === 0;
    }

    /**
     * 指定された時間とこの時間を比較します.
     *
     * もしもこのオブジェクトが持つ時間フィールドすべてが
     * 引数のオブジェクトの時間フィールドと一致した場合,
     * より多くの時間フィールドを持つほうが「後」となります.
     *
     * 例: 2012-05-21 (Date) < 2012-05-21T00:00 (Datetime) < 2012-05-21T00:00:00 (Timestamp)
     *
     * @param  Time $time 比較対象の時間
     * @return bool       この時間のほうが過去である場合は TRUE, それ以外は FALSE
     */
    public final function before(Time $time)
    {
        $c = $this->compareTo($time);
        return isset($c) && ($c < 0);
    }

    /**
     * 指定された時間とこの時間を比較します.
     *
     * もしもこのオブジェクトが持つ時間フィールドすべてが
     * 引数のオブジェクトの時間フィールドと一致した場合,
     * より多くの時間フィールドを持つほうが「後」となります.
     *
     * 例: 2012-05-21 (Date) < 2012-05-21T00:00 (Datetime) < 2012-05-21T00:00:00 (Timestamp)
     *
     * @param  Time $time 比較対象の時間
     * @return bool       この時間のほうが未来である場合は TRUE, それ以外は FALSE
     */
    public final function after(Time $time)
    {
        $c = $this->compareTo($time);
        return isset($c) && (0 < $c);
    }

    /**
     * この時間の時刻 (時・分・秒) 部分を書式化します.
     * 時・分・秒をサポートしていないオブジェクトの場合は空文字列を返します.
     *
     * @return string "hh:mm:ss" 形式の文字列. このオブジェクトが時刻をサポートしない場合は空文字列.
     */
    public function formatTime()
    {
        return "";
    }

    /**
     * このオブジェクトが指す時刻を, SQL などで使われる慣用表現に変換して返します.
     *
     * @return string このオブジェクトの文字列表現 ("YYYY-MM-DD", "YYYY-MM-DD hh:mm" など)
     * @codeCoverageIgnore
     */
    public function __toString()
    {
        return (string) $this;
    }

    /**
     * 指定されたフィールドを使ってこの時間オブジェクトを初期化します.
     * サブクラスはこのメソッドを継承して独自の初期化処理を行ないます.
     *
     * @param  Map $fields
     * @ignore
     */
    protected function init(Map $fields)
    {
        $this->adjust($fields);
        $this->fields = $fields;
    }

    /**
     * 時間の不整合を調整します.
     * 例えば, 0 から 23 までの値を取るはずの「時」のフィールドが
     * 24 以上の値を持っていた場合に, 日付の繰上げ処理を行うなどの操作を行います.
     *
     * このメソッドはサブクラスのコンストラクタ内で参照されます.
     *
     * @param Map フィールド一覧
     * @ignore
     */
    protected abstract function adjust(Map $fields);

    /**
     * 指定されたフィールドを持つ新しいインスタンスを構築します.
     *
     * @param  Map 各種フィールド
     * @return Time
     * @ignore
     */
    protected abstract function newInstance(Map $fields);

    /**
     * このオブジェクトと指定された時間オブジェクトについて,
     * 共通するフィールド同士を比較します.
     * このメソッドは compareTo() から参照されます.
     *
     * @param  Time $time
     * @return int
     * @see    Time::compareTo
     * @ignore
     */
    protected abstract function compareFields(Time $time);

    /**
     * 指定されたフォーマットを使ってこの時間オブジェクトを書式化します.
     * このメソッドは format() から参照されます.
     *
     * @param  Format $format
     * @return string
     * @see    Time::format
     * @ignore
     */
    protected abstract function handleFormat(Format $format);

    /**
     * 指定された日付の曜日を返します. 返される値は 0 から 6 までの整数で, 0 が日曜, 6 が土曜をあらわします.
     * プログラム内で各曜日を表現する場合は, ソースコード内に数値を直接書き込む代わりに
     * Time::SUNDAY や Time::SATURDAY などの定数を使ってください.
     *
     * @param  int $y 年
     * @param  int $m 月
     * @param  int $d 日
     * @return int 曜日 (0 以上 6 以下の整数)
     *
     * @see    Date::SUNDAY
     * @see    Date::MONDAY
     * @see    Date::TUESDAY
     * @see    Date::WEDNESDAY
     * @see    Date::THURSDAY
     * @see    Date::FRIDAY
     * @see    Date::SATURDAY
     * @ignore
     */
    protected static function getDayOf($y, $m, $d)
    {
        static $m_sub = array(0, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4);
        if ($m < 3) {
            $y --;
        }
        return ($y + intval($y / 4) - intval($y / 100) + intval($y / 400) + $m_sub[$m] + $d) % 7;
    }

    /**
     * 指定されたフィールド名を $fields のインデックスに変換します.
     * 不正なフィールド名の場合は -1 を返します.
     *
     * @param  string $field フィールド名
     * @return int           インデックス
     *
     * @see    Time::$YEAR
     * @see    Time::$MONTH
     * @see    Time::$DATE
     * @see    Time::$HOUR
     * @see    Time::$MINUTE
     * @see    Time::$SECOND
     * @codeCoverageIgnore
     */
    private function getFieldIndex($field)
    {
        static $mapping = null;
        if (!isset($mapping)) {
            $mapping = array(
                "y"  => self::$YEAR,
                "mo" => self::$MONTH,
                "d"  => self::$DATE,
                "h"  => self::$HOUR,
                "m"  => self::$MINUTE,
                "s"  => self::$SECOND
            );
        }

        $field = strtolower($field);
        foreach ($mapping as $key => $index) {
            if (Strings::startsWith($field, $key)) {
                return $index;
            }
        }
        return -1;
    }
}


<?php

/**
 * Time object
 *
 * @package    RpkUtils\Converter
 * @author     Repkit <repkit@gmail.com>
 * @copyright  2015 Repkit
 * @license    MIT <http://opensource.org/licenses/MIT>
 * @since      2015-11-12
 */

 namespace RpkUtils\Converter;

 class Time
 {
    /**
     * Convert seconds into human readeble time
     * @param int $seconds
     * @return string
    */
    public static function sec2time($seconds)
    {
        $sec = intval($seconds);
        $dtF = new \DateTime("@0");
        $dtT = new \DateTime("@$sec");
        return $dtF->diff($dtT)->format('%a days, %h hours, %i minutes and %s seconds');
    }
 }


<?php

/**
 * This file is part of RawPHP - a PHP Framework.
 *
 * Copyright (c) 2014 RawPHP.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * PHP version 5.3
 *
 * @category  PHP
 * @package   RawPHP\RawRouter
 * @author    Tom Kaczocha <tom@rawphp.org>
 * @copyright 2014 Tom Kaczocha
 * @license   http://rawphp.org/license.txt MIT
 * @link      http://rawphp.org/
 */

namespace RawPHP\RawRouter;

use RawPHP\RawDispatcher\Contract\IDispatcher;
use RawPHP\RawDispatcher\Contract\IEvent;
use RawPHP\RawDispatcher\Contract\IListener;
use RawPHP\RawRouter\Contract\IAction;
use RawPHP\RawRouter\Contract\IController;
use RawPHP\RawRouter\Event\AfterControllerRunEvent;
use RawPHP\RawRouter\Event\BeforeControllerRunEvent;
use RawPHP\RawRouter\Event\Events;
use RawPHP\RawRouter\Event\GetViewsDirEvent;
use RawPHP\RawSupport\Exception\RawException;

/**
 * Base controller class which all other controllers in the application
 * will extend.
 *
 * @category  PHP
 * @package   RawPHP\RawRouter
 * @author    Tom Kaczocha <tom@rawphp.org>
 * @copyright 2014 Tom Kaczocha
 * @license   http://rawphp.org/license.txt MIT
 * @link      http://rawphp.org/
 */
abstract class Controller implements IController, IListener
{
    /** @var  IAction */
    protected $action = NULL;
    /** @var  string */
    protected $pageView = '';
    /** @var  IDispatcher */
    protected $dispatcher;

    /**
     * Initialises the controller and attach default listeners.
     */
    public function addDefaultListeners()
    {
        $this->dispatcher->addListener( Events::EVENT_BEFORE_CONTROLLER_RUN, $this );
        $this->dispatcher->addListener( Events::EVENT_AFTER_CONTROLLER_RUN, $this );
    }

    /**
     * Default index action for controller.
     *
     * Subclasses should ALWAYS override this method.
     */
    public abstract function indexAction();

    /**
     * Runs the controller action.
     */
    public function run()
    {
        $event = new BeforeControllerRunEvent();

        $this->dispatcher->fire( Events::EVENT_BEFORE_CONTROLLER_RUN, $event );

        $action = $this->action->getName();

        if ( $this->action->hasParams() )
        {
            call_user_func_array( [
                                      $this,
                                      $action
                                  ],
                                  $this->action->getParams()
            );
        }
        else
        {
            $this->$action();
        }

        $event = new AfterControllerRunEvent();

        $this->dispatcher->fire( Events::EVENT_AFTER_CONTROLLER_RUN, $event );
    }

    /**
     * Callback called before the controller run method executes.
     */
    public function onBeforeAction()
    {
        $this->pageView = '';
    }

    /**
     * Callback called after the controller run method executes.
     *
     * This callback action is a good time to cleanup after the
     * controller.
     */
    public function onAfterAction()
    {
        $view = $this->pageView;

        echo $view;
    }

    /**
     * Loads a view file.
     *
     * This method requires Controller::ON_GET_VIEWS_DIR_FILTER to have
     * a valid callback assigned to the path of the view files.
     *
     * @param array $data   data to make available to the views as variables
     * @param bool  $return whether to return the view to the calling method
     *
     * @return mixed view html string on success, FALSE on error
     *
     * @throws RawException if there is something wrong.
     */
    public function loadView( $data = [ ], $return = FALSE )
    {
        $retVal = NULL;
        //$extraData = $this->filter( self::ON_LOAD_EXTRA_DATA_FILTER, [ ] );

        $extra = [
            'route' => $this->_getRoute(),
        ];

        extract( $extra, EXTR_OVERWRITE );
        //extract( $extraData, EXTR_OVERWRITE );
        extract( $data, EXTR_OVERWRITE );

        $level = error_reporting();
        error_reporting( 0 );

        ob_start();

        if ( isset( $view ) )
        {
            $viewsDirEvent = new GetViewsDirEvent();

            $this->dispatcher->fire( Events::EVENT_GET_VIEWS_DIR, $viewsDirEvent );

            $viewDir = $viewsDirEvent->getViewsDir();

            if ( NULL === $viewDir )
            {
                throw new RawException( 'The views directory has not been set.' );
            }

            if ( FALSE !== strstr( $view, '.php' ) )
            {
                include $viewDir . $view;
            }
            else
            {
                include $viewDir . $view . '.php';
            }

            $newView = ob_get_clean();

            if ( $return )
            {
                $retVal = $newView;
            }
            else
            {
                $this->pageView .= $newView;
            }
        }
        else
        {
            $retVal = '';
        }

        error_reporting( $level );

        return $retVal;
    }

    /**
     * Helper method to work out the current route.
     *
     * @return string the route
     */
    private function _getRoute()
    {
        $action = str_replace( 'Action', '', $this->action->getName() );
        $action = explode( '\\', $action );
        $action = strtolower( $action[ 0 ] );

        $cls = str_replace( 'Controller', '', get_class( $this ) );
        $cls = strtolower( $cls );

        $path = explode( '\\', $cls );
        $path = $path[ count( $path ) - 1 ] . '/' . $action;

        if ( $this->action->hasParams() )
        {
            foreach ( $this->action->getParams() as $param )
            {
                $path .= '/' . $param;
            }
        }

        return $path;
    }

    /**
     * Redirects the browser to new location.
     *
     * @param string $url the redirection url
     */
    public function redirect( $url )
    {
        $location = $url;

        header( 'Location: ' . $location );
        exit();
    }

    /**
     * Handle an event.
     *
     * @param IEvent      $event
     * @param string      $name
     * @param IDispatcher $dispatcher
     */
    public function handle( IEvent $event, $name, IDispatcher $dispatcher )
    {
        if ( $event instanceof BeforeControllerRunEvent )
        {
            return $this->onBeforeAction();
        }
        elseif ( $event instanceof AfterControllerRunEvent )
        {
            return $this->onAfterAction();
        }
    }

    /**
     * Get the event dispatcher.
     *
     * @return IDispatcher
     */
    public function getDispatcher()
    {
        return $this->dispatcher;
    }

    /**
     * Set the dispatcher.
     *
     * @param IDispatcher $dispatcher
     */
    public function setDispatcher( IDispatcher $dispatcher )
    {
        $this->dispatcher = $dispatcher;
    }

    /**
     * Get the controller action.
     *
     * @return IAction
     */
    public function getAction()
    {
        return $this->action;
    }

    /**
     * Set the controller action.
     *
     * @param IAction $action
     */
    public function setAction( IAction $action )
    {
        $this->action = $action;
    }

    /**
     * Get the page view.
     *
     * @return string
     */
    public function getPageView()
    {
        return $this->pageView;
    }

    /**
     * Set the page view.
     *
     * @param string $pageView
     */
    public function setPageView( $pageView )
    {
        $this->pageView = $pageView;
    }
}


<?php
/*
This is part of Wedeto, the WEb DEvelopment TOolkit.
It is published under the MIT Open Source License.

Copyright 2017, Egbert van der Wal

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Wedeto\Application\Task;

use Wedeto\Util\Hook;
use Wedeto\Application\CLI\CLI;
use Wedeto\Application\Application;
use Wedeto\Application\Module\Manager as ModuleManager;

use Wedeto\Log\Logger;
use Wedeto\Log\Writer\StreamWriter;

/**
 * The TaskRunner collects and runs tasks. It is also used by the scheduler to
 * run periodic jobs
 */
class TaskRunner
{
    /** The list of available tasks */
    protected $task_list = array();

    /** If the tasks were already located */
    protected $init = false;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    /**
     * Add a task to the list of registered tasks
     * @param $task string The class name of the task
     * @param $description string The description of the task
     */
    public function registerTask(string $task, string $description)
    {
        $this->task_list[$task] = $description;
    }

    /**
     * Find tasks in all registered modules. This method calls registerTasks on
     * all modules that have been registered, giving them the opportunity to register
     * their tasks.
     */
    private function findTasks()
    {
        if ($this->init)
            return;

        $resolver = $this->app->moduleManager;
        $modules = $resolver->getModules();
        foreach ($modules as $mod)
            $mod->registerTasks($this);

        // Provide a way to register tasks using a hook
        Hook::execute("Wedeto.Application.Task.TaskRunner.findTasks", ['taskrunner' => $this]);
        $this->init = true;
    }

    /**
     * List the registered tasks
     * @param $ostr resource The output stream to write to. Defaults to STDOUT
     */
    public function listTasks($ostr = STDOUT)
    {
        $this->findTasks();
        if (count($this->task_list) === 0)
        {
			// @codeCoverageIgnoreStart
            fprintf($ostr, "No tasks available\n");
			// @codeCoverageIgnoreEnd
        }
        else
        {
            fprintf($ostr, "Listing available tasks: \n");

            foreach ($this->task_list as $task => $desc)
            {
                $task = str_replace('\\', ':', $task);
                fprintf($ostr, "- %-30s", $task);
                CLI::formatText(32, CLI::MAX_LINE_LENGTH, ' ' . $desc, $ostr);
            }
            printf("\n");
        }
    }

    /**
     * Run the specified task.
     *
     * @param string $task The task to run - classname. It may use : rather
     *                     than \ as a namespace separator
     * @param resource $ostr The stream to send output to
     * @return bool True on success, false on failure
     */
    public function run(string $task, $ostr = STDERR)
    {
        // CLI uses : because \ is used as escape character, so that
        // awkward syntax is required.
        $task = str_replace(":", "\\", $task);

        $log = Logger::getLogger('');
        $log->addLogWriter(new StreamWriter(STDOUT));

        if (!class_exists($task))
        {
            fprintf($ostr, "Error: task does not exist: {$task}\n");
            return false;
        }

        try
        {
            if (!is_subclass_of($task, TaskInterface::class))
            {
                fprintf($ostr, "Error: invalid task: {$task}\n");
                return false;
            }
            $taskrunner = new $task;
            $taskrunner->execute();
        }
        catch (\Throwable $e)
        {
            fprintf($ostr, "Error: error while running task: %s\n", $task);
            fprintf($ostr, "Exception: %s\n", get_class($e));
            fprintf($ostr, "Message: %s\n", $e->getMessage());
            if (method_exists($e, "getLine"))
                fprintf($ostr, "On: %s (line %d)\n", $e->getFile(), $e->getLine());
            fprintf($ostr, $e->getTraceAsString() . "\n");
            return false;
        }
        return true;
    }
}


<?php
/**
 * This file is part of the "litgroup/sms" package.
 *
 * (c) Roman Shamritskiy <roman@litgroup.ru>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace LitGroup\Sms;

use LitGroup\Sms\Exception\InvalidArgumentException;

/**
 * Message.
 *
 * @author Roman Shamritskiy <roman@litgroup.ru>
 *
 * @api
 */
class Message
{
    /**
     * @var string
     */
    private $sender;

    /**
     * @var string[]
     */
    private $recipients;

    /**
     * @var string
     */
    private $body;

    /**
     * Message constructor.
     *
     * @param string $body Text of message (UTF-8 string).
     * @param string[] $recipients List of phone numbers of recipients. Phone number should be in the format
     *                             "+7000123456789" or "7000123456789".
     * @param null $sender Identifier of sender. (For example "MyCompany"). Identifier should be allowed by
     *                     SMS-Gateway provider.
     */
    public function __construct($body, array $recipients, $sender = null)
    {
        $this->setBody($body);
        $this->setRecipients($recipients);
        $this->setSender($sender);
    }

    /**
     * Returns the message body.
     *
     * @return string
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * Returns the length of the message body in a number of characters.
     *
     * @return integer
     */
    public function getLength()
    {
        return mb_strlen($this->getBody(), 'UTF-8');
    }

    /**
     * Returns list of phone number of recipients.
     *
     * @return string[]
     */
    public function getRecipients()
    {
        return $this->recipients;
    }

    /**
     * Returns the name of sender.
     *
     * @return string|null
     */
    public function getSender()
    {
        return $this->sender;
    }

    /*
     * @param string $body
     */
    private function setBody($body)
    {
        if (is_null($body)) {
            throw new InvalidArgumentException('Body of message cannot be null');
        }

        if (!is_string($body)) {
            throw new InvalidArgumentException(
                sprintf(
                    'Body of message must be a string, but "%s" given',
                    is_object($body) ? get_class($body) : gettype($body)
                )
            );
        }

        if (mb_strlen($body, 'UTF-8') === 0) {
            throw new InvalidArgumentException('Body of message cannot be an empty string');
        }

        $this->body = (string) $body;
    }

    /**
     * Sets/replaces list of recipients.
     *
     * @param string[] $recipients A list of phone numbers in the one of formats: "+71234567890" or "71234567890".
     *
     * @throws \InvalidArgumentException If one of recipients is not a string or format is invalid.
     */
    private function setRecipients(array $recipients)
    {
        if (count($recipients) === 0) {
            throw new InvalidArgumentException('At least one recipient required');
        }

        $this->recipients = [];
        foreach ($recipients as $recipient) {
            $this->addRecipient($recipient);
        }
    }

    /**
     * @param string $recipient A phone number in the one of formats: "+71234567890" or "71234567890".
     *
     * @throws \InvalidArgumentException If $recipient is not a string or format is invalid.
     */
    private function addRecipient($recipient)
    {
        if (is_null($recipient)) {
            throw new InvalidArgumentException('Recipient cannot be NULL');
        }

        if (!is_string($recipient)) {
            throw new InvalidArgumentException(
                sprintf(
                    'Recipient must be presented as string, but "%s" given',
                    is_object($recipient) ? get_class($recipient) : gettype($recipient)
                )
            );
        }

        if (\preg_match('/^\+\d+$/Ds', $recipient) != 1) {
            throw new InvalidArgumentException(
                sprintf(
                    'Recipient must match pattern \+\d+, but "%s" does not match',
                    $recipient
                )
            );
        }

        array_push($this->recipients, $recipient);
    }

    /**
     * @param string $sender
     */
    private function setSender($sender)
    {
        if (is_null($sender)) {
            return;
        }

        if (!is_string($sender)) {
            throw new InvalidArgumentException(
                sprintf(
                    'Sender must be presented as string, but "%s" given',
                    is_object($sender) ? get_class($sender) : gettype($sender)
                )
            );
        }

        if (mb_strlen(trim($sender), 'UTF-8') === 0) {
            throw new InvalidArgumentException('Sender cannot be an empty string or contains whitespaces only');
        }

        $this->sender = $sender;
    }
}


<?php
/**
 * Phossa Project
 *
 * PHP version 5.4
 *
 * @category  Library
 * @package   Phossa\Query
 * @author    Hong Zhang <phossa@126.com>
 * @copyright 2015 phossa.com
 * @license   http://mit-license.org/ MIT License
 * @link      http://www.phossa.com/
 */
/*# declare(strict_types=1); */

namespace Phossa\Query\Clause;

/**
 * GroupByTrait
 *
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     GroupByInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait GroupByTrait
{
    /**
     * GROUP BYs
     *
     * @var    array
     * @access protected
     */
    protected $clause_groupby = [];

    /**
     * {@inheritDoc}
     */
    public function groupBy($col, /*# bool */ $rawMode = false)
    {
        if (is_array($col)) {
            foreach ($col as $c) {
                $this->groupBy($c, $rawMode);
            }
        } else {
            $this->clause_groupby[] = [
                $rawMode ?: $this->isRaw($col), $col
            ];
        }
        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function groupByRaw(/*# string */ $groupby)
    {
        return $this->groupBy($groupby, true);
    }

    /**
     * Build GROUP BY
     *
     * @return array
     * @access protected
     */
    protected function buildGroupBy()/*# : array */
    {
        $result = [];
        foreach ($this->clause_groupby as $grp) {
            $result[] = $grp[0] ? $grp[1] : $this->quote($grp[1]);
        }
        return $result;
    }

    /* utilities from UtilityTrait */
    abstract protected function isRaw(/*# string */ $string)/*# : bool */;
    abstract protected function quote(/*# string */ $str)/*# : string */;
}


<?php
/**
 * Phossa Project
 *
 * PHP version 5.4
 *
 * @category  Library
 * @package   Phossa\Query
 * @author    Hong Zhang <phossa@126.com>
 * @copyright 2015 phossa.com
 * @license   http://mit-license.org/ MIT License
 * @link      http://www.phossa.com/
 */
/*# declare(strict_types=1); */

namespace Phossa\Query\Clause;

/**
 * ColTrait
 *
 * @trait
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     ColInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait ColTrait
{
    /**
     * DISTINCT
     *
     * @var    bool
     * @access protected
     */
    protected $clause_distinct = false;

    /**
     * FIELDS or COLUMNS
     *
     * @var    array
     * @access protected
     */
    protected $clause_column   = [];

    /**
     * {@inheritDoc}
     */
    public function distinct()
    {
        $this->clause_distinct = true;
        return $this;
    }

    /**
     * {@inheritDoc}
     */
    public function col(
        $col = '',
        /*# string */ $colAlias = ''
    ) {
        return $this->realCol($col, $colAlias);
    }

    /**
     * {@inheritDoc}
     */
    public function field(
        $col = '',
        /*# string */ $colAlias = ''
    ) {
        return $this->realCol($col, $colAlias);
    }

    /**
     * {@inheritDoc}
     */
    public function colRaw($string, /*# string */ $alias = '')
    {
        return $this->realCol($string, $alias, true);
    }

    /**
     * {@inheritDoc}
     */
    public function fieldRaw($string, /*# string */ $alias = '')
    {
        return $this->realCol($string, $alias, true);
    }

    /**
     * {@inheritDoc}
     */
    protected function realCol(
        $col = '',
        /*# string */ $colAlias = '',
        $rawMode = false
    ) {
        // col array definition
        if (is_array($col)) {
            foreach ($col as $key => $val) {
                if (is_int($key)) {
                    $key = $val;
                    $val = '';
                }
                $this->realCol($key, $val, $rawMode);
            }

        // clear columns
        } else if ('*' === $col) {
            $this->clause_column = [];

        // add columns
        } elseif (!empty($col)) {
            // auto raw mode detect
            $rawMode = $rawMode ?: $this->isRaw($col);

            if ('' === $colAlias) {
                $this->clause_column[] = [$rawMode, $col];
            } else {
                $this->clause_column[(string) $colAlias] = [$rawMode, $col];
            }
        }
        return $this;
    }

    /**
     * Build columns
     *
     * @return array
     * @access protected
     */
    protected function buildCol()/*# : array */
    {
        $result = [];

        // all cols
        if (empty($this->clause_column)) {
            $result[] = '*';

        // specific cols
        } else {
            foreach ($this->clause_column as $as => $col) {
                // col alias
                $alias = is_int($as) ? '' : (' AS ' . $this->quoteSpace($as));

                // rawMode ?
                $field = $col[0] ? $col[1] : $this->quote($col[1]);

                // function ?
                if (isset($col[2])) {
                    $field = sprintf($col[2], $field);
                }
                $result[] = $field . $alias;
            }
        }
        return $result;
    }

    /**
     * Build DISTINCT
     *
     * @return array
     * @access protected
     */
    protected function buildDistinct()/*# : array */
    {
        $result = [];
        if ($this->clause_distinct) {
            $result[] = 'DISTINCT';
        }
        return $result;
    }

    /* utilities from UtilityTrait */
    abstract protected function isRaw($str)/*# : bool */;
    abstract protected function quote(/*# string */ $str)/*# : string */;
    abstract protected function quoteSpace(/*# string */ $str)/*# : string */;
}


<?php
/**
 *
 * LICENCE
 *
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE.txt', which is part of this source code package.
 *
 * @author Schwartz Michaël
 * @copyright Copyright (c) EPOKMEDIA SARL
 *
 */

namespace Epkm\MessagePackRpc;

use Epkm\MessagePackRpc\Exception\NetworkErrorException;
use Epkm\MessagePackRpc\Exception\ProtocolErrorException;
use Zend\Serializer\Adapter\MsgPack;
use Zend\Stdlib\ErrorHandler;

/**
 * Class Back
 *
 * @package Epkm\MessagePackRpc
 */
class Back {

    /**
     * @var int
     */
    protected $size;

    /**
     * @var resource
     */
    public $clientSocket = null;

    /**
     * @var bool
     */
    public $reuseConnection = true;

    /**
     * @param int   $size
     * @param array $opts
     */
    public function __construct($size = 1024, $opts = array())
    {
        $this->size = $size;
        $this->serializer = new MsgPack();

        if (array_key_exists('reuse_connection', $opts)) {
            $this->reuseConnection = $opts['reuse_connection'];
        }
    }

    public function __destruct()
    {
        if ($this->clientSocket) {
            fclose($this->clientSocket);
        }
    }

    /**
     * @param $code
     * @param $func
     * @param $args
     *
     * @return array
     */
    public function clientCallObject($code, $func, $args)
    {
        $data    = array();
        $data[0] = 0;
        $data[1] = $code;
        $data[2] = $func;
        $data[3] = $args;

        return $data;
    }

    /**
     * @param $host
     * @param $port
     * @param $call
     *
     * @return string
     * @throws Exception\NetworkErrorException
     */
    public function clientConnection($host, $port, $call)
    {
        $size = $this->size;
        $send = $this->serializer->serialize($call);
        $sock = $this->connect($host, $port);

        if ($sock === false) {
            throw new NetworkErrorException("Cannot open socket");
        }

        ErrorHandler::start();
        $puts = fwrite($sock, $send);
        $error = ErrorHandler::stop();

        if ($puts === false) {
            throw new NetworkErrorException("Cannot write to socket", 0, $error);
        }

        ErrorHandler::start();
        $read = fread($sock, $size);
        $error = ErrorHandler::stop();

        if ($read === false) {
            throw new NetworkErrorException("Cannot read from socket", 0, $error);
        }

        if (!$this->reuseConnection) {
            ErrorHandler::start();
            fclose($sock);
            ErrorHandler::stop();
        }

        return $read;
    }

    /**
     * @param $host
     * @param $port
     *
     * @return null|resource
     */
    public function connect($host, $port) {

        if (!$this->reuseConnection) {
            ErrorHandler::start();
            $sock = fsockopen($host, $port);
            ErrorHandler::stop();

            return $sock;
        }

        $sock = $this->clientSocket;

        if ($sock && !feof($sock)) {
            return $sock;
        }

        if (!$sock) {
            ErrorHandler::start();
            $sock = fsockopen($host, $port);
            ErrorHandler::stop();
        } else if (feof($sock)) {
            ErrorHandler::start();
            $sock = fsockopen($host, $port);
            ErrorHandler::stop();
        }

        $this->clientSocket = $sock;

        return $sock;
    }

    /**
     * @param $recv
     *
     * @return Future
     * @throws Exception\ProtocolErrorException
     */
    public function clientRecvObject($recv)
    {
        $data = $this->serializer->unserialize($recv);

        $type = $data[0];
        $code = $data[1];
        $errs = $data[2];
        $sets = $data[3];

        if ($type != 1) {
            throw new ProtocolErrorException("Invalid message type for response: {$type}");
        }

        $feature = new Future();
        $feature->setErrors($errs);
        $feature->setResult($sets);

        return $feature;
    }

    /**
     * @param $code
     * @param $sets
     * @param $errs
     *
     * @return string
     */
    public function serverSendObject($code, $sets, $errs)
    {
        $data    = array();
        $data[0] = 1;
        $data[1] = $code;
        $data[2] = $errs;
        $data[3] = $sets;

        $send = $this->serializer->serialize($data);

        return $send;
    }

    /**
     * @param  mixed $recv
     *
     * @return array
     * @throws Exception\ProtocolErrorException
     */
    public function serverRecvObject($recv)
    {
        $data = $this->serializer->unserialize($recv);

        if (count($data) != 4) {
            throw new ProtocolErrorException("Invalid message structure.");
        }

        $type = $data[0];
        $code = $data[1];
        $func = $data[2];
        $args = $data[3];

        if ($type != 0) {
            throw new ProtocolErrorException("Invalid message type for request: {$type}");
        }

        return array($code, $func, $args);
    }

    /**
     * @return int
     */
    public function getSize()
    {
        return $this->size;
    }

}


<?php
/*
 * Copyright (c) 2015 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.2.0
 */
namespace Peach\Http\Header;

use InvalidArgumentException;
use Peach\Http\SingleHeaderField;
use Peach\Util\Values;

/**
 * HTTP レスポンスのステータスを表すクラスです.
 *
 * このクラスは HTTP/1 におけるステータスライン, HTTP/2 における :status 擬似ヘッダーを表現します.
 */
class Status implements SingleHeaderField
{
    /**
     * 3 桁の数字から成る文字列です.
     *
     * @var string
     */
    private $code;

    /**
     * HTTP ステータスの "Reason-phrase" をあらわす文字列です.
     *
     * @var string
     */
    private $reasonPhrase;

    /**
     * 指定されたステータスコードおよび Reason-Phrase からなる Status インスタンスを構築します.
     *
     * @param string $code         "200", "404" など, 3 桁の数字から成る文字列
     * @param string $reasonPhrase "OK", "Not Found" など, HTTP ステータスの Reason-Phrase に相当する文字列 (省略可能)
     */
    public function __construct($code, $reasonPhrase = "")
    {
        $this->code         = $this->cleanCode($code);
        $this->reasonPhrase = $reasonPhrase;
    }

    /**
     * 引数を 3 桁の数字文字列に変換します.
     *
     * @param  mixed  $code ステータスコードをあらわす文字列または整数
     * @return string 3 桁の数字から成る文字列
     * @throws InvalidArgumentException 引数がステータスコードとして妥当ではない場合
     */
    private function cleanCode($code)
    {
        $value = Values::stringValue($code);
        if (!strlen($value)) {
            throw new InvalidArgumentException("Code must not be empty");
        }
        if (!preg_match("/\\A[0-9]{3}\\z/", $value)) {
            throw new InvalidArgumentException("Code must be composed of 3 digits.");
        }
        return $value;
    }

    /**
     * 3 桁のステータスコードを返します.
     *
     * @return string
     */
    public function getCode()
    {
        return $this->code;
    }

    /**
     * このステータスの Reason-Phrase 部分を返します.
     *
     * @return string
     */
    public function getReasonPhrase()
    {
        return $this->reasonPhrase;
    }

    /**
     * このメソッドは HTTP/2 ベースのレスポンスでのみ利用されます.
     * ステータスコードのみ返します.
     *
     * @return string
     */
    public function format()
    {
        return $this->code;
    }

    /**
     * 文字列 ":status" を返します.
     *
     * @return string このヘッダーの名前 (":status")
     */
    public function getName()
    {
        return ":status";
    }

    /**
     * この Status オブジェクトの情報を返します.
     * 返り値はステータスコードおよび Reason-Phrase から成る要素数 2 の配列となります.
     *
     * @return array
     */
    public function getValue()
    {
        return array($this->code, $this->reasonPhrase);
    }

    /**
     * "200 OK" をあらわす Status オブジェクトを返します.
     *
     * @return Status
     */
    public static function getOK()
    {
        // @codeCoverageIgnoreStart
        static $ok = null;
        if ($ok === null) {
            $ok = new self("200", "OK");
        }
        // @codeCoverageIgnoreEnd

        return $ok;
    }
}


<?php
declare(strict_types=1);

/*
 * This file is part of the Stinger Entity Search package.
 *
 * (c) Oliver Kotte <oliver.kotte@stinger-soft.net>
 * (c) Florian Meyer <florian.meyer@stinger-soft.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace StingerSoft\EntitySearchBundle\Model;

class Query {

	/**
	 *
	 * @var string
	 */
	private $term;

	/**
	 *
	 * @var array
	 */
	private $facets;

	/**
	 *
	 * @var array
	 */
	private $usedFacets = null;

	/**
	 *
	 * @param string $term
	 * @param array $facets
	 * @param array $usedFacets
	 */
	public function __construct(string $term = null, array $facets = array(), array $usedFacets = null) {
		$this->term = $term;
		$this->facets = $facets;
		$this->usedFacets = $usedFacets;
	}

	/**
	 * Get the search term
	 *
	 * @return string Returns the search term
	 */
	public function getSearchTerm(): string {
		return $this->term;
	}

	/**
	 *
	 * @return string[string]
	 */
	public function getFacets(): array {
		return $this->facets;
	}

	public function setFacets(array $facets): Query {
		$this->facets = $facets;
		return $this;
	}

	/**
	 *
	 * @return string[]
	 */
	public function getUsedFacets(): ?array {
		return $this->usedFacets;
	}

	public function setUsedFacets(array $usedFacets): Query {
		$this->usedFacets = $usedFacets;
		return $this;
	}

	public function setSearchTerm(string $term): Query {
		$this->term = $term;
		return $this;
	}

	/**
	 *
	 * @param string $name
	 *            Name of the property to fetch
	 * @return array
	 */
	public function __get($name) {
		if(strrpos($name, 'facet_', -strlen($name)) !== false) {
			$facetname = substr($name, 6);

			if(isset($this->facets[$facetname])) {
				return $this->facets[$facetname];
			}
			return array();
		}
	}

	/**
	 *
	 * @param string $name
	 *            Name of the property to set
	 * @param mixed $value
	 *            The value of the property
	 */
	public function __set($name, $value): void {
		if(strrpos($name, 'facet_', -strlen($name)) !== false) {
			$facetname = substr($name, 6);
			$this->facets[$facetname] = $value;
		}
	}

	/**
	 * Checks whether the given property is set or not
	 *
	 * @param string $name
	 * @return boolean
	 */
	public function __isset($name): bool {
		if(strrpos($name, 'facet_', -strlen($name)) !== false) {
			return true;
		}

		return false;
	}
}