<?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\Markup;

/**
 * 汎用的な Helper オブジェクトです.
 * コンストラクタ引数に指定された Builder および空要素タグ一覧をもとにノードの生成・出力を行います.
 *
 * このクラスのインスタンスは, AbstractHelper の各派生クラスにおいて親の
 * Helper オブジェクトとして使用されることを想定しています.
 */
class BaseHelper implements Helper
{
    /**
     * 出力の際に使用される Builder です
     * @var Builder
     */
    private $builder;

    /**
     * 空要素として扱われる要素名の一覧です
     * @var array
     */
    private $emptyNodeNames;

    /**
     * 指定された Builder を使ってマークアップを行う, 新しい Helper インスタンスを生成します.
     * 第二引数で, 空要素として扱われる要素名の一覧を指定することができます.
     * @param Builder $builder        マークアップに利用する Builder
     * @param array   $emptyNodeNames 空要素の要素名一覧
     */
    public function __construct(Builder $builder, array $emptyNodeNames = array())
    {
        $this->builder        = $builder;
        $this->emptyNodeNames = $emptyNodeNames;
    }

    /**
     * 新しい HelperObject を生成します.
     * このメソッドが返す HelperObject は, 引数の型に応じて以下のように振る舞います.
     *
     * - 文字列の場合: その文字列を要素名に持つ {@link Element}
     * - null または空文字列の場合: 空の {@link NodeList}
     * - Node オブジェクトの場合: その Node 自身
     *
     * 第 2 引数に配列を指定した場合, 生成された要素に対して属性をセットすることが出来ます.
     * (生成された HelperObject が要素ではない場合, 第 2 引数は無視されます)
     *
     * @param  string|Component $var
     * @param  array $attr
     * @return HelperObject
     */
    public function tag($var, $attr = array())
    {
        $object = new HelperObject($this, $var);
        if (count($attr)) {
            $object->attr($attr);
        }
        return $object;
    }

    /**
     * 指定された HelperObject の変換結果を返します.
     * このヘルパーに設定されている Builder を使って, 引数の HelperObject を build した結果を返します.
     * @param  HelperObject $object
     * @return mixed
     */
    public function write(HelperObject $object)
    {
        return $this->builder->build($object->getNode());
    }

    /**
     * この Helper にセットされている Builder オブジェクトを返します.
     * 返り値の Builder に対する変更は, この Helper にも影響されます.
     *
     * @return Builder
     */
    public function getBuilder()
    {
        return $this->builder;
    }

    /**
     * この Helper にセットされている Builder を,
     * 引数の Builder オブジェクトで上書きします.
     *
     * @param Builder $builder
     */
    public function setBuilder(Builder $builder)
    {
        $this->builder = $builder;
    }

    /**
     * 指定された要素名を持つ新しい Element オブジェクトを返します.
     *
     * @param  string  $name 要素名
     * @return Element       指定された要素名を持つ Element
     */
    public function createElement($name)
    {
        return in_array($name, $this->emptyNodeNames) ?
            new EmptyElement($name) : new ContainerElement($name);
    }
}


<?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:     26/03/2018
// Time:     13:36
// Project:  Psr15Middlewares
//
declare(strict_types=1);
namespace CodeInc\Psr15Middlewares;
use CodeInc\Psr15Middlewares\Tests\PhpSessionMiddlewareTest;
use HansOtt\PSR7Cookies\SetCookie;
use Micheh\Cache\CacheUtil;
use Micheh\Cache\Header\ResponseCacheControl;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Class PhpSessionMiddleware
 *
 * @uses ResponseCacheControl
 * @see PhpSessionMiddlewareTest
 * @package CodeInc\Psr15Middlewares
 * @author Joan Fabrégat <joan@codeinc.fr>
 */
class PhpSessionMiddleware implements MiddlewareInterface
{
    /**
     * @inheritdoc
     * @throws \HansOtt\PSR7Cookies\InvalidArgumentException
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler):ResponseInterface
    {
        // reads the session id from the request and starts the session
        if (session_status() != PHP_SESSION_ACTIVE) {
            if (isset($request->getCookieParams()[session_name()])) {
                session_id($request->getCookieParams()[session_name()]);
            }
            session_start();
        }

        // processes the request
        $response = $handler->handle($request);

        // if the response is HTML, adding cache limiter and session cookie
        $statusCode = $response->getStatusCode();
        $contentType = $response->getHeaderLine("Content-Type");
        if ($statusCode >= 200 && $statusCode < 400
            && (empty($contentType) || preg_match("#^text/html#ui", $contentType))) {
            $response = $this->addSessionCookie($response);
            $response = $this->addCacheLimiterHeaders($response);
        }

        return $response;
    }

    /**
     * Adds the cache limiter cookie
     *
     * @param ResponseInterface $response
     * @return ResponseInterface
     * @throws \HansOtt\PSR7Cookies\InvalidArgumentException
     */
    private function addSessionCookie(ResponseInterface $response):ResponseInterface
    {
        $params = session_get_cookie_params();
        $cookie = new SetCookie(
            session_name(),
            session_id(),
            time() + $params["lifetime"],
            $params["path"],
            $params["domain"],
            $params["secure"],
            $params["httponly"]
        );
        return $cookie->addToResponse($response);
    }

    /**
     * Adds cache limiter headers.
     *
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    private function addCacheLimiterHeaders(ResponseInterface $response):ResponseInterface
    {
        $cache = new CacheUtil();
        switch (session_cache_limiter()) {
            case 'public':
                $response = $cache->withExpires($response, time() + session_cache_limiter() * 60);
                $response = $cache->withCacheControl($response,
                    (new ResponseCacheControl())
                        ->withPublic()
                        ->withMaxAge(session_cache_limiter() * 60)
                );
                break;

            case 'private_no_expire':
                $response = $cache->withCacheControl($response,
                    (new ResponseCacheControl())
                        ->withPrivate()
                        ->withMaxAge(session_cache_limiter() * 60)
                );
                break;

            case 'private':
                $response = $cache->withExpires($response, 'Thu, 19 Nov 1981 08:52:00 GMT');
                $response = $cache->withCacheControl($response,
                    (new ResponseCacheControl())
                        ->withPrivate()
                        ->withMaxAge(session_cache_limiter() * 60)
                );
                break;

            case 'nocache':
                $response = $cache->withExpires($response, 'Thu, 19 Nov 1981 08:52:00 GMT');
                $response = $cache->withCacheControl($response,
                    (new ResponseCacheControl())
                        ->withPrivate()
                        ->withCachePrevention()
                );
                $response = $response->withHeader("Pragma", "no-cache");
                break;
        }
        return $response;
    }
}


<?php

/**
 * This file is part of the Minion package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license MIT License
 */

namespace Minion\Twig;

use Minion\Application;
use Minion\Utils;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\Request;

/**
 * Class AssetExtension.
 *
 * @package Minion
 * @author Damian Szczerbiński <dszczer@gmail.com>
 */
class AssetExtension extends \Twig_Extension
{
    /** @var Application Application container */
    private $container;

    /**
     * AssetExtension constructor.
     * Inject dependencies
     *
     * @param Application $app Framework
     *
     * @return AssetExtension
     */
    public function __construct(Application $app) {
        $this->container = $app;
    }

    /**
     * {@inheritdoc}
     */
    public function getName() {
        return 'minion_twig_asset';
    }

    /**
     * {@inheritdoc}
     */
    public function getFunctions() {
        return [
            new \Twig_Function('asset', [
                    $this,
                    'assetFunction',
                ]
            ),
        ];
    }

    /**
     * Return fixed asset's path.
     *
     * @param string $asset      Path to the asset
     * @param bool   $serverPath Server-related path or web-related
     *
     * @throws FileException File does not exist on server
     *
     * @return string
     */
    public function assetFunction($asset, $serverPath = false) {
        /** @var Request|null $request */
        $request = isset($this->container['request']) ? $this->container['request'] : null;
        $path = \ltrim($asset, '/\\');
        $assetPath = Utils::fixPath($this->container->getRootDir() . '/' . $path);

//        if(!\file_exists($assetPath))
//            throw new FileException("Asset '$asset' with path '$assetPath' not found");

        if(!$serverPath)
            if($request instanceof Request)
                $assetPath = $request->getSchemeAndHttpHost() . '/' . $path;
            else
                $assetPath = '/' . $path;

        return $assetPath;
    }
}


<?php

namespace Peyote;

/**
 * A class to build HAVING clauses.
 *
 * @package    Peyote
 * @author     Dave Widmer <dave@davewidmer.net>
 */
class Having extends \Peyote\Condition implements \Peyote\Mixin
{
	/**
	 * Gets the type of sorting query we are running.
	 *
	 * @return string
	 */
	public function getType()
	{
		return "HAVING";
	}

	/**
	 * Builds an AND HAVING clause.
	 *
	 * @param  string  $column  The column name
	 * @param  string  $op      The comparison operator
	 * @param  mixed   $value   The value to bind
	 * @param  boolean $isParam Is this a parameter (replace value with ? if true)
	 * @return \Peyote\Where
	 */
	public function andHaving($column, $op, $value, $isParam = true)
	{
		$this->clauses[] = array("AND", $column, $op, $value, $isParam);
		return $this;
	}

	/**
	 * Builds an OR HAVING clause.
	 *
	 * @param  string  $column  The column name
	 * @param  string  $op      The comparison operator
	 * @param  mixed   $value   The value to bind
	 * @param  boolean $isParam Is this a parameter (replace value with ? if true)
	 * @return \Peyote\Where
	 */
	public function orHaving($column, $op, $value, $isParam = true)
	{
		$this->clauses[] = array("OR", $column, $op, $value, $isParam);
		return $this;
	}

	/**
	 * Gets all of the methods that should be passed as "mixin" methods.
	 *
	 * @return array
	 */
	public function getMethods()
	{
		return array('andHaving', 'orHaving');
	}

}


<?php
/**
 * WellCommerce Open-Source E-Commerce Platform
 *
 * This file is part of the WellCommerce package.
 *
 * (c) Adam Piotrowski <adam@wellcommerce.org>
 *
 * For the full copyright and license information,
 * please view the LICENSE file that was distributed with this source code.
 */

namespace WellCommerce\Bundle\ProductStatusBundle\Configurator;

use WellCommerce\Bundle\LayoutBundle\Configurator\AbstractLayoutBoxConfigurator;
use WellCommerce\Component\Form\Elements\FormInterface;
use WellCommerce\Component\Form\FormBuilderInterface;

/**
 * Class ProductShowcaseBoxConfigurator
 *
 * @author  Adam Piotrowski <adam@wellcommerce.org>
 */
final class ProductShowcaseBoxConfigurator extends AbstractLayoutBoxConfigurator
{
    /**
     * {@inheritdoc}
     */
    public function addFormFields(FormBuilderInterface $builder, FormInterface $form, $defaults)
    {
        $fieldset = $this->getFieldset($builder, $form);

        $fieldset->addChild($builder->getElement('tip', [
            'tip' => $this->trans('product_showcase.tip'),
        ]));

        $status = $fieldset->addChild($builder->getElement('select', [
            'name'    => 'status',
            'label'   => $this->trans('product_showcase.label.status'),
            'options' => $this->get('product_status.dataset.admin')->getResult('select'),
        ]));

        $status->setValue($this->getPropertyAccessor()->getValue($defaults, '[status]'));
    }
}


<?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 Peach\Http\MultiHeaderField;
use Peach\Util\ArrayMap;

/**
 * Set-Cookie ヘッダーを表現するクラスです.
 */
class SetCookie implements MultiHeaderField
{
    /**
     * 各 cookie のキーと, そのキーに相当する CookieItem オブジェクトをマッピングする ArrayMap です.
     *
     * @var ArrayMap
     */
    private $items;

    /**
     * 新しい SetCookie オブジェクトを構築します.
     * 引数に cookie のキー, 値, 属性を指定することで, 初期化と同時に
     * 1 個目の cookie を追加することができます.
     * 引数を省略した場合は cookie を何も持たない状態で初期化されます.
     *
     * @param string        $name    cookie のキー
     * @param string        $value   cookie の値
     * @param CookieOptions $options 各種属性
     */
    public function __construct($name = null, $value = null, CookieOptions $options = null)
    {
        $this->items = new ArrayMap();
        if ($name !== null) {
            $this->setItem($name, $value, $options);
        }
    }

    /**
     * 指定されたキーと値の cookie を持つ新しい Set-Cookie ヘッダーを追加します.
     *
     * @param string        $name    cookie のキー
     * @param string        $value   cookie の値
     * @param CookieOptions $options 各種属性
     */
    public function setItem($name, $value, CookieOptions $options = null)
    {
        $item = new CookieItem($name, $value, $options);
        $this->items->put($name, $item);
    }

    /**
     * すべての Set-Cookie ヘッダーの値を配列で返します.
     *
     * @return array すべての Set-Cookie ヘッダー値の配列
     */
    public function format()
    {
        $result = array();
        foreach ($this->items as $item) {
            $result[] = $item->format();
        }
        return $result;
    }

    /**
     * 文字列 "set-cookie" を返します.
     *
     * @return string ヘッダー名 "set-cookie"
     */
    public function getName()
    {
        return "set-cookie";
    }

    /**
     * このオブジェクトにセットされている Set-Cookie ヘッダーの一覧を
     * CookieItem オブジェクトの配列として返します.
     *
     * @return CookieItem[] CookieItem オブジェクトの配列
     */
    public function getValues()
    {
        return array_values($this->items->asArray());
    }
}


<?php
namespace LunixREST\RequestFactory\URLParser\RegexURLParser;

use LunixREST\RequestFactory\URLParser\Exceptions\UnableToParseURLException;
use LunixREST\RequestFactory\URLParser\Exceptions\UnableToProvideMIMEException;
use LunixREST\RequestFactory\URLParser\MIMEProvider;
use LunixREST\RequestFactory\URLParser\ParsedURL;
use LunixREST\RequestFactory\URLParser\RegexURLParser\Exceptions\InvalidRegexPatternException;
use LunixREST\RequestFactory\URLParser\Exceptions\InvalidRequestURLException;
use LunixREST\RequestFactory\URLParser\URLParser;
use Psr\Http\Message\UriInterface;

/**
 * An implementation of a URLParser that uses named regex capture groups to parse urls.
 * Class RegexURLParser
 * @package LunixREST\RequestFactory\URLParser\RegexURLParser
 */
class RegexURLParser implements URLParser
{
    /**
     * @var string
     */
    protected $pattern;
    /**
     * @var MIMEProvider|null
     */
    private $MIMEProvider;

    /**
     * RegexURLParser constructor.
     * @param string $pattern - a pattern that matches named groups: endpoint. And optionally: element, version, apiKey, acceptableExtension
     * @param MIMEProvider|null $MIMEProvider
     * @throws InvalidRegexPatternException
     */
    public function __construct(string $pattern, ?MIMEProvider $MIMEProvider = null)
    {
        $this->pattern = $pattern;

        if(@preg_match($pattern, null) === false) {
            throw new InvalidRegexPatternException("Unable to parse regex pattern", preg_last_error());
        }
        $this->MIMEProvider = $MIMEProvider;
    }

    /**
     * Parses API request data out of a url
     * @param UriInterface $uri
     * @return ParsedURL
     * @throws UnableToParseURLException
     * @throws InvalidRequestURLException
     */
    public function parse(UriInterface $uri): ParsedURL
    {
        $matches = [];
        if(preg_match($this->pattern, $uri->getPath(), $matches) === 0) {
            throw new InvalidRequestURLException("Unable to parse request path: did not match regex");
        }
        if(!($endpoint = $matches["endpoint"] ?? null)) {
            throw new InvalidRequestURLException("Unable to match endpoint in url");
        }
        $element = $matches["element"] ?? null;
        $version = $matches["version"] ?? null;
        $apiKey = $matches["apiKey"] ?? null;

        $acceptableMimeTypes = [];
        if(($acceptableExtension = $matches["acceptableExtension"] ?? null)) {
            if(!$this->MIMEProvider) {
                throw new UnableToParseURLException("Unable to accept acceptable extensions");
            } else {
                try {
                    $acceptableMimeTypes[] = $this->MIMEProvider->provideMIME($acceptableExtension);
                } catch (UnableToProvideMIMEException $exception) {
                    throw new UnableToParseURLException($exception->getMessage());
                }
            }
        }

        return new ParsedURL($endpoint, $element, $version, $apiKey, $acceptableMimeTypes, $uri->getQuery());
    }

    /**
     * @return string
     */
    public function getPattern(): string
    {
        return $this->pattern;
    }

}


<?php

namespace Peyote;

use \Peyote\Facade as Peyote;

/**
 * A very simple wrapper for executing PDO based queries.
 *
 * @package    Peyote
 * @author     Dave Widmer <dave@davewidmer.net>
 */
class PDO
{
	/**
	 * @var \PDO  The PDO instance used to query the database
	 */
	protected $pdo;

	/**
	 * @param PDO $pdo  The PDO instance used to query the database
	 */
	public function __construct(\PDO $pdo)
	{
		$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
		$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);

		$this->pdo = $pdo;
	}

	/**
	 * @param  string $table The table to insert into
	 * @param  array  $data  The data to add
	 * @return int           The id of the last inserted row
	 */
	public function insert($table, array $data)
	{
		$query = Peyote::insert($table)
			->columns(\array_keys($data))
			->values(\array_values($data));

		$this->runQuery($query);
		return (int) $this->pdo->lastInsertId();
	}

	/**
	 * Run a Peyote based query.
	 *
	 * @param  \Peyote\Query $query  A Peyote Query
	 * @return \PDOStatement
	 */
	public function runQuery(\Peyote\Query $query)
	{
		return $this->run($query->compile(), $query->getParams());
	}

	/**
	 * Run a MySQL query.
	 *
	 * @param  string $query   The query to run
	 * @param  array  $params  Any query params to add
	 * @return \PDOStatement
	 */
	public function run($query, array $params = array())
	{
		$statement = $this->pdo->prepare($query);
		$statement->execute($params);

		return $statement;
	}

}


<?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;

/**
 * HintTrait
 *
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     HintInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait HintTrait
{
    /**
     * hints
     *
     * @var    array
     * @access protected
     */
    protected $clause_hints = [];

    /**
     * {@inheritDoc}
     */
    public function addHint(/*# string */ $hintName)
    {
        $this->clause_hints[strtoupper($hintName)] = true;
        return $this;
    }

    /**
     * Build HINT
     *
     * @return array
     * @access protected
     */
    protected function buildHint()/*# : array */
    {
        $res = [];
        foreach ($this->clause_hints as $name => $status) {
            if ($status) {
                $res[] = $name;
            }
        }
        if (!empty($res)) {
            return [join(' ', $res)];
        } else {
            return [];
        }
    }
}


<?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;

/**
 * IntoTrait
 *
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     IntoInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait IntoTrait
{
    /**
     * INTO TABLE
     *
     * @var    string
     * @access protected
     */
    protected $clause_into = '';

    /**
     * Insert into table
     *
     * @param  string $table
     * @return self
     * @access public
     */
    public function into(/*# string */ $table)
    {
        $this->clause_into = $table;
        return $this;
    }

    /**
     * Build INTO
     *
     * @return array
     * @access protected
     */
    protected function buildInto()/*# : array */
    {
        $result = [];
        if ($this->clause_into) {
            $result[] = 'INTO ' . $this->quote($this->clause_into);
        }
        return $result;
    }

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


<?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;

use InvalidArgumentException;
use Peach\DT\HttpDateFormat;
use Peach\DT\Timestamp;
use Peach\Http\Header\HttpDate;
use Peach\Http\Header\QualityValues;
use Peach\Http\Header\Raw;

/**
 * HTTP メッセージを扱う際によく使われる機能を集めたユーティリティクラスです.
 */
class Util
{
    /**
     * このクラスはインスタンス化できません
     */
    private function __construct() {}

    /**
     * 指定された文字列が HTTP ヘッダー名として妥当かどうかを検証します.
     * 文字列が半角アルファベット・数字・ハイフンから成る場合のみ妥当とします.
     * 妥当な文字列でない場合は InvalidArgumentException をスローします.
     *
     * @param string $name ヘッダー名
     * @throws InvalidArgumentException 引数がヘッダー名として不正だった場合
     */
    public static function validateHeaderName($name)
    {
        // @codeCoverageIgnoreStart
        static $whiteList = array(
            ":authority",
            ":path",
            ":method",
            ":scheme",
            ":status",
        );
        // @codeCoverageIgnoreEnd
        if (in_array($name, $whiteList, true)) {
            return;
        }
        if (!preg_match("/\\A[a-zA-Z0-9\\-]+\\z/", $name)) {
            throw new InvalidArgumentException("{$name} is not a valid header name");
        }
    }

    /**
     * 指定された文字列が HTTP ヘッダーの値として妥当かどうかを検証します.
     *
     * {@link https://tools.ietf.org/html/rfc7230 RFC 7230} で定義された以下の ABNF に基いて妥当性の判定を行います.
     *
     *

     * header-field   = field-name ":" OWS field-value OWS
     *
     * field-name     = token
     * field-value    = *( field-content / obs-fold )
     * field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
     * field-vchar    = VCHAR / obs-text
     *
     * obs-fold       = CRLF 1*( SP / HTAB )
     *

     *
     * 妥当な文字列でない場合は InvalidArgumentException をスローします.
     * obs-text および obs-fold については RFC7230 で廃止されているため例外として処理します.
     *
     * @param  string $value 検査対象のヘッダー値
     * @throws InvalidArgumentException 引数がヘッダー値として不正だった場合
     */
    public static function validateHeaderValue($value)
    {
        if (!self::handleValidateHeaderValue($value)) {
            throw new InvalidArgumentException("'{$value}' is not a valid header value");
        }
    }

    /**
     * 引数がヘッダー値として妥当な場合のみ true を返します.
     *
     * @param  string $value ヘッダー値
     * @return bool          妥当なヘッダー値の場合は true, それ以外は false
     */
    private static function handleValidateHeaderValue($value)
    {
        $trimmed = trim($value);
        if ($trimmed !== $value) {
            return false;
        }
        if ($value === "") {
            return true;
        }
        $bytes = str_split($value);
        return (count($bytes) === 1) ? self::validateVCHAR($value) : self::validateBytes($bytes);
    }

    /**
     * 指定された文字列が印字可能文字と空白文字で構成されているかどうかを確認します.
     * ただし文字列の先頭および末尾が空白文字だった場合は NG とします.
     *
     * @param  array $bytes
     * @return bool
     */
    private static function validateBytes($bytes)
    {
        $head = array_shift($bytes);
        if (!self::validateVCHAR($head)) {
            return false;
        }
        $tail = array_pop($bytes);
        if (!self::validateVCHAR($tail)) {
            return false;
        }
        foreach ($bytes as $chr) {
            if (!self::validateVCHAR($chr) && $chr !== " " && $chr !== "\t") {
                return false;
            }
        }
        return true;
    }

    /**
     * 引数の 1 文字について, 印字可能文字かどうかを判定します.
     * @param  string $chr 検査対象の文字
     * @return bool        印字可能文字の場合のみ true
     */
    private static function validateVCHAR($chr)
    {
        $byte = ord($chr);
        return (0x21 <= $byte && $byte <= 0x7E);
    }

    /**
     * 指定された Request の If-Modified-Since および If-None-Match ヘッダーを参照し,
     * この Request がキャッシュしているリソースの最新版が存在するかどうかを判定します.
     *
     * @param  Request   $request      判定対象の Request
     * @param  Timestamp $lastModified サーバー側リソースの最終更新日時
     * @param  string    $etag         サーバー側リソースの ETag
     * @return bool
     */
    public static function checkResponseUpdate(Request $request, Timestamp $lastModified, $etag = null)
    {
        $ifModifiedSince = $request->getHeader("If-Modified-Since");
        if (!($ifModifiedSince instanceof HttpDate)) {
            return true;
        }
        $clientTime = $ifModifiedSince->getValue();
        if ($clientTime->before($lastModified)) {
            return true;
        }

        return $etag !== $request->getHeader("If-None-Match")->getValue();
    }

    /**
     * 指定されたヘッダー名, ヘッダー値の組み合わせから
     * HeaderField オブジェクトを構築します.
     *
     * @param  string $name  ヘッダー名
     * @param  string $value ヘッダー値
     * @return HeaderField
     */
    public static function parseHeader($name, $value)
    {
        static $qNames = array(
            "accept",
            "accept-language",
            "accept-encoding",
        );
        static $dNames = array(
            "date",
            "if-modified-since",
            "last-modified",
        );
        $lName = strtolower($name);
        if (in_array($lName, $qNames)) {
            return new QualityValues($lName, self::parseQualityValue($value));
        }
        if (in_array($lName, $dNames)) {
            $format    = HttpDateFormat::getInstance();
            $timestamp = Timestamp::parse($value, $format);
            return new HttpDate($lName, $timestamp, $format);
        }
        if ($lName === "host") {
            return new Raw(":authority", $value);
        }

        return new Raw($lName, $value);
    }

    /**
     * qualitiy value を配列に変換します.
     * 引数を "ja,en-us;q=0.8,en;q=0.6" とした場合, 返り値は以下の配列になります.
     *

     * array("ja" => 1.0, "en-us" => 0.8, "en" => 0.6)
     *

     *
     * @param  string $value
     * @return array
     */
    private static function parseQualityValue($value)
    {
        $values  = preg_split("/\\s*,\\s*/", $value);
        $matched = array();
        $qvList  = array();
        foreach ($values as $item) {
            if (preg_match("/\\A([^;]+)\\s*;\\s*(.+)\\z/", $item, $matched)) {
                $key    = $matched[1];
                $qvalue = self::parseQvalue($matched[2]);
            } else {
                $key    = $item;
                $qvalue = 1.0;
            }
            $qvList[$key] = $qvalue;
        }
        return $qvList;
    }

    /**
     * qvalue 形式の文字列 ("q=0.8" など) から小数部分を解析し, float として返します.
     *
     * @param  string $qvalue "q=0.9" のような形式の文字列
     * @return float  qvalue の小数値. もしも不正な場合は 1.0
     */
    private static function parseQvalue($qvalue)
    {
        $matched = array();
        if (preg_match("/\\Aq\\s*=\\s*([0-9\\.]+)\\z/", $qvalue, $matched)) {
            $val = (float) $matched[1];
            return (0.0 < $val && $val <= 1.0) ? $val : 1;
        }
        return 1;
    }
}


<?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\Controller;

use StingerSoft\EntitySearchBundle\Form\QueryType;
use StingerSoft\EntitySearchBundle\Model\PaginatableResultSet;
use StingerSoft\EntitySearchBundle\Model\Query;
use StingerSoft\EntitySearchBundle\Services\Mapping\DocumentToEntityMapperInterface;
use StingerSoft\EntitySearchBundle\Services\SearchService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

trait SearchControllerTrait {

	/**
	 * @var SearchService
	 */
	protected $searchService;
	private $availableFacets;
	private $facetFormatter;

	public function searchAction(Request $request, DocumentToEntityMapperInterface $mapper) {
		if($request->query->get('term', false) !== false) {
			$this->setSearchTerm($request->getSession(), $request->query->get('term'));
			return $this->redirectToRoute('stinger_soft_entity_search_search');
		}

		$term = $this->getSearchTerm($request->getSession());
		$facets = $this->getSearchFacets($request->getSession());
		$availableFacets = $this->getAvailableFacets();

		$query = new Query($term, $facets, array_keys($availableFacets));

		$facetForm = $this->createForm(QueryType::class, $query, array(
			'used_facets' => $this->getConfiguredUsedFacets($query->getUsedFacets())
		));

		$facetForm->handleRequest($request);
		if($facetForm->isSubmitted()) {
			if($facetForm->get('clear')->isClicked()) {
				$query->setFacets($this->getDefaultFacets());
			}
			$this->setSearchTerm($request->getSession(), $query->getSearchTerm());
			$this->setSearchFacets($request->getSession(), $query->getFacets());
		}

		try {
			$result = $this->searchService->search($query);

			$facetForm = $this->createForm(QueryType::class, $query, array(
				'result'          => $result,
				'used_facets'     => $this->getConfiguredUsedFacets($query->getUsedFacets()),
				'facet_formatter' => $this->getFacetFormatter()
			));

			$page = (int)$request->query->get('page', 1);
			$results = null;
			if($result instanceof PaginatableResultSet) {
				$results = $result->paginate($page, $this->getResultsPerPage());
			} elseif($results !== null) {
				$results = $result->getResults(($page - 1) * $this->getResultsPerPage(), $this->getResultsPerPage());
			}

			return $this->render($this->getTemplate(), array(
				'results'   => $results,
				'resultSet' => $result,
				'term'      => $query->getSearchTerm(),
				'mapper'    => $mapper,
				'facetForm' => $facetForm->createView()
			));
		} catch(\Exception $exception) {
			$response = $this->render($this->getErrorTemplate(), array(
				'error' => $exception->getMessage(),
				'term'  => $query->getSearchTerm()
			));
			return $response->setStatusCode(500);
		}
	}

	/**
	 * Returns a JSON array of autocompletions for the given term.
	 * The term can be provided as a GET or POST paramater with the name term
	 *
	 * @param Request $request
	 * @return \Symfony\Component\HttpFoundation\JsonResponse
	 */
	public function autocompleteAction(Request $request) {
		$term = $request->get('term');
		return new JsonResponse($this->searchService->autocomplete($term, $this->getSuggestionCount()));
	}

	/**
	 * Provides an online help for the configured search service.
	 * If the search service has no online help defined a warning message will be displayed to the user.
	 *
	 * @param Request $request
	 * @return \Symfony\Component\HttpFoundation\Response
	 */
	public function onlineHelpAction(Request $request) {
		$template = $this->searchService->getOnlineHelp($request->getLocale(), $this->getDefaultLocale());
		return $this->render($template ?: 'StingerSoftEntitySearchBundle:Help:no_help.html.twig');
	}

	/**
	 * @param SearchService $searchService
	 * @required
	 */
	public function setSearchService(SearchService $searchService): void {
		$this->searchService = $searchService;
	}

	protected function getConfiguredUsedFacets(array $queryUsedFacets) {
		$availableFacets = $this->getAvailableFacets();
		$usedFacets = array();
		foreach($queryUsedFacets as $queryUsedFacet) {
			$usedFacets[$queryUsedFacet] = $availableFacets[$queryUsedFacet];
		}
		return $usedFacets;
	}

	/**
	 * Maximum number of suggestions which should be provided by the autocomplete action
	 *
	 * @return integer
	 */
	protected function getSuggestionCount() {
		return 10;
	}

	/**
	 * Prefix to store information in the session variable
	 *
	 * @return string
	 */
	protected function getSessionPrefix() {
		return 'stinger_soft_entity_search';
	}

	/**
	 * Number of results which should be displayed per page
	 *
	 * @return integer
	 */
	protected function getResultsPerPage() {
		return 10;
	}

	protected function getTemplate() {
		return 'StingerSoftEntitySearchBundle:Search:results.html.twig';
	}

	protected function getErrorTemplate() {
		return 'StingerSoftEntitySearchBundle:Search:error.html.twig';
	}

	protected function getFacetFormatter() {
		$this->initFacets();
		return $this->facetFormatter;
	}

	/**
	 * Returns an array of preselected facets (no facet selected is the default)
	 *
	 * @return string[string][]
	 */
	protected function getDefaultFacets() {
		$availableFacets = $this->getAvailableFacets();
		return array_combine(array_keys($availableFacets), array_fill(0, count($availableFacets), array()));
	}

	/**
	 * Returns an array of the available facets which should be offered the user as a filter
	 *
	 * @return string[]
	 */
	protected function getAvailableFacets() {
		$this->initFacets();
		return $this->availableFacets;
	}

	protected function initFacets() {
		if(!$this->availableFacets) {
			$this->availableFacets = array();
			$this->facetFormatter = array();

			$facetServices = $this->getParameter('stinger_soft.entity_search.available_facets');
			foreach($facetServices as $facetServiceId) {
				$facetService = $this->searchService->getFacet($facetServiceId);
				$this->availableFacets[$facetService->getField()] = $facetService->getFormOptions();
				if($facetService->getFacetFormatter()) {
					$this->facetFormatter[$facetService->getField()] = $facetService->getFacetFormatter();
				}
			}
		}
	}

	/**
	 * Fetches the searched facets from the session object
	 *
	 * @param SessionInterface $session
	 * @return string[string][]
	 */
	protected function getSearchFacets(SessionInterface $session) {
		$facets = $session->get($this->getSessionPrefix() . '_facets', false);
		return $facets ? \json_decode($facets, true) : $this->getDefaultFacets();
	}

	/**
	 * Sets the given search facets in the user's session
	 *
	 * @param SessionInterface $session
	 * @param string[string][] $facets
	 */
	protected function setSearchFacets(SessionInterface $session, $facets) {
		$session->set($this->getSessionPrefix() . '_facets', \json_encode($facets));
	}

	/**
	 * Fetches the search term from the session object
	 *
	 * @param SessionInterface $session
	 * @return mixed
	 */
	protected function getSearchTerm(SessionInterface $session) {
		return $session->get($this->getSessionPrefix() . '_term', false);
	}

	/**
	 * Sets the given search term in the user's session
	 *
	 * @param SessionInterface $session
	 * @param string $term
	 */
	protected function setSearchTerm(SessionInterface $session, $term) {
		$session->set($this->getSessionPrefix() . '_term', $term);
	}

}


<?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\Statement;

use Phossa\Query\Statement\RawInterface;
use Phossa\Query\Dialect\DialectInterface;

/**
 * UtilityTrait
 *
 * Utilities for the statement
 *
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait UtilityTrait
{
    /**
     * If $string contains any char other than '[0-9a-zA-Z$_.]', we consider
     * it is a raw string case
     *
     * @param  string|object $str
     * @return bool
     * @access protected
     */
    protected function isRaw($str)/*# : bool */
    {
        if (is_string($str)) {
            return (bool) preg_match('/[^0-9a-zA-Z\$_.]/', $str);
        } elseif (is_object($str) && $str instanceof RawInterface) {
            return true;
        }
        return false;
    }

    /**
     * Quote SQL identifier base on settings
     *
     * @param  string $str
     * @return string
     * @access protected
     */
    protected function quote(/*# string */ $str)/*# : string */
    {
        return $this->getDialect()->quote(
            $str,
            $this->getSettings()['autoQuote'] ?
            DialectInterface::QUOTE_YES :
            DialectInterface::QUOTE_NO
        );
    }

    /**
     * If SPACE found ,quote it anyway
     *
     * @param  string $str
     * @return string
     * @access protected
     */
    protected function quoteSpace(/*# string */ $str)/*# : string */
    {
        return $this->getDialect()->quote(
            $str,
            DialectInterface::QUOTE_SPACE | (
                $this->getSettings()['autoQuote'] ?
                DialectInterface::QUOTE_YES :
                DialectInterface::QUOTE_NO
            )
        );
    }

    /**
     * Quote 'name(4) ASC' as '`name`(4) ASC' as used in index creation
     * @param  string $str
     * @return string
     * @access protected
     */
    protected function quoteLeading(/*# string */ $str)/*# : string */
    {
        $parts = preg_split('/([^0-9a-zA-Z_.])/', $str, 5,
            \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
        $first = array_shift($parts);
        return $this->quote($first) . join('', $parts);
    }

    /**
     * Get current settings
     *
     * @return array
     * @access public
     */
    abstract public function getSettings()/*# : array */;

    /**
     * Get the dialect
     *
     * @return DialectInterface
     * @access public
     */
    abstract public function getDialect()/*# : DialectInterface */;
}


<?php

/**
 * This file is part of the Minion package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license MIT License
 */

namespace Minion\Twig;

use Minion\Service\ServiceProvider;
use Silex\Application as SilexApp;

/**
 * {@internal it is NOT RECOMMENDED to use it outside Minion package}}
 *
 * Class TwigExtensionTagServiceProvider.
 *
 * Allow to extend twig environment by registering extension as a service.
 *
 * @package Minion
 * @author Damian Szczerbiński <dszczer@gmail.com>
 */
class TwigExtensionTagServiceProvider extends ServiceProvider
{
    /**
     * Extend Twig Environment with provided Extension.
     *
     * @param SilexApp $app
     *
     * @return void
     */
    public function register(SilexApp $app) {
        $app['twig'] = $app->share($app->extend('twig', function (\Twig_Environment $twig, SilexApp $app) {
            $class = $this->getServiceConfig()->getProviderClass();
            $twig->addExtension(new $class);

            return $twig;
        }));
    }

    /**
     * {@inheritdoc}
     */
    public function boot(SilexApp $app) {}
}


<?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
 * @ignore
 */
namespace Peach\DF\JsonCodec;

/**
 * JSON の BNF ルール array をあらわす Expression です.
 * RFC 7159 で定義されている以下のフォーマットを解釈します.
 *
 * <pre>
 * array = begin-array [ value *( value-separator value ) ] end-array
 * </pre>
 *
 * @ignore
 */
class ArrayExpr implements Expression
{
    /**
     * handle() の解析結果です.
     *
     * @var array
     */
    private $result;

    /**
     * 新しい ArrayExpr オブジェクトを構築します.
     */
    public function __construct()
    {
        $this->result = null;
    }

    /**
     * 現在の Context から配列部分を読み込みます.
     *
     * @param Context $context
     */
    public function handle(Context $context)
    {
        $beginArray = new StructuralChar(array("["));
        $beginArray->handle($context);

        if ($context->current() === "]") {
            $endArray = new StructuralChar(array("]"));
            $endArray->handle($context);
            $this->result = array();
            return;
        }

        $result = array();
        while (true) {
            $value = new Value();
            $value->handle($context);
            $result[] = $value->getResult();

            $struct = new StructuralChar(array(",", "]"));
            $struct->handle($context);
            if ($struct->getResult() === "]") {
                $this->result = $result;
                break;
            }
        }
    }

    /**
     * handle() の結果を配列で返します.
     *
     * @return array
     */
    public function getResult()
    {
        return $this->result;
    }
}


<?php

/**
 * Melis Technology (http://www.melistechnology.com)
 *
 * @copyright Copyright (c) 2016 Melis Technology (http://www.melistechnology.com)
 *
 */

namespace MelisCmsPageHistoric\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\View\Model\JsonModel;
use Zend\Session\Container;
use Zend\Json\Json;
use Zend\View\View;

/**
 * Page Historic Controller
 * Adds the historic tabulation on the page's edition
 */
class PageHistoricController extends AbstractActionController
{
    const PLUGIN_INDEX = 'meliscmspagehistoric';
    const TOOL_KEY = 'tool_meliscmspagehistoric';

    /**
     * Renders the view inside the Page Historic tab
     * @return \Zend\View\Model\ViewModel
     */
    public function renderPageHistoricAction()
    {
		$idPage = $this->params()->fromRoute('idPage', $this->params()->fromQuery('idPage', ''));
    	$melisKey = $this->params()->fromRoute('melisKey', '');

    	$view = new ViewModel();
    	$view->idPage = $idPage;
    	$view->melisKey = $melisKey;

    	return $view;
    }

    /**
     * Renders the Page Historic table view
     * @return \Zend\View\Model\ViewModel
     */
    public function renderPageHistoricTableAction()
    {

        $translator = $this->getServiceLocator()->get('translator');
        $melisKey = $this->params()->fromRoute('melisKey', '');
        $melisTool = $this->getServiceLocator()->get('MelisCoreTool');
        $melisTool->setMelisToolKey(self::PLUGIN_INDEX, self::TOOL_KEY);
        $columns = $melisTool->getColumns();

        $idPage = $this->params()->fromRoute('idPage', $this->params()->fromQuery('idPage', ''));

        $container = new Container('meliscore');
        $locale = $container['melis-lang-locale'];

        $view = new ViewModel();
        $view->melisKey = $melisKey;
        $view->tableColumns = $columns;
        $view->getToolDataTableConfig = $melisTool->getDataTableConfiguration('#tableHistoricPageId'.$idPage, true);
        $view->idPage = $idPage;
        $view->tableId = 'tableHistoricPageId'.$idPage;

        return $view;
    }

    /**
     * Renders the select limit for the datatable
     * @return ViewModel
     */
    public function renderPageHistoricTableLimitAction()
    {
        return new ViewModel();
    }

    /**
     * Renders the input filter for users
     * @return ViewModel
     */
    public function renderPageHistoricContentFiltersSearchUserAction()
    {
        return new ViewModel();
    }

    /**
     * Renders the date range filter
     * @return ViewModel
     */
    public function renderPageHistoricContentFiltersDateAction()
    {
        return new ViewModel();
    }

    /**
     * Renders the actions filter
     * @return ViewModel
     */
    public function renderPageHistoricContentFiltersActionsAction()
    {
        $melisPageHistoricTable = $this->getServiceLocator()->get('MelisPagehistoricTable');
        //get distinct actions on database
        $actions = $melisPageHistoricTable->getPageHistoricListOfActions()->toArray();
        $translator = $this->getServiceLocator()->get('translator');

        $options = '<option value="">' . $translator->translate('tr_melispagehistoric_filter_action_select') . '</option>';
        foreach ($actions as $action) {
            $options .= '<option value="' . $action['action'] . '">' . $action['action'] . '</option>';
        }

        $view = new ViewModel();
        $view->options = $options;

        return $view;
    }

    /**
     * Renders to the refresh button in the datatable
     * @return \Zend\View\Model\ViewModel
     */
    public function renderPageHistoricTableRefreshAction()
    {
        return new ViewModel();
    }

    /**
     * Returns a JSON format of Page Historic Data from DB
     * @return \Zend\View\Model\JsonModel
     */
    public function getPageHistoricDataAction()
    {
        $melisPageHistoricTable = $this->getServiceLocator()->get('MelisPagehistoricTable');
        $melisUserTable = $this->serviceLocator->get('MelisCoreTableUser');

        $translator = $this->getServiceLocator()->get('translator');
        $melisTool = $this->getServiceLocator()->get('MelisCoreTool');
        $melisTool->setMelisToolKey(self::PLUGIN_INDEX, self::TOOL_KEY);

        $melisTranslation = $this->getServiceLocator()->get('MelisCoreTranslation');
        $container = new Container('meliscore');
        $locale = $container['melis-lang-locale'];

        $colId = array();
        $dataCount = 0;
        $draw = 0;
        $tableData = array();
        if ($this->getRequest()->isPost()) {
            $pageId = (int) $this->getRequest()->getPost('pageId');
            $userName = $this->getRequest()->getPost('user_name', null);
            $action = $this->getRequest()->getPost('action', null);

            $colId = array_keys($melisTool->getColumns());
            $selCol = $this->getRequest()->getPost('order');
            $selCol = $colId[$selCol[0]['column']];

            $startDate = $this->getRequest()->getPost('startDate');
            $endDate = $this->getRequest()->getPost('endDate');

            if ($selCol != 'hist_id') {
                $sortOrder = $this->getRequest()->getPost('order');
                $sortOrder = $sortOrder[0]['dir'];
            }
            else {
                $sortOrder = 'desc';
            }

            $draw = $this->getRequest()->getPost('draw');
            $start = $this->getRequest()->getPost('start');
            $length =  $this->getRequest()->getPost('length');

            $dataCount = $melisPageHistoricTable->getTotalData('hist_page_id',$pageId);

            $option = array(
                'where' => array(
                    'key' => 'hist_page_id',
                    'value' => $pageId,
                ),
                // fixed order, since page historic is sorting descendingly using history ID
                'order' => array(
                    'key' => 'hist_id',
                    'dir' => 'desc',
                ),
                'start' => $start,
                'limit' => $length,
                'columns' => $melisTool->getSearchableColumns(),
                'date_filter' => array(

                ),
            );

            if ($startDate != NULL && $endDate != NULL) {
                $option['date_filter'] = [
                    'key' => 'hist_date',
                    'startDate' => date('Y-m-d', strtotime($startDate)),
                    'endDate' => date('Y-m-d', strtotime($endDate))
                ];
            }

            $getData = $melisPageHistoricTable->getPageHistoricData($option, null, $userName, $action);

            // store fetched Object Data into array so we can apply any string modifications
            foreach($getData as $key => $values)
            {
                $tableData[$key] = (array) $values;
            }

            for($ctr = 0; $ctr < count($tableData); $ctr++)
            {
                // Initialize as Deleted User As Default
                $histUserId = $tableData[$ctr]['hist_user_id'];
                $tableData[$ctr]['hist_user_id'] = $translator->translate('tr_meliscore_user_deleted').' ('.$tableData[$ctr]['hist_user_id'].')';

                $histUserData = $melisUserTable->getEntryById($histUserId);

                if (!empty($histUserData)){
                    $histUserData = $histUserData->current();
                    if(!empty($histUserData)) {
                        $tableData[$ctr]['hist_user_id'] = ucfirst(mb_strtolower($histUserData->usr_firstname, 'UTF-8')).' '.ucfirst(mb_strtolower($histUserData->usr_lastname, 'UTF-8'));
                    }
                }

                $tableData[$ctr]['DT_RowId'] = $tableData[$ctr]['hist_id'];
                $tableData[$ctr]['hist_action'] = $translator->translate('tr_melispagehistoric_action_text_'.$tableData[$ctr]['hist_action']);
                $tableData[$ctr]['hist_date'] = strftime($melisTranslation->getDateFormatByLocate($locale), strtotime($tableData[$ctr]['hist_date']));
                $tableData[$ctr]['hist_description'] =$translator->translate($tableData[$ctr]['hist_description']);
            }
        }

        return new JsonModel(array(
            'draw' => (int) $draw,
            'recordsTotal' => $dataCount,
            'recordsFiltered' =>  $melisPageHistoricTable->getTotalFiltered(),
            'data' => $tableData,
        ));
    }
    /**
     * Returns latest page historic
     *
     * return array
     */
    public  function getLatestPageHistoric()
    {
        $responseData = $this->params()->fromRoute('datas', $this->params()->fromQuery('datas', ''));
        $melisPageHistoricTable = $this->getServiceLocator()->get('MelisPageHistoricTable');

        $histDatas = array(
            'hist_page_id' => $idPage,
            'hist_action'  => 'Delete',
            'hist_date'     => date('Y-m-d H:i:s'),
            'hist_user_id' => $userId,
            'hist_description' => 'tr_melispagehistoric_action_text_Delete'
        );

        return $histDatas;
    }

    /**
     * Saves the action taken from MelisCMS Page Actions
     */
    public function savePageHistoricAction()
    {
        $responseData = $this->params()->fromRoute('datas', $this->params()->fromQuery('datas', ''));

    	$idPage = isset($responseData['idPage']) ? $responseData['idPage'] : (!empty($responseData[0]['idPage'])?($responseData[0]['idPage']):0);
        $isNew =  isset($responseData['isNew']) ? $responseData['isNew'] : (!empty($responseData[0]['isNew'])?($responseData[0]['isNew']):0);

        $response = array(
        		'idPage' => $idPage,
        		'isNew' => $isNew
        );
        $this->getEventManager()->trigger('meliscmspagehistoric_historic_save_start', $this, $response);

        $melisCoreAuth = $this->getServiceLocator()->get('MelisCoreAuth');
    	$melisPageHistoricTable = $this->getServiceLocator()->get('MelisPageHistoricTable');

    	$pageAction = $this->params()->fromRoute('pageActionUsed', $this->params()->fromQuery('pageActionUsed',''));
    	$histDatas  = array();

    	$container = new Container('meliscms');
    	$datas = array();

    	if (isset($container['action-page-tmp']['success'])
    		&& $container['action-page-tmp']['success'] == 0)
    		return;

    	// Update from the different save actions done
    	if (!empty($container['action-page-tmp']))
    	{
            if (!empty($container['action-page-tmp']['datas']))
                $datas = $container['action-page-tmp']['datas'];
    	}

    	$description = '';

    	switch ($pageAction) {
    	    case 'Save':
    	        if ($isNew) {
    	            $description = 'tr_melispagehistoric_description_text_new';
    	        } else {
    	            $description = 'tr_melispagehistoric_description_text_save';
    	        }
	            break;
    	    case 'Publish':
    	        $description = 'tr_melispagehistoric_description_text_publish';
	            break;
    	    case 'Unpublish':
    	        $description = 'tr_melispagehistoric_description_text_unpublished';
	            break;
    	}

    	if ($idPage) {
    	    $userId = (int) null;
    	    $userAuthDatas =  $melisCoreAuth->getStorage()->read();

    	    if ($userAuthDatas)
    	       $userId = $userAuthDatas->usr_id;

    	    $histDatas = array(
    	        'hist_page_id' => $idPage,
    	        'hist_action'  => $pageAction,
    	        'hist_date'     => date('Y-m-d H:i:s'),
    	        'hist_user_id' => $userId,
    	        'hist_description' => $description
    	    );

    	    $melisPageHistoricTable->save($histDatas);
    	}

    	$this->getEventManager()->trigger('meliscmspagehistoric_historic_save_end', $this, $histDatas);
    }

    /**
     * Removes page historic entries
     */
    public function deletePageHistoricAction()
    {
        $responseData = $this->params()->fromRoute('datas', $this->params()->fromQuery('datas', ''));

        $idPage       = $responseData[0]['idPage'];

        $response = array('idPage' => $idPage);
        $this->getEventManager()->trigger('meliscmspagehistoric_historic_delete_start', $this, $response);

    	$melisPageHistoricTable = $this->getServiceLocator()->get('MelisPageHistoricTable');

    	$melisCoreAuth = $this->getServiceLocator()->get('MelisCoreAuth');

    	$userId = (int) null;
        $userAuthDatas =  $melisCoreAuth->getStorage()->read();
    	if($userAuthDatas)
    	   $userId = $userAuthDatas->usr_id;

        $histDatas = array(
            'hist_page_id' => $idPage,
    	    'hist_action'  => 'Delete',
            'hist_date'     => date('Y-m-d H:i:s'),
    	    'hist_user_id' => $userId,
    	    'hist_description' => 'tr_melispagehistoric_action_text_Delete'
        );
        $melisPageHistoricTable->save($histDatas);

        $this->getEventManager()->trigger('meliscmspagehistoric_historic_delete_end', $this, $responseData);
    }

    /**
     * Gets all back office users that has a record in database
     * @return JsonModel
     */
    public function getBackOfficeUsersAction()
    {
        $melisPageHistoricTable = $this->getServiceLocator()->get('MelisPageHistoricTable');
        $users = $melisPageHistoricTable->getUsers()->toArray();

        return new JsonModel(array(
            'users' => $users,
        ));
    }
}


<?php
namespace Yoanm\BehatUtilsExtension\ServiceContainer;

use Behat\Testwork\ServiceContainer\Extension;
use Behat\Testwork\ServiceContainer\ExtensionManager;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Yoanm\BehatUtilsExtension\ServiceContainer\Configuration\EventSubscriberConfiguration;
use Yoanm\BehatUtilsExtension\ServiceContainer\Configuration\LoggerConfiguration;
use Yoanm\BehatUtilsExtension\ServiceContainer\Configuration\StepLoggerConfiguration;

class BehatUtilsExtension implements Extension
{
    const EXTENSION_CONFIG_KEY = 'behat_utils';
    const CONTAINER_KEY_BASE = 'behat_utils_extension';

    /**
     * {@inheritdoc}
     */
    public function getConfigKey()
    {
        return self::EXTENSION_CONFIG_KEY;
    }

    // @codeCoverageIgnoreStart
    /**
     * {@inheritdoc}
     */
    public function initialize(ExtensionManager $extensionManager)
    {
    }
    // @codeCoverageIgnoreEnd

    /**
     * {@inheritdoc}
     */
    public function configure(ArrayNodeDefinition $builder)
    {
        $builder->append((new LoggerConfiguration())->getConfigNode());
        $builder->append((new StepLoggerConfiguration())->getConfigNode());
        $builder->append((new EventSubscriberConfiguration())->getConfigNode());
    }

    /**
     * {@inheritdoc}
     */
    public function load(ContainerBuilder $container, array $config)
    {
        $this->bindConfigToContainer($container, $config);

        $loader = new XmlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );

        $loader->load('logger.xml');

        if (true === $config['event_subscriber']['enabled']) {
            $loader->load('event_subscriber.xml');
        }

        if (true === $config['step_logger']['enabled']) {
            $loader->load('behat_step_logger.xml');
        }
    }

    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
    }

    /**
     * @param ContainerBuilder $container
     * @param array            $config
     * @param string           $baseId
     */
    protected function bindConfigToContainer(
        ContainerBuilder $container,
        array $config,
        $baseId = self::CONTAINER_KEY_BASE
    ) {
        foreach ($config as $configKey => $configValue) {
            if (is_array($configValue)) {
                $this->bindConfigToContainer(
                    $container,
                    $configValue,
                    sprintf('%s.%s', $baseId, $configKey)
                );
            } else {
                $container->setParameter(sprintf('%s.%s', $baseId, $configKey), $configValue);
            }
        }
    }
}


<?php

namespace Asoc\Dadatata\Filter\PDFBox;

use Asoc\Dadatata\Exception\ProcessingFailedException;
use Asoc\Dadatata\Filter\DocumentImageOptions;
use Asoc\Dadatata\Filter\FilterInterface;
use Asoc\Dadatata\Filter\OptionsInterface;
use Asoc\Dadatata\Model\ThingInterface;
use Asoc\Dadatata\Tool\PdfBox;
use Asoc\Dadatata\ToolInterface;
use Neutron\TemporaryFilesystem\TemporaryFilesystemInterface;

class PdfToImage implements FilterInterface
{
    /**
     * @var \Asoc\Dadatata\ToolInterface|PdfBox
     */
    private $pdfBox;
    /**
     * @var \Neutron\TemporaryFilesystem\TemporaryFilesystemInterface
     */
    private $tmpFs;
    /**
     * @var OptionsInterface
     */
    private $defaults;

    public function __construct(ToolInterface $pdfBox, TemporaryFilesystemInterface $tmpFs)
    {
        $this->pdfBox = $pdfBox;
        $this->tmpFs  = $tmpFs;
    }

    /**
     * @param ThingInterface   $thing
     * @param string           $sourcePath
     * @param OptionsInterface $options
     *
     * @throws \Asoc\Dadatata\Exception\ProcessingFailedException
     * @return array Paths to generated files
     */
    public function process(ThingInterface $thing, $sourcePath, OptionsInterface $options = null)
    {
        $tmpDir = $this->tmpFs->createTemporaryDirectory();

        /** @var DocumentImageOptions $options */
        $options = $this->defaults->merge($options);

        $pb = $this->pdfBox->getProcessBuilder()
            ->toImage()
            ->imageType($options->getFormat())
            ->output($tmpDir)
            ->source($sourcePath);

        if ($options->has($options::OPTION_PAGES)) {
            $pages = $options->getPages();

            if (strpos($pages, '-') !== false) {
                list($startPage, $endPage) = explode('-', $pages);
            } else {
                $startPage = $pages;
            }

            $startPage = intval($startPage);
            if (isset($endPage)) {
                $endPage = intval($endPage);
            }

            if ($startPage === 0) {
                // one based
                $startPage = 1;

                if (isset($endPage)) {
                    $endPage++;
                }
            }

            $pb->startPage($startPage);

            if (isset($endPage)) {
                $pb->endPage($endPage);
            }
        }

        $process = $pb->getProcess();

        $code = $process->run();
        if ($code !== 0) {
            throw ProcessingFailedException::create(
                'Failed to convert PDF to image',
                $code,
                $process->getOutput(),
                $process->getErrorOutput()
            );
        }

        $outputFiles = glob($tmpDir.'*.jpg');

        return $outputFiles;
    }

    /**
     * @param ThingInterface $thing
     *
     * @return boolean
     */
    public function canHandle(ThingInterface $thing)
    {
        return $thing->getMime() === 'application/pdf';
    }

    /**
     * @param OptionsInterface $options
     */
    public function setOptions(OptionsInterface $options)
    {
        if (!($options instanceof DocumentImageOptions)) {
            $options = new DocumentImageOptions($options->all());
        }
        $this->defaults = $options;
    }
}


<?php
/**
 * Phossa Project
 *
 * PHP version 5.4
 *
 * @category  Package
 * @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\Statement;

use Phossa\Query\Message\Message;
use Phossa\Query\Builder\SettingsTrait;
use Phossa\Query\Clause\BeforeAfterTrait;
use Phossa\Query\Builder\BuilderInterface;
use Phossa\Query\Dialect\DialectAwareTrait;
use Phossa\Query\Exception\BadMethodCallException;

/**
 * StatementAbstract
 *
 * @abstract
 * @package Phossa\Query
 * @author  Hong Zhang <phossa@126.com>
 * @see     StatementInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
abstract class StatementAbstract implements StatementInterface
{
    use UtilityTrait,
        SettingsTrait,
        PreviousTrait,
        BeforeAfterTrait,
        DialectAwareTrait,
        BuilderAwareTrait,
        ParameterAwareTrait;

    /**
     * Statement type
     *
     * @var    string
     * @access protected
     */
    protected $type;

    /**
     * order, prefix, join char
     *
     * @var    array
     * @access protected
     */
    protected $config = [];

    /**
     * dialect related order, prefix, join char
     *
     * @var    array
     * @access protected
     */
    protected $dialect_config = [];

    /**
     * Constructor
     *
     * @param  BuilderInterface $builder
     * @access public
     */
    public function __construct(BuilderInterface $builder)
    {
        $this->setBuilder($builder);
        $this->setDialect($builder->getDialect());
    }

    /**
     * Pass any unkown method like 'get()' to the query executor
     *
     * @param  string $method
     * @param  array $arguments
     * @return mixed
     * @throws BadMethodCallException
     */
    public function __call(/*# string */ $method, array $arguments)
    {
        $executor = $this->getBuilder()->getExecutor();
        if ($executor && method_exists($executor, $method)) {
            $sql = $this->getStatement();
            $val = $this->getBindings();
            return call_user_func_array([$executor, $method], [$sql, $val]);
        }

        throw new BadMethodCallException(
            Message::get(Message::BUILDER_UNKNOWN_METHOD, $method),
            Message::BUILDER_UNKNOWN_METHOD
        );
    }

    /**
     * {@inheritDoc}
     */
    public function getStatement(
        array $settings = [],
        /*# bool */ $replace = true
    )/*# : string */ {
        // merge with builder's & provided settings
        $this->combineSettings(
            array_replace($this->getBuilder()->getSettings(), $settings)
        );

        // current settings
        $currSettings = $this->getSettings();

        // build PREVIOUS statement if any (UNION etc)
        $res = [];
        if ($this->hasPrevious()) {
            $res[] = $this->getPrevious()->getStatement($currSettings, false);
        }

        // build current statement
        $res[] = $this->build();

        // raw sql with placeholders
        $sql = join($currSettings['seperator'], $res);

        // replace placeholders with '?' or values
        if ($replace) {
            // flush bindings array
            $this->resetBindings();

            // replace with '?' or values
            $sql = $this->bindValues($sql, $currSettings);
        }

        return trim($sql);
    }

    /**
     * {@inheritDoc}
     */
    public function getPositionedStatement(array $settings = [])/*# : string */
    {
        $settings = array_replace($settings, ['positionedParam' => true]);
        return $this->getStatement($settings);
    }

    /**
     * {@inheritDoc}
     */
    public function getNamedStatement(array $settings = [])/*# : string */
    {
        $settings = array_replace($settings, ['namedParam' => true]);
        return $this->getStatement($settings);
    }

    /**
     * {@inheritDoc}
     */
    public function getType()/*# : string */
    {
        return $this->type;
    }

    /**
     * {@inheritDoc}
     */
    public function __toString()/*# : string */
    {
        return $this->getStatement();
    }

    /**
     * Real building the statement
     *
     * @return string
     * @access protected
     */
    protected function build()/*# : string */
    {
        // settings
        $settings = $this->getSettings();

        // before build()
        $this->beforeBuild();

        // configs
        $configs  = $this->getConfig();

        // start of result array
        $result = [$this->getType()];

        // seperator & indent
        $sp = $settings['seperator'];
        $in = $settings['indent'];
        $si = $sp . $in;

        foreach ($configs as $pos => $part) {
            // before clause
            if (isset($this->before[$pos])) {
                $result[] = join($sp, $this->before[$pos]);
            }

            $built = call_user_func([$this, $part['func']]);
            if (!empty($built)) {
                $prefix = $part['prefix'] . (empty($part['prefix']) ?
                    ($part['indent'] ? $in : '') : $si);
                $result[] = $prefix . join($part['join'] . $si, $built);
            }

            // after clause
            if (isset($this->after[$pos])) {
                $result[] = join($sp, $this->after[$pos]);
            }
        }

        return join($sp, $result);
    }

    /**
     * Get config of this type of statement
     *
     * @return array
     * @access protected
     */
    protected function getConfig()/*# : array */
    {
        $config = array_replace($this->config, $this->dialect_config);
        ksort($config);
        return $config;
    }

    /**
     * Things to do before build
     *
     * @access protected
     */
    protected function beforeBuild()
    {
        return;
    }
}


<?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;

use Phossa\Query\Dialect\Common\CreateTableStatementInterface;

/**
 * CreateTableTrait
 *
 * @package package_name
 * @author  Hong Zhang <phossa@126.com>
 * @see     CreateTableStatementInterface
 * @version 1.0.0
 * @since   1.0.0 added
 */
trait CreateTableTrait
{
    /**
     * SELECT ... LIKE
     *
     * @var    string
     * @access protected
     */
    protected $like;

    /**
     * @var    bool
     * @access protected
     */
    protected $temporary = false;

    /**
     * @var    bool
     * @access protected
     */
    protected $if_not_exists = false;

    /**
     * CREATE TEMPORARY TABLE ...
     *
     * @return self
     * @access public
     */
    public function temp()
    {
        $this->temporary = true;
        return $this;
    }

    /**
     * CREATE TABLE IF NOT EXISTS ...
     *
     * @return self
     * @access public
     */
    public function ifNotExists()
    {
        $this->if_not_exists = true;
        return $this;
    }

    /**
     * CREATE TABLE ... LIKE
     *
     * @param  string $tableName
     * @return self
     * @access public
     */
    public function like(/*# string */ $tableName)
    {
        $this->like = $tableName;
        return $this;
    }

    /**
     * CREATE TABLE ... SELECT ...
     *
     * @return SelectStatementInterface
     * @access public
     */
    public function select()/*# : SelectStatementInterface */
    {
        $cols = func_get_args();
        return $this->getBuilder()->setPrevious($this)
            ->select(false)->col($cols);
    }

    /**
     * build LIKE
     *
     * @access protected
     */
    protected function buildLike()
    {
        if ($this->like) {
            return ['LIKE ' . $this->quote($this->like)];
        } else {
            return [];
        }
    }
}


<?php
/**
 * Created by PhpStorm.
 * User: sicmouse
 * Date: 2018/9/1
 * Time: 下午10:31
 */

namespace DdvPhp\DdvRestfulApi\Abstracts;

use DdvPhp\DdvUrl;
use DdvPhp\DdvAuth\Sign;
use DdvPhp\DdvRestfulApi\Util\Auth as DdvAtuh;
use DdvPhp\DdvRestfulApi\Exception\AuthError as AuthErrorException;
use DdvPhp\DdvRestfulApi\Interfaces\RequestSignInfo as RequestSignInfoInterface;
use DdvPhp\DdvRestfulApi\Interfaces\AuthSign as AuthSignInterface;
use DdvPhp\DdvRestfulApi\Interfaces\Auth;

abstract class AuthSign implements AuthSignInterface
{

    /**
     *
     * @var Auth|null
     */
    protected $auth = null;
    protected $authDatas = array();
    protected $authDataDriverClass = '';
    protected $authDataDriverObj = null;
    protected $authDataDriverConfig = array();
    protected $authorization = null;
    protected $accessKeyId = null;
    /**
     * @var RequestSignInfoInterface $signInfo
     */
    protected $signInfo = null;
    protected $regSessionCard = '/^([\da-f]{4}-[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}-[\da-f]{8})$/i';

    public function __destruct()
    {
        $this->authDataDriverClose();
    }

    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
        $this->signInfo = $auth->getRequestSignInfo();
        $this->authDataDriverClassInit($auth->getAuthDataDriver());
        $this->authDataDriverConfig = $auth->getAuthDataDriverConfig();
        $this->authorization = $auth->getAuthorization();
    }

    //判断session_card
    public function isSessionCard($card_id = '')
    {
        return (boolean)preg_match($this->regSessionCard, $card_id);
    }

    //生成session_card
    public function createSessionCard()
    {
        $ua = $this->signInfo->getHeader('user-agent');
        $ua = empty($ua) ? microtime() : $ua;
        $session_card = strtolower(substr(md5(uniqid(mt_rand(), true)), 15, 4) . '-' . Sign::createGuid() . '-' . substr(md5($ua), 15, 8));
        $session_card = str_replace(substr($session_card, 13, 6), '-5555-', $session_card);
        return $session_card;
    }

    //生成session_key
    public function createSessionKey($session_card = null)
    {
        $session_card = empty($session_card) ? $this->createSessionCard() : $session_card;
        $ua = $this->signInfo->getHeader('user-agent');
        $ua = empty($ua) ? microtime() : $ua;
        $session_key = strtolower(
            substr(md5($this->createSessionCard() . $session_card), 7, 4)
            . '-' . substr(md5($this->createSessionCard() . mt_rand() . $session_card . Sign::createGuid()), 7, 12)
            . '-' . substr(md5(uniqid(mt_rand(), true)), 15, 4) . '-' . Sign::createGuid() . '-' . substr(md5($ua), 15, 8)
            . '-' . substr(md5(uniqid(mt_rand(), true) . $session_card), 7, 12)
            . '-' . substr(md5(mt_rand() . $session_card), 7, 4)
            . '-' . substr(md5($session_card . mt_rand() . $session_card), 7, 8)
            . '-' . substr(md5($ua . mt_rand() . $ua . $session_card), 7, 4)
        );
        return $session_key;
    }

    public function generateSessionId()
    {
        if ($this->authDataDriverObj && method_exists($this->authDataDriverObj, 'generateSessionId')) {
            return $this->authDataDriverObj->generateSessionId();
        }
        $sidLength = @ini_get('session.sid_length');
        $sidLength = !isset($sidLength) || intval($sidLength) <= 8 ? 32 : $sidLength;
        $randomSid = bin2hex(random_bytes($sidLength));
        // Use same charset as PHP
        $sessionId = '';
        if (!$sidLength > 12) {
            $server = $this->signInfo->getServers();

            $pp = isset($server['REMOTE_ADDR']) ? $server['REMOTE_ADDR'] : microtime();
            $pp .= isset($server['HTTP_CLIENT_IP']) ? $server['HTTP_CLIENT_IP'] : microtime();
            $pp .= isset($server['HTTP_X_FORWARDED_FOR']) ? $server['HTTP_X_FORWARDED_FOR'] : microtime();
            $sessionId = substr(md5(microtime() . $pp . mt_rand() . Sign::createGuid()), 0, 3);
            $sessionId .= substr(md5($pp . microtime() . mt_rand() . $sidLength . $randomSid), 0, 3);
            $sessionId .= substr(md5(microtime() . $pp . mt_rand() . $pp . $this->createSessionKey() . $sessionId), 0, 3);
            $sessionId .= substr(md5(microtime() . $sessionId . mt_rand() . $pp . $randomSid), 0, 3);
        }
        $sessionId .= substr(rtrim(strtr($randomSid, '+/', ',-'), '='), 0, $sidLength - ($sidLength > 12 ? 12 : 0));
        $sessionId = substr($sessionId, 0, $sidLength);

        if ($this->getAuthData($sessionId) !== null) {
            return $this->generateSessionId();
        }
        return $sessionId;
    }

    public function getAccessKeyId(){
        return $this->accessKeyId;
    }
    public function getAuthData($accessKeyId)
    {
        if (isset($authDatas[$accessKeyId])) {
            return $authDatas[$accessKeyId];
        }
        // 读取数据
        $res = $this->getAuthDataDriver()->read($accessKeyId);
        // 反序列化并且返回
        $authDatas[$accessKeyId] = empty($res) ? null : unserialize($res);
        return $authDatas[$accessKeyId];
    }

    public function saveAuthData($accessKeyId, $data = null)
    {
        $authDatas[$accessKeyId] = $data;
        // 序列化数组
        $res = serialize($data);
        // 保存数据
        $res = $this->getAuthDataDriver()->write($accessKeyId, $res);
    }

    public function getAuthDataDriver()
    {
        if ($this->authDataDriverObj && method_exists($this->authDataDriverObj, 'close')) {
            return $this->authDataDriverObj;
        }
        $this->authDataDriverObj = new $this->authDataDriverClass();
        // 打开连接
        $this->authDataDriverObj->open($this->authDataDriverConfig);
        return $this->authDataDriverObj;
    }

    public function authDataDriverClose()
    {
        if (!($this->authDataDriverObj && method_exists($this->authDataDriverObj, 'close'))) {
            return;
        }
        // 打开连接
        $this->authDataDriverObj->close();
        $this->authDataDriverObj = null;
    }

    public function getSignHeaders($signHeaderKeys = array())
    {
        $signHeaders = array();
        $signSysHeadersKeys = $this->signInfo->getSysHeadersKeys();
        $signHeaderKeysLower = [];
        foreach ($signHeaderKeys as $key) {
            $signHeaderKeysLower[] = strtolower(str_replace('-', '_', $key));
            $value = $this->signInfo->getHeader($key);
            if ($value !== null && is_string($value)) {
                $signHeaders[$key] = $value;
            } else {
                throw new AuthErrorException('I did not find your authorization header[' . $key . ']', 'AUTHORIZATION_HEADERS_NOT_FIND', 403);
            }
        }
        // 遍历所有获取到的，但是没有签名的
        foreach ($this->signInfo->getXHeadersKeys() as $key) {
            // 匹配的时候，需要把键名的-替换为_ 因为php的特殊原因
            if (!in_array(strtolower(str_replace('-', '_', $key)), $signHeaderKeysLower)) {
                throw new AuthErrorException('The following header information you have not authenticated[' . $key . ']', 'AUTHORIZATION_HEADERS_X_NOT_ALL_SIGNATURES', 403);
            }
        }
        // 遍历所有获取到的，但是没有签名的
        foreach ($this->signInfo->getSysHeadersKeys() as $key) {
            $keyt = strtolower(str_replace('-', '_', $key));
            // 匹配的时候，需要把键名的-替换为_ 因为php的特殊原因
            if (!in_array($keyt, $signHeaderKeysLower)) {
                // 如果不需要检验请求体正确性
                if (!$this->signInfo->isValidationContentMd5()) {
                    // 就不检验以下字段的缺失
                    if (in_array($keyt, ['content_md5', 'content_type', 'content_length'])) {
                        continue;
                    }
                }
                throw new AuthErrorException('The following header information you have not authenticated[' . $key . ']', 'AUTHORIZATION_HEADERS_SYS_NOT_ALL_SIGNATURES', 403);
            }
        }
        return $signHeaders;
    }

    // 获取已经索取的数据信息
    public function getSignUrlByUrl($accessKeyId = null, $url = '/', $noSignQuery = array(), $method = 'GET', $query = array(), $headers = array(), $authClassName = null)
    {
        $urlObj = DdvUrl::parse($url);
        if ($urlObj['query']) {
            $params = DdvUrl::parseQuery($urlObj['query']);
            $params = is_array($params) ? $params : array();
            $params = array_merge($params, $query);
            $path = self::getSignUrl($accessKeyId, $urlObj['path'], $params, $noSignQuery, $method, $headers, $authClassName);
            $index = strpos($path, '?');
            if ($index !== false) {
                $urlObj['path'] = substr($path, 0, $index);
                $urlObj['query'] = substr($path, $index + 1);
            } else {
                $urlObj['path'] = $path;
            }
        }
        return DdvUrl::build($urlObj);
    }

    public function getSignUrl($accessKeyId = null, $path = '/', $query = array(), $noSignQuery = array(), $method = 'GET', $headers = array(), $authClassName = null)
    {
        if (empty($accessKeyId)) {
            throw new AuthErrorException('session id must input', 'MUST_INPUT_SESSION_ID', 400);
        }
        $authData = $this->auth->getAuthData($accessKeyId);
        if (empty($authData)) {
            throw new AuthErrorException('auth data not find', 'AUTH_DATA_NOT_FIND', 400);
        }
        if (empty($authClassName)) {
            $authClassName = \DdvPhp\DdvRestfulApi\Auth\AuthSignDdvUrlV1::class;
        }
        if (!class_exists($authClassName)) {
            throw new AuthErrorException('Authentication Version Class Not Find', 'AUTHENTICATION_VERSION_CLASS_NOT_FIND', 400);
        }
        if (!method_exists($authClassName, 'getSignUrl')) {
            throw new AuthErrorException('Authentication Version Class Not support getSignUrl', 'AUTHENTICATION_VERSION_CLASS_NOT_SUPPORT_GET_SIGN_URL', 400);
        }
        return $authClassName::getSignUrl($accessKeyId, $authData, $path, $query, $noSignQuery, $method, $headers, $authClassName);
    }

    public function checkContentMd5True()
    {
        if (!$this->signInfo->isPassContentMd5()) {
            throw new AuthErrorException('Content Md5 Error', 'CONTENT_MD5_ERROR', 403);
        }
    }

    public function checkContentLengthTrue()
    {
        if (!$this->signInfo->isPassContentLength()) {
            throw new AuthErrorException('Content Length Error', 'CONTENT_LENGTH_ERROR', 403);
        }
    }

    protected function authDataDriverClassInit($authDataDriverInput)
    {
        // 默认是这种模式查找
        $authDataDriver = $authDataDriverInput;
        if (!class_exists($authDataDriver)) {
            $authDataDriver = '\\DdvPhp\\DdvRestfulApi\\AuthData\\AuthData' . ucfirst($authDataDriverInput) . 'Driver';
        }
        if (!class_exists($authDataDriver)) {
            $authDataDriver = '\\' . $authDataDriverInput;
        }
        if (!class_exists($authDataDriver)) {
            throw new AuthErrorException('authDataDriver Class Not Find', 'AUTHDATADRIVER_CLASS_NOT_FIND', '500');
        }

        $this->authDataDriverClass = $authDataDriver;
        unset($authDataDriver, $authDataDriverInput);
    }
}


<?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\Util;

/**
 * 配列に関する操作を行うユーティリティクラスです.
 */
class Arrays
{
    /**
     * このクラスはインスタンス化できません
     */
    private function __construct() {}

    /**
     * {@link Arrays::max} と {@link Arrays::min} の共通部分の実装です.
     * @param  array      $arr
     * @param  Comparator $c
     * @param  bool       $isMax
     * @return mixed
     */
    private static function getTop(array $arr, Comparator $c = null, $isMax = false)
    {
        if (!isset($c)) {
            $c = DefaultComparator::getInstance();
        }
        $candidate = null;
        foreach ($arr as $current) {
            if (!isset($candidate)) {
                $candidate = $current;
                continue;
            }
            $comp = $c->compare($current, $candidate);
            if (($isMax && 0 < $comp) || (!$isMax && $comp < 0)) {
                $candidate = $current;
            }
        }
        return $candidate;
    }

    /**
     * 指定された配列の各要素の中で「最も大きい」値を返します.
     *
     * 配列に含まれるオブジェクトが {@link Comparable} を実装している場合は
     * そのオブジェクトの {@link Comparable::compareTo}
     * メソッドを使って大小の比較を行います. それ以外の値の場合は
     * {@link http://jp.php.net/manual/ja/language.operators.comparison.php PHP の比較演算子のルール}
     * に従って大小比較が行われます.
     *
     * 大小の比較方法が型によって異なるため,
     * 配列内の要素の型に一貫性がない場合は, 格納順序の違いによって
     * 異なる結果となる可能性があります.
     * 意図しない動作を防ぐためには, あらかじめ {@link Arrays::pickup}
     * を使って配列に含まれる型を揃えてください.
     *
     * オプションとして第 2 引数に {@link Comparator}
     * オブジェクトを指定することもできます.
     * もし第 2 引数が指定された場合は {@link Comparator::compare}
     * メソッドを使って大小比較を行います.
     *
     * @param  array      $arr
     * @param  Comparator $c
     * @return mixed      引数 $arr の中で最も大きな値. 配列が空の場合は NULL
     */
    public static function max(array $arr, Comparator $c = null)
    {
        return self::getTop($arr, $c, true);
    }

    /**
     * 指定された配列の各要素の中で「最も小さい」値を返します.
     *
     * 配列に含まれるオブジェクトが {@link Comparable} を実装している場合は
     * そのオブジェクトの {@link Comparable::compareTo}
     * メソッドを使って大小の比較を行います. それ以外の値の場合は
     * {@link http://jp.php.net/manual/ja/language.operators.comparison.php PHP の比較演算子のルール}
     * に従って大小比較が行われます.
     *
     * 大小の比較方法が型によって異なるため,
     * 配列内の要素の型に一貫性がない場合は, 格納順序の違いによって
     * 異なる結果となる可能性があります.
     * 意図しない動作を防ぐためには, あらかじめ {@link Arrays::pickup}
     * を使って配列に含まれる型を揃えてください.
     *
     * オプションとして第 2 引数に {@link Comparator}
     * オブジェクトを指定することもできます.
     * もし第 2 引数が指定された場合は {@link Comparator::compare}
     * メソッドを使って大小比較を行います.
     *
     * @param  array      $arr
     * @param  Comparator $c
     * @return mixed      $arr の中で最も大きな値. 配列が空の場合は NULL
     */
    public static function min(array $arr, Comparator $c = null)
    {
        return self::getTop($arr, $c, false);
    }

    /**
     * 配列の中から, $type で指定した型の値だけを取り出します.
     * $keyFlag に TRUE を指定した場合はキーと要素の関連付けを維持します.
     * $type に指定できる文字列は以下のとおりです. (大文字・小文字は区別しません)
     *
     * - int
     * - integer
     * - numeric
     * - float (※ numeric と同じです. int 型の値もマッチングします.)
     * - string
     * - bool
     * - boolean
     * - array
     * - object
     * - resource
     * - null
     *
     * 上記に挙げた以外の文字列を指定した場合は, クラス (インタフェース) 名として扱います.
     *
     * @param  array  $arr     対象の配列
     * @param  string $type    'int', 'integer', 'numeric', 'float', 'string', 'bool',
     *                         'object', 'resource' など.
     *                         それ以外の文字列はクラス (インタフェース) 名として扱う
     * @param  bool   $keyFlag 関連付けを維持する場合は TRUE (デフォルトは FALSE)
     * @return array
     */
    public static function pickup(array $arr, $type, $keyFlag = false)
    {
        $result = array();
        foreach ($arr as $key => $value) {
            if (self::pickupMatch($value, $type)) {
                if ($keyFlag) {
                    $result[$key] = $value;
                } else {
                    $result[] = $value;
                }
            }
        }
        return $result;
    }

    /**
     * 指定された値が第 2 引数で指定した型にマッチするかどうかを調べます.
     *
     * @param  string  $value 検査対象の値
     * @param  string  $type  型
     * @return bool           引数 $value の型が $type に合致する場合に true
     */
    private static function pickupMatch($value, $type)
    {
        $ltype = strtolower($type);
        switch ($ltype) {
            case 'int':
            case 'integer':
                return is_int($value);
            case 'float':
            case 'numeric':
                return is_numeric($value);
            case 'string':
                return is_string($value);
            case 'null':
                return is_null($value);
            case 'bool':
            case 'boolean':
                return is_bool($value);
            case 'array':
                return is_array($value);
            case 'resource':
                return is_resource($value);
            case 'object':
                return is_object($value);
            default:
                return is_object($value) && ($value instanceof $type);
        }
    }

    /**
     * 指定された配列をソートします.
     * 配列のキーは連番で初期化されます.
     * コンパレータが指定されなかった場合は {@link DefaultComparator} が適用されます.
     *
     * @param  array      $arr ソート対象の配列
     * @param  Comparator $c   コンパレータ
     * @return array
     */
    public static function sort(array $arr, Comparator $c = null)
    {
        if (count($arr) < 2) {
            return $arr;
        }
        if (!isset($c)) {
            $c = DefaultComparator::getInstance();
        }
        $func = function ($var1, $var2) use ($c) {
            return $c->compare($var1, $var2);
        };
        usort($arr, $func);
        return $arr;
    }

    /**
     * 配列のキーと値のマッピングを保持しながら, 指定された配列をソートします.
     * コンパレータが指定されなかった場合は {@link DefaultComparator} が適用されます.
     *
     * @param  array      $arr ソート対象の配列
     * @param  Comparator $c   コンパレータ
     * @return array           ソート後の配列
     */
    public static function asort(array $arr, Comparator $c = null)
    {
        if (count($arr) < 2) {
            return $arr;
        }
        if (!isset($c)) {
            $c = DefaultComparator::getInstance();
        }
        $func = function ($var1, $var2) use ($c) {
            return $c->compare($var1, $var2);
        };
        uasort($arr, $func);
        return $arr;
    }

    /**
     * 引数の配列または値を連結して, 一つの配列として返します.
     *
     * 例えば
     *
     *
     * $arr1   = array(10, 20, 30);
     * $arr2   = array(40, 50);
     * $concat = Arrays::concat($arr1, "X", $arr2, "Y");
     *
     *
     * の結果は
     *
     * array(10, 20, 30, "X", 40, 50, "Y")
     *
     * に等しくなります。
     *
     * この関数は多次元配列はサポートしません.
     *
     *
     * $arr1 = array("hoge", "fuga");
     * $arr2 = array(
     *     array(1, 2, 3),
     *     array(5, 7)
     * );
     * $concat = Arrays::concat($arr1, $arr2);
     *
     *
     * の結果は
     *
     *
     * array(
     *     "hoge",
     *     "fuga",
     *     array(1, 2, 3),
     *     array(5, 7)
     * )
     *
     *
     * となります.
     *
     * この関数は, 配列に含まれるキーをすべて無視します.
     * 結果の配列のキーは連番で初期化されます.
     *
     * @return array
     */
    public static function concat()
    {
        $args = func_get_args();
        $result = array();
        foreach ($args as $arg) {
            if (is_array($arg)) {
                foreach ($arg as $subarg) {
                    $result[] = $subarg;
                }
            } else {
                $result[] = $arg;
            }
        }
        return $result;
    }

    /**
     * 指定された配列から, 重複した値を取り除いた結果を返します.
     * 重複かどうかの判定は, 引数に指定されたコンパレータを使って行われます.
     * コンパレータが指定されなかった場合は {@link DefaultComparator} が適用されます.
     *
     * @param  array      $arr
     * @param  Comparator $c   コンパレータ
     * @return array
     */
    public static function unique(array $arr, Comparator $c = null)
    {
        if (!isset($c)) {
            $c = DefaultComparator::getInstance();
        }
        $sorted = self::asort($arr, $c);
        $delKey = array();
        list($lastKey, $lastValue) = each($sorted);
        while (list($key, $value) = each($sorted)) {
            if ($c->compare($value, $lastValue) === 0 && $value == $lastValue) {
                $delKey[] = $key;
                continue;
            } else {
                $lastKey = $key;
                $lastValue = $value;
            }
        }
        foreach ($delKey as $key) {
            unset($arr[$key]);
        }
        return $arr;
    }
}