rabin 1 年之前
当前提交
ef4ad141c1
共有 6 个文件被更改,包括 1010 次插入0 次删除
  1. 3 0
      README.md
  2. 25 0
      composer.json
  3. 74 0
      dever.php
  4. 148 0
      src/Dever/Config.php
  5. 625 0
      src/Dever/Import.php
  6. 135 0
      src/Dever/Route.php

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+framework
+
+wiki 

+ 25 - 0
composer.json

@@ -0,0 +1,25 @@
+{
+    "name": "dever-main/framework",
+    "type": "framework",
+    "description": "dever framework",
+    "keywords": ["framework","library"],
+    "homepage": "https://github.com/dever-main/framework",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Rabin",
+            "email": "2934170@qq.com"
+        }
+    ],
+    "require": {
+        "php": ">=5.0.0"
+    },
+    "autoload": {
+        "files": [
+            "dever.php"
+        ],
+        "psr-4": {
+            "Dever\\": "src/Dever/"
+        }
+    }
+}

+ 74 - 0
dever.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * This file is part of Dever.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    rabin<rabin@shemic.com>
+ * @copyright rabin<rabin@shemic.com>
+ * @link      http://www.dever.cc/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+class Dever
+{
+    /**
+     * @var array
+     */
+    private static $register = array
+    (
+        'load' => array('Import', 'load'),
+        'config' => array('Config', 'get'),
+        'input' => array('Route', 'input'),
+    );
+
+    /**
+     * @var array
+     */
+    private static $define = array();
+
+    /**
+     * run
+     */
+    public static function run()
+    {
+        $data = Dever\Route::get();
+        Dever\Import::load($data['l']);
+    }
+
+    /**
+     * call
+     * @param string $name
+     * @param array $param
+     * @return mixed
+     */
+    public static function __callStatic($name, $param = array())
+    {
+        if (isset(self::$register[$name])) {
+            $class = 'Dever\\' . self::$register[$name][0];
+            $method = self::$register[$name][1];
+            return call_user_func_array(array($class, $method), $param);
+        } elseif (isset(self::$define[$name])) {
+            if (is_array(self::$define[$name])) {
+                $class = self::$define[$name][0];
+                $method = self::$define[$name][1];
+            } else {
+                 $class = self::$define[$name];
+                 $method = $name;
+            }
+            return call_user_func_array(array($class, $method), $param);
+        }
+    }
+
+    /**
+     * register
+     * @param string $method
+     * @param array $function
+     * @return mixed
+     */
+    public static function reg($method, $function)
+    {
+        self::$define[$method] = $function;
+    }
+}

+ 148 - 0
src/Dever/Config.php

@@ -0,0 +1,148 @@
+<?php
+/**
+ * This file is part of Dever.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    rabin<rabin@shemic.com>
+ * @copyright rabin<rabin@shemic.com>
+ * @link      http://www.dever.cc/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Dever;
+use Dever;
+/**
+ * Class Config
+ * @package Dever
+ */
+class Config
+{
+    /**
+     * @var string
+     */
+    protected $path = '';
+
+    /**
+     * @var string
+     */
+    protected $key = '';
+
+    /**
+     * @var array
+     */
+    protected $data = array();
+
+    /**
+     * @var object
+     */
+    protected static $instance;
+
+    /**
+     * __construct
+     */
+    public function __construct($path)
+    {
+        $this->path = $path;
+    }
+
+    /**
+     * __set
+     */
+    public function __set($name, $value)
+    {
+        $this->data[$this->key][$name] = $value;
+    }
+
+    /**
+     * __get
+     */
+    public function __get($name)
+    {
+        if (array_key_exists($name, $this->data[$this->key])) {
+            return $this->data[$this->key][$name];
+        } elseif ($name == 'all') {
+            return $this->data[$this->key];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * __isset
+     */
+    public function __isset($name)
+    {
+        return isset($this->data[$this->key][$name]);
+    }
+
+    /**
+     * __unset
+     */
+    public function __unset($name)
+    {
+        unset($this->data[$this->key][$name]);
+    }
+
+    /**
+     * get
+     * @param string $key
+     * @param string $path
+     * @return array
+     */
+    public static function get($key, $path = 'config')
+    {
+        if (empty(self::$instance[$path])) {
+            self::$instance[$path] = new self($path);
+        }
+
+        return self::$instance[$path]->load($key);
+    }
+
+    /**
+     * load
+     * @param string $key
+     * @return array
+     */
+    public function load($key)
+    {
+        $this->key = $key;
+        if (empty($this->data[$this->key])) {
+            $env = $this->env();
+            $this->data[$this->key] = array();
+            $config = array(DEVER_APP_PATH, DEVER_PROJECT_PATH, DEVER_PATH);
+            foreach ($config as $k => $v) {
+                $file = $v . $this->path . DIRECTORY_SEPARATOR . $this->key . '.php';
+                if (is_file($file)) {
+                    $this->data[$this->key] += include($file);
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * env
+     * @return array
+     */
+    protected function env()
+    {
+        if (empty($_SERVER['DEVER_ENV_NAME'])) {
+            if (isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] != '127.0.0.1') {
+                $_SERVER['DEVER_ENV_NAME'] = $_SERVER['SERVER_NAME'];
+            } else {
+                $_SERVER['DEVER_ENV_NAME'] = 'localhost';
+            }
+        }
+        if (empty($_SERVER['DEVER_ENV_PATH'])) {
+            $_SERVER['DEVER_ENV_PATH'] = DEVER_PROJECT_PATH . $this->path . DIRECTORY_SEPARATOR . 'env' . DIRECTORY_SEPARATOR;
+        }
+
+        $file = $_SERVER['DEVER_ENV_PATH'] . $_SERVER['DEVER_ENV_NAME'] . '.php';
+        if (is_file($file)) {
+            return include($file);
+        }
+    }
+}

+ 625 - 0
src/Dever/Import.php

@@ -0,0 +1,625 @@
+<?php
+/**
+ * This file is part of Dever.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    rabin<rabin@shemic.com>
+ * @copyright rabin<rabin@shemic.com>
+ * @link      http://www.dever.cc/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Dever;
+use Dever;
+/**
+ * Class Import
+ * @package Dever
+ */
+class Import
+{
+    /**
+     * API
+     *
+     * @var string
+     */
+    const API = '_api';
+
+    /**
+     * SECURE
+     *
+     * @var string
+     */
+    const SECURE_API = '_secure_api';
+
+    /**
+     * COMMIT
+     *
+     * @var string
+     */
+    const COMMIT = '_commit';
+
+    /**
+     * MAIN
+     *
+     * @var string
+     */
+    const MAIN = 'main';
+
+    /**
+     * api
+     *
+     * @var bool
+     */
+    protected $api = false;
+
+    /**
+     * param
+     *
+     * @var array
+     */
+    protected $param;
+
+    /**
+     * class
+     *
+     * @var array
+     */
+    protected $class;
+
+    /**
+     * data
+     *
+     * @var array
+     */
+    protected $data;
+
+    /**
+     * key
+     *
+     * @var string
+     */
+    protected $key;
+
+    /**
+     * commit
+     *
+     * @var bool
+     */
+    protected static $commit = false;
+
+    /**
+     * instance
+     *
+     * @var string
+     */
+    protected static $instance;
+
+    /**
+     * load
+     *
+     * @param  string  $method
+     * @param  array  $param
+     * @return \Dever\Loader\Import
+     */
+    public static function load()
+    {
+        list($key, $attr, $param) = self::argc(func_get_args());
+        print_r($key);die;
+
+        if (empty(self::$instance[$key])) {
+            self::$instance[$key] = new self($key);
+        }
+
+        return self::$instance[$key]->get($param, $attr);
+    }
+
+    /**
+     * argc
+     * @param array $param
+     *
+     * @return array
+     */
+    public static function argc($argv)
+    {
+        if (isset($argv[0])) {
+            $method = $argv[0];
+        } else {
+            Export::alert('api_param_exists', 'method');
+        }
+
+        $param = array();
+        if (isset($argv[1])) {
+            unset($argv[0]);
+            $param = array_values($argv);
+        }
+
+        return array($method, $param);
+    }
+
+    /**
+     * apply
+     *
+     * @return mixed
+     */
+    public static function apply($file, $project = false)
+    {
+        Library::get()->apply($file, $project);
+    }
+
+    /**
+     * __construct
+     *
+     * @return mixed
+     */
+    protected function __construct($key)
+    {
+        $this->key = $key;
+    }
+
+    /**
+     * get
+     *
+     * @return mixed
+     */
+    protected function get($param = array(), $attr = '')
+    {
+        $this->data($this->status($param));
+
+        if ($attr) {
+            if (isset($this->data[$attr])) {
+                return $this->data[$attr];
+            }
+            return false;
+        }
+
+        return $this->data;
+    }
+
+    /**
+     * data
+     *
+     * @return mixed
+     */
+    protected function data($status)
+    {
+        $cache = $this->cache();
+        if ($cache) {
+            $this->data = $cache;
+        } else {
+            $this->getData($status);
+            $this->cache($this->data);
+        }
+    }
+
+    /**
+     * getData
+     *
+     * @return mixed
+     */
+    protected function getData($status)
+    {
+        if (strpos($this->key, 'http://') !== false) {
+            $this->loadServer($this->key);
+        }
+
+        if ($status == true || empty($this->data)) {
+            $this->data = array();
+            $this->loadClass();
+        }
+
+        $state = false;
+    }
+
+    /**
+     * loadServer
+     *
+     * @return mixed
+     */
+    protected function loadServer($key = '', $url = '')
+    {
+        $this->data = $this->cache(false, 'curl');
+        if (!$this->data) {
+            if (isset($this->param[0]) && !isset($this->param[1])) {
+                $param = $this->param[0];
+            } else {
+                $param = $this->param;
+            }
+            $this->data = Server::get($url, $key, $param);
+            $this->cache($this->data, 'curl');
+        }
+    }
+
+    /**
+     * loadClass
+     *
+     * @return mixed
+     */
+    protected function loadClass()
+    {
+        $this->manage();
+
+        if (strpos($this->key, '!')) {
+            $this->key = str_replace('!', '.' . self::MAIN, $this->key);
+        }
+
+        if (strpos($this->key, '.')) {
+            $this->loadMethod();
+        } elseif (strpos($this->key, '-')) {
+            $this->loadModel();
+        } else {
+            $this->class = Library::get()->loadClass($this->key);
+            $this->data =& $this->class;
+        }
+    }
+
+    /**
+     * loadModel
+     *
+     * @return mixed
+     */
+    protected function loadModel()
+    {
+        if (isset($this->param[0])) {
+            $param = $this->param[0];
+        } else {
+            $param = $this->param;
+        }
+        $this->data = Model::load($this->key, $param);
+    }
+
+    /**
+     * loadMethod
+     *
+     * @return mixed
+     */
+    protected function loadMethod()
+    {
+        list($class, $method) = $this->demerge();
+        list($key, $project) = Library::get()->getProject($class);
+        $this->ai($project);
+        if ($this->data) {
+            return;
+        }
+        if ($project && strpos($project['path'], 'http') === 0) {
+            //$url = Url::get($project['name'] . '/' . strtolower($key) . '.' . $method);
+            $this->loadServer('l=' . strtolower($key) . '.' . $method, $project['path']);
+            return;
+        }
+
+        $this->class = Library::get()->loadClass($class);
+        $method = $this->api($class, $method);
+        $commit = $this->commit($method);
+        //$commit = false;
+        if ($commit) {
+            $db = Model::load(DEVER_APP_NAME . '/commit');
+            try {
+                self::$commit = true;
+                $db->begin();
+                $this->call($method, $project);
+                $db->commit();
+            } catch (\Exception $e) {
+                $db->rollBack();
+                $data = $e->getTrace();
+                Debug::trace($data);
+                if (isset($data[0]['args'][1])) {
+                    if (isset($data[0]['args'][2])) {
+                        throw new Exceptions($data[0]['args'][1] . '['.$data[0]['args'][2].':'.$data[0]['args'][3].']');
+                    } else {
+                        throw new Exceptions($data[0]['args'][1] . '['.$data[0]['file'].':'.$data[0]['line'].']');
+                    }
+                    
+                } else {
+                    throw new Exceptions($data[0]['file'] . '['.$data[0]['line'].']');
+                }
+            }
+        } else {
+            $this->call($method, $project);
+        }
+    }
+
+    /**
+     * ai
+     *
+     * @return mixed
+     */
+    protected function ai($project)
+    {
+        if (DEVER_APP_NAME == 'ai' && !$project && Config::get('base')->ai && isset(Config::get('base')->ai[$this->key])) {
+            $this->data = Import::load('ai/data.get', $this->key, Config::get('base')->ai[$this->key]);
+        }
+    }
+
+    /**
+     * demerge
+     *
+     * @return mixed
+     */
+    protected function demerge()
+    {
+        list($class, $method) = explode('.', $this->key);
+        $main = array(self::MAIN . self::API, self::MAIN . self::SECURE_API, self::MAIN . self::COMMIT);
+        if (in_array($method, $main)) {
+            $method = str_replace(self::API, '', $method);
+        }
+        return array($class, $method);
+    }
+
+    /**
+     * call
+     *
+     * @return mixed
+     */
+    protected function call($method, $project)
+    {
+        if (is_array($method)) {
+            foreach ($method as $one) {
+                $this->call($one, $project);
+                $this->setCall();
+            }
+        } else {
+            $plugin = Config::get('plugin')->{$this->key};
+            $this->step($method, $this->class);
+            $param = $this->getParam($method);
+            if ($plugin && isset($plugin['start'])) {
+                $param = Import::load($project['name'] . '/plugin/' . $plugin['start'], $param);
+            }
+
+            if ($plugin && isset($plugin['cover'])) {
+                $this->data = Import::load($project['name'] . '/plugin/' . $plugin['cover'], $param);
+            } else {
+                if (is_array($param) && $param) {
+                    if (isset($param[0]) && is_array($param[0])) {
+                        foreach ($param[0] as $k => $v) {
+                            Input::set($k, $v);
+                        }
+                    }
+                    $this->data = call_user_func_array(array($this->class, $method), $param);
+                } else {
+                    $this->data = call_user_func(array($this->class, $method), $param);
+                }
+            }
+
+            if ($plugin && isset($plugin['end'])) {
+                Import::load($project['name'] . '/plugin/' . $plugin['end'], $this->data);
+            }
+            
+            Debug::reflection($this->class, $method);
+
+            if ($this->api) {
+                $this->apiRecord();
+            }
+        }
+    }
+
+    /**
+     * getParam
+     *
+     * @return mixed
+     */
+    protected function getParam($method)
+    {
+        if (!isset($this->param[0])) {
+            $reflectionMethod = new \ReflectionMethod($this->class, $method);
+            $param = $reflectionMethod->getParameters();
+            $result = array();
+            foreach ($param as $k => $v) {
+                $name = $v->name;
+                if (isset($this->param[$name])) {
+                    $result[$name] = $this->param[$name];
+                }
+            }
+            return $result;
+        } else {
+            return $this->param;
+        }
+    }
+
+    /**
+     * setCall
+     *
+     * @return mixed
+     */
+    protected function setCall()
+    {
+        if (!$this->data && isset($this->param['callback'])) {
+            $this->data = $this->param['callback'];
+        }
+        $this->param['callback'] = $this->data;
+    }
+
+    /**
+     * apiRecord
+     *
+     * @return mixed
+     */
+    protected function apiRecord()
+    {
+        if (Config::get('base')->apiDoc) {
+            Api::doc($this->key, $this->param, $this->data);
+        }
+
+        if (Config::get('base')->apiLog) {
+            Api::log($this->key, $this->param, $this->data);
+        }
+    }
+
+    /**
+     * api
+     *
+     * @return mixed
+     */
+    protected function api($class, $method)
+    {
+        $this->api = false;
+        if (strpos($method, self::API) !== false) {
+            $this->api = true;
+            $method = $this->secure($method);
+            $map = Helper::replace(array(self::API, self::SECURE_API), '', $method);
+            if (method_exists($this->class, $map) && method_exists($this->class, $method)) {
+                return array($map, $method);
+            }
+        }
+
+        if (Config::get('base')->apiConfig) {
+            list($api, $method) = Api::load($class, $method, self::API, $this->param);
+            if ($api) {
+                $this->api = $api;
+            }
+        }
+
+        if (!method_exists($this->class, $method)) {
+            if (strpos($method, self::API) !== false && Config::get('base')->apiOpenPath) {
+                $className = get_class($this->class);
+                if (stripos($className, '\\' . Config::get('base')->apiOpenPath)) {
+                    $temp = explode(self::API, $method);
+                    $method = $temp[0];
+                    if (method_exists($this->class, $method . '_commit')) {
+                        return $method . '_commit';
+                    }
+                    return $method;
+                }
+            }
+
+            if ($this->api == false) {
+                $newMethod = $method . self::API;
+                if (method_exists($this->class, $newMethod)) {
+                    return $newMethod;
+                }
+            }
+
+            Export::alert('method_exists', array($class, $method));
+        }
+        return $method;
+    }
+
+    /**
+     * secure
+     *
+     * @return mixed
+     */
+    protected function secure($method)
+    {
+        if (strpos($method, self::SECURE_API) !== false) {
+            Api::check($this->param);
+        } else {
+            $api = Helper::replace(self::API, self::SECURE_API, $method);
+            $token = $api . '_token';
+            $key = false;
+            if (method_exists($this->class, $token)) {
+                $key = call_user_func(array($this->class, $token));
+            }
+            if (method_exists($this->class, $api)) {
+                Api::check($this->param, array(), $key);
+                return $api;
+            }
+        }
+
+        return $method;
+    }
+
+    /**
+     * commit
+     *
+     * @return mixed
+     */
+    protected function commit($method)
+    {
+        if (self::$commit) {
+            return false;
+        }
+        if (is_array($method)) {
+            foreach ($method as $one) {
+                $state = $this->commit($one);
+                if ($state) {
+                    return true;
+                }
+            }
+        }
+        elseif (strpos($method, self::COMMIT) !== false) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * cache
+     *
+     * @return mixed
+     */
+    protected function cache($data = false, $type = 'load')
+    {
+        if (isset($this->param) && $this->param) {
+            $key = $this->key . '_' . md5(serialize($this->param));
+        } else {
+            $param = Input::get();
+            $key = $this->key . '_' . md5(serialize($param));
+        }
+
+        if ($page = Input::get('page')) {
+            $key .= '_p' . $page;
+        }
+
+        return Cache::load($key, $data, 0, $type, true);
+    }
+
+    /**
+     * status
+     *
+     * @return mixed
+     */
+    protected function status($param)
+    {
+        $status = false;
+        if (isset($param['cache']) && $param['cache']) {
+            $status = true;
+        } elseif (isset($this->param) && $this->param != $param) {
+            $status = true;
+        }
+        $this->param = $param;
+        //$this->unsetParam();
+        
+        return $status;
+    }
+
+    /**
+     * unsetParam
+     *
+     * @return mixed
+     */
+    protected function unsetParam()
+    {
+        $config = array('shell', 'json', 'callback', 'function');
+        foreach ($config as $k => $v) {
+            if (isset($this->param[$v])) {
+                unset($this->param[$v]);
+            }
+        }
+    }
+
+    /**
+     * step
+     *
+     * @return mixed
+     */
+    protected function step($method, $class)
+    {
+        $key = '_step_';
+        if (strpos($method, $key) != false) {
+            $config = explode($key, $method);
+
+            Step::init($config[0], $config[1], $key, $class);
+        }
+    }
+
+    /**
+     * log
+     *
+     * @return log
+     */
+    protected function log($method, $data = array())
+    {
+        Debug::log(array('method' => $method, 'param' => $this->param, 'data' => $data), 'load');
+    }
+}

+ 135 - 0
src/Dever/Route.php

@@ -0,0 +1,135 @@
+<?php
+/**
+ * This file is part of Dever.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    rabin<rabin@shemic.com>
+ * @copyright rabin<rabin@shemic.com>
+ * @link      http://www.dever.cc/
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Dever;
+use Dever;
+/**
+ * Class Route
+ * @package Dever
+ */
+class Route
+{
+    /**
+     * @var array
+     */
+    protected static $data = array();
+
+    /**
+     * get
+     * @param string $name
+     * @param string $lang
+     * @param string $condition
+     * @param string $value
+     * @return value
+     */
+    public static function input($key = false, $lang = '', $condition = '', $value = '')
+    {
+        if (!$key) {
+            return self::$data;
+        }
+
+        if (is_string($key) && isset(self::$data[$key]) && self::$data[$key]) {
+            $value = self::$data[$key];
+        }
+
+        return $value;
+
+        if ($condition) {
+            if (!$value) {
+                Dever::alert($lang . '不能为空');
+            }
+            $state = false;
+            $test = '$state = ' . $value . $condition . ';';
+            eval($test);
+            if (!$state) {
+                Dever::alert($lang);
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * get
+     */
+    public static function get()
+    {
+        !self::command() && self::api();
+        self::filter();
+        return self::$data;
+    }
+
+    /**
+     * command
+     * @return bool
+     */
+    protected static function command()
+    {
+        if (isset($_SERVER['argc'])) {
+            global $argv;
+            if (isset($argv[1]) && $argv[1]) {
+                self::$data = Dever::json_decode($argv[1]);
+            }
+            define('DEVER_PROTO', 'command');
+            define('DEVER_APP_HOST', '');
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * api
+     */
+    protected static function api()
+    {
+        self::$data = $_REQUEST;
+        if (isset($_FILES) && $_FILES) {
+            self::$data = array_merge(self::$data, $_FILES);
+        }
+        $pathinfo = self::pathinfo();
+        if ($pathinfo) {
+            self::$data['l'] = trim($pathinfo, '/');
+        }
+        
+        define('DEVER_PROTO', ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https' : 'http');
+        define('DEVER_APP_HOST', DEVER_PROTO . '://' . $_SERVER['HTTP_HOST'] . ($_SERVER['SCRIPT_NAME'] ? substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], DEVER_ENTRY)) : DIRECTORY_SEPARATOR));
+    }
+
+    /**
+     * pathinfo
+     * @return string
+     */
+    protected static function pathinfo()
+    {
+        $pathinfo = '';
+        if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO']) {
+            $pathinfo = $_SERVER['PATH_INFO'];
+        } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
+            $pathinfo = $_SERVER['ORIG_PATH_INFO'];
+        }
+        return $pathinfo;
+    }
+
+    protected static function filter()
+    {
+        if (self::$data) {
+            foreach (self::$data as $k => $v) {
+                if (self::$data[$k] == 'undefined') {
+                    self::$data[$k] = '';
+                } else {
+                    self::$data[$k] = htmlspecialchars($v);
+                }
+            }
+        }
+    }
+}