From 893becebab0fe4c3cb15df2aa41c86cad7678713 Mon Sep 17 00:00:00 2001 From: Emmanuel ROY Date: Wed, 4 Dec 2019 15:21:19 +0100 Subject: [PATCH] mise en place des actions de vue, du loggeur du MVC test des resultat des reponse Rest avec les methode GET PUT DELETE POST avec curl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FIXME: appel curl ou fopen d'une methode http depuis une action ou un controlleur. TODO: sécuriser les accès HTTP1.1 par un fichier config similaire a l'applet Discourse faite pour Tinternet TODO: ajouter un plug-in symfony permettant de charger un utilisateur dans les apps a partir de l'authentification multiple TODO: lire les documentation officielles provenant des 4 plate-formes tranquillement afin de comprendre commet doit on tester ces type d'auth quitte a créé un sous domaine particulier directement hebergé sur gittea -->Sécuriser le serveur de dev --- application/class/Application.php | 7 +- application/class/Browser.php | 93 +++++++++++++++++++ application/class/Controlleur.php | 47 +++++----- application/class/ControlleurAction.php | 33 +++++++ application/class/Dumper.php | 6 +- .../class/{Request.php => HttpMethod.php} | 8 +- .../{Response.php => HttpMethodRequete.php} | 83 ++++++++++++----- application/class/Implement/Action.php | 27 ++++++ application/class/Implement/HttpReponse.php | 16 +++- application/class/Implement/RestReponse.php | 21 ++++- application/class/Logger.php | 25 +++++ application/class/Url.php | 49 +++++++++- application/class/VueVide.php | 15 +++ application/config/define-constantes.php | 1 + application/include/actions/DefaultAction.php | 67 +++++++++++++ .../controlleurs/AcceuilHttpReponse.php | 16 ---- .../controlleurs/AccueilHttpReponse.php | 45 +++++++++ .../include/controlleurs/ErrorHttpReponse.php | 27 ++++++ application/include/controlleurs/accueil.php | 7 +- .../include/vues/view/accueil.blade.php | 5 + .../include/vues/view/action.blade.php | 1 + composer.json | 2 + 22 files changed, 523 insertions(+), 78 deletions(-) create mode 100644 application/class/Browser.php create mode 100644 application/class/ControlleurAction.php rename application/class/{Request.php => HttpMethod.php} (80%) rename application/class/{Response.php => HttpMethodRequete.php} (64%) create mode 100644 application/class/Implement/Action.php create mode 100644 application/class/Logger.php create mode 100644 application/class/VueVide.php create mode 100644 application/include/actions/DefaultAction.php delete mode 100644 application/include/controlleurs/AcceuilHttpReponse.php create mode 100644 application/include/controlleurs/AccueilHttpReponse.php create mode 100644 application/include/controlleurs/ErrorHttpReponse.php create mode 100644 application/include/vues/view/action.blade.php diff --git a/application/class/Application.php b/application/class/Application.php index f819afc..773b389 100644 --- a/application/class/Application.php +++ b/application/class/Application.php @@ -6,10 +6,15 @@ require APPLICATION_PATH . DIRECTORY_SEPARATOR . "parameters.php"; class Application { + public $http; public $url; + public $browser; + public function __construct(){ - $this->url = new Url(); + $this->http = new HttpMethod(); + $this->browser = new Browser(); + $this->url = new Url($this->http->method, $this->browser->isAppRequest()); } public function launch(){ diff --git a/application/class/Browser.php b/application/class/Browser.php new file mode 100644 index 0000000..b857c9d --- /dev/null +++ b/application/class/Browser.php @@ -0,0 +1,93 @@ +userAgent = $_SERVER['HTTP_USER_AGENT']; + $this->user = $this->get_browser_name(); + } + + protected function get_browser_name() + { + + // Make case insensitive. + $t = strtolower($this->userAgent); + + // If the string *starts* with the string, strpos returns 0 (i.e., FALSE). Do a ghetto hack and start with a space. + // "[strpos()] may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE." + // http://php.net/manual/en/function.strpos.php + $t = " " . $t; + + // Humans / Regular Users + if (strpos($t, 'opera') || strpos($t, 'opr/')) return 'Opera'; + elseif (strpos($t, 'edge')) return 'Edge'; + elseif (strpos($t, 'chrome')) return 'Chrome'; + elseif (strpos($t, 'safari')) return 'Safari'; + elseif (strpos($t, 'firefox')) return 'Firefox'; + elseif (strpos($t, 'msie') || strpos($t, 'trident/7')) return 'Internet Explorer'; + + // Application Users + elseif (strpos($t, 'curl')) return '[App] Curl'; + + // Search Engines + elseif (strpos($t, 'google')) return '[Bot] Googlebot'; + elseif (strpos($t, 'bing')) return '[Bot] Bingbot'; + elseif (strpos($t, 'slurp')) return '[Bot] Yahoo! Slurp'; + elseif (strpos($t, 'duckduckgo')) return '[Bot] DuckDuckBot'; + elseif (strpos($t, 'baidu')) return '[Bot] Baidu'; + elseif (strpos($t, 'yandex')) return '[Bot] Yandex'; + elseif (strpos($t, 'sogou')) return '[Bot] Sogou'; + elseif (strpos($t, 'exabot')) return '[Bot] Exabot'; + elseif (strpos($t, 'msn')) return '[Bot] MSN'; + + // Common Tools and Bots + elseif (strpos($t, 'mj12bot')) return '[Bot] Majestic'; + elseif (strpos($t, 'ahrefs')) return '[Bot] Ahrefs'; + elseif (strpos($t, 'semrush')) return '[Bot] SEMRush'; + elseif (strpos($t, 'rogerbot') || strpos($t, 'dotbot')) return '[Bot] Moz or OpenSiteExplorer'; + elseif (strpos($t, 'frog') || strpos($t, 'screaming')) return '[Bot] Screaming Frog'; + + // Miscellaneous + elseif (strpos($t, 'facebook')) return '[Bot] Facebook'; + elseif (strpos($t, 'pinterest')) return '[Bot] Pinterest'; + + // Check for strings commonly used in bot user agents + elseif (strpos($t, 'crawler') || strpos($t, 'api') || + strpos($t, 'spider') || strpos($t, 'http') || + strpos($t, 'bot') || strpos($t, 'archive') || + strpos($t, 'info') || strpos($t, 'data')) return '[Bot] Other'; + + return 'Other (Unknown)'; + } + + public function isBot() + { + if (preg_match('#Bot#', $this->user)) { + return true; + } else { + return false; + } + } + + // Alternative TO https://www.php.net/manual/fr/function.get-browser.php + // Function written and tested December, 2018 + + public function isAppRequest() + { + if (preg_match('#App#', $this->user)) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/application/class/Controlleur.php b/application/class/Controlleur.php index 884736f..27124f3 100644 --- a/application/class/Controlleur.php +++ b/application/class/Controlleur.php @@ -9,40 +9,19 @@ class Controlleur{ public function __construct($application){ - - $requete = new MVC\Classe\Request(); - - switch ($requete->method) { + switch ($application->http->method) { //cas des requètes PUT et DELETE case 'PUT': case 'DELETE': - require CONTROLLER_PATH . DIRECTORY_SEPARATOR . $application->url->page['name'] . 'HttpReponse.php'; - $reponseHttp = lcfirst($application->url->page['name']) . 'HttpReponse'; - $response = new $reponseHttp($application->url, $requete->getData()); - if ($requete->method == 'DELETE') { - $reponseHttp->delete(); - } else { - $reponseHttp->put(); - } - break; - //cas des requètes POST et GET case 'POST': case 'GET': - if (!file_exists(CONTROLLER_PATH . DIRECTORY_SEPARATOR . $application->url->page['name'] . '')) { + if ($application->browser->isAppRequest()) { require CONTROLLER_PATH . DIRECTORY_SEPARATOR . $application->url->page['name'] . 'HttpReponse.php'; - $reponseHttp = lcfirst($application->url->page['name']) . 'HttpReponse'; - $response = new $reponseHttp($application->url, $requete->getData()); - if ($requete->method == 'POST') { - $reponseHttp->post(); - } else { - $reponseHttp->get(); - } + $this->callHttpResponse($application); break; } - default: - if ($application->url->page['control']) { $url_params = $application->url->page['params']; require TRAITEMENT_PATH . DIRECTORY_SEPARATOR . $application->url->page['name'] . '.php'; @@ -54,5 +33,25 @@ class Controlleur{ } + + public function callHttpResponse($application) + { + $reponseHttp = "\\" . $application->url->page['name'] . 'HttpReponse'; + + //FIXME: + //Le passage par le contructeur dans le cas d'une instanciation dynamique ne fonctionne pas + //$reponse = new $reponseHttp($application->url, $application->http->getData()); + //il faut passer par une fonction personnelle permettant l'instanciation des variables + + $reponse = new $reponseHttp(); + $reponse->instanciate($application->url, $application->http->getData()); + $method = strtolower($application->http->method); + + $this->vue = new VueVide(); + ob_start(); + $reponse->$method(); + $this->vue->ecran = ob_get_clean(); + return; + } } diff --git a/application/class/ControlleurAction.php b/application/class/ControlleurAction.php new file mode 100644 index 0000000..8ccdc77 --- /dev/null +++ b/application/class/ControlleurAction.php @@ -0,0 +1,33 @@ +$method($data); + } else { + return $slot->default($data); + } + + } else { + /*HandleError*/ + } + + + } + + +} \ No newline at end of file diff --git a/application/class/Dumper.php b/application/class/Dumper.php index c266080..922a63b 100644 --- a/application/class/Dumper.php +++ b/application/class/Dumper.php @@ -7,7 +7,11 @@ class Dumper{ public static function dump($var){ echo "
";
-        print_r($var);
+        if (is_bool($var)) {
+            echo ($var) ? "true" : "false";
+        } else {
+            print_r($var);
+        }
         echo "
"; } diff --git a/application/class/Request.php b/application/class/HttpMethod.php similarity index 80% rename from application/class/Request.php rename to application/class/HttpMethod.php index 125f56e..5fa58ba 100644 --- a/application/class/Request.php +++ b/application/class/HttpMethod.php @@ -4,11 +4,11 @@ namespace MVC\Classe; -class Request +class HttpMethod { public $method; - public $data; + protected $data; public function __construct() { @@ -26,11 +26,11 @@ class Request case 'PUT': //$this->data['GET'] = ... //POST DATA except enctype="multipart/form-data" - $this->data['POST'] = json_decode(file_get_contents("php://input"), true); + $this->data = json_decode(file_get_contents("php://input"), true); case 'DELETE': //$this->data['GET'] = ... //POST DATA except enctype="multipart/form-data" - $this->data['POST'] = json_decode(file_get_contents("php://input"), true); + $this->data = json_decode(file_get_contents("php://input"), true); break; default: // Requête invalide diff --git a/application/class/Response.php b/application/class/HttpMethodRequete.php similarity index 64% rename from application/class/Response.php rename to application/class/HttpMethodRequete.php index 8eda6e4..f1ace43 100644 --- a/application/class/Response.php +++ b/application/class/HttpMethodRequete.php @@ -40,10 +40,13 @@ namespace MVC\Classe; * * @package MVC\Classe */ -class Response +class HttpMethodRequete { protected $url; protected $options; + protected $method; + protected $data; + protected $content; /** * Response multi-constructor. @@ -85,7 +88,7 @@ class Response public function __construct2($url, $method) { $this->url = $url; - + $this->method = $method; // utilisez 'http' même si vous envoyez la requête sur https:// ... $this->options = array( 'http' => array( @@ -102,28 +105,57 @@ class Response return $this; } - public function setGetParamsUrl($url, $params = array()) - { - $this->url = $url . (strpos($url, '?') ? '&' : '?') . http_build_query($params); - return $this; - } - - public function get($params = array()) - { - return $this->replaceContext('GET')->addContent($params)->send(); - } - + /* + public function setGetParamsUrl($url, $params = array()) + { + $this->url = $url . (strpos($url, '?') ? '&' : '?') . http_build_query($params); + return $this; + } + */ public function send() { - $context = stream_context_create($this->options); - $result = file_get_contents($this->url, false, $context); - if ($result === FALSE) { - /* Handle error */ +// /** Pour utiliser ce code il faut mettre la variable allow_furl_open a ON dans php.ini */ +// +// ob_start(); +// Dumper::dump($this->options); +// Dumper::dump($this->url); +// $text = ob_get_clean(); +// Logger::addLog('fopen',$text); +// +// $context = stream_context_create($this->options); +// $result = file_get_contents($this->url, false, $context); +// if ($result === FALSE) { +// /* Handle error */ +// return false; +// } else { +// return true; +// } + + $curl_cmd = "curl -i -X $this->method -H 'Content-Type: application/json' -d '$this->content' $this->url"; + + /** Pour utiliser ce code il faut utiliser la variable curl.cainfo dans php.ini */ + Logger::addLog('curl', $curl_cmd); + + $curl = curl_init($this->url); + //curl_setopt($curl, CURLOPT_HEADER, false); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->method); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($this->data)); + + $response = curl_exec($curl); + curl_close($curl); + + if (!$response) { return false; } else { return true; } + + /** Pour utiliser ce code il faut mettre la variable safe_mode a ON dans php.ini */ + //exec($curl_cmd); + + } /** @@ -131,23 +163,21 @@ class Response */ public function addContent($data) { - //Exemple - //$this->data = array('name' => 'PEC', 'description' => 'Pencil 2H', 'price' => '2.25', 'category' => '9'); - //'content' => http_build_query($data) - if (is_array($data)) { - $pContent = http_build_query($data); - } - $this->options['http']['content'] = $data; + $this->data = $data; + $this->content = json_encode($data); + $this->options['http']['content'] = http_build_query($data); return $this; } public function replaceContext($method) { + $this->method = $method; return $this->createContext($method); } public function createContext($method) { + $this->method = $method; // utilisez 'http' même si vous envoyez la requête sur https:// ... $this->options = array( 'http' => array( @@ -158,6 +188,11 @@ class Response return $this; } + public function get($params = array()) + { + return $this->replaceContext('GET')->addContent($params)->send(); + } + public function post($params = array()) { return $this->replaceContext('POST')->addContent($params)->send(); diff --git a/application/class/Implement/Action.php b/application/class/Implement/Action.php new file mode 100644 index 0000000..7c4ec95 --- /dev/null +++ b/application/class/Implement/Action.php @@ -0,0 +1,27 @@ +insert(VIEW_PATH . DIRECTORY_SEPARATOR . "system", 100); + $paths->insert(VIEW_PATH . DIRECTORY_SEPARATOR . "layout", 200); + $paths->insert(VIEW_PATH . DIRECTORY_SEPARATOR . "view", 300); + + $renderer = new \Windwalker\Renderer\BladeRenderer($paths, array('cache_path' => VIEW_PATH . DIRECTORY_SEPARATOR . "cache")); + + return $renderer->render($view, $data); + + //return ob_get_clean(); + + } +} \ No newline at end of file diff --git a/application/class/Implement/HttpReponse.php b/application/class/Implement/HttpReponse.php index fb7f5b2..653a20c 100644 --- a/application/class/Implement/HttpReponse.php +++ b/application/class/Implement/HttpReponse.php @@ -5,13 +5,20 @@ namespace MVC\Classe\Implement; use MVC\Classe\Implement\Contrat\HttpReponseInterface; -class HttpReponse implements HttpReponseInterface +class HttpReponse extends Action implements HttpReponseInterface { public $url; public $params; public $data; + /** + * Le passage par le contructeur dans le cas d'une instanciation dynamique ne fonctionne pas + * http://www.thedarksideofthewebblog.com/appel-dynamique-de-constructeur-en-php/ + * il faut passer par une fonction personnelle permettant l'instanciation des variables + * @param $url + * @param $requestData + */ public function __contruct($url, $requestData) { $this->url = $url; @@ -19,6 +26,13 @@ class HttpReponse implements HttpReponseInterface $this->data = $requestData; } + public function instanciate($url, $requestData) + { + $this->url = $url; + $this->params = $url->page['params']; + $this->data = $requestData; + } + public function put() { diff --git a/application/class/Implement/RestReponse.php b/application/class/Implement/RestReponse.php index e333def..b2a495c 100644 --- a/application/class/Implement/RestReponse.php +++ b/application/class/Implement/RestReponse.php @@ -3,19 +3,36 @@ namespace MVC\Classe\Implement; +use MVC\Classe\Dumper; +use MVC\Classe\Url; +use MVC\Classe\HttpMethod; use MVC\Classe\Implement\Contrat\RestReponseInterface; -class HttpReponse implements RestReponseInterface +class RestReponse implements RestReponseInterface { public $url; public $params; public $data; + /** + * Le passage par le contructeur dans le cas d'une instanciation dynamique ne fonctionne pas + * http://www.thedarksideofthewebblog.com/appel-dynamique-de-constructeur-en-php/ + * il faut passer par une fonction personnelle permettant l'instanciation des variables + * @param $url + * @param $requestData + */ public function __contruct($url, $requestData) { $this->url = $url; - $this->params = $url['params']; + $this->params = $url->page['params']; + $this->data = $requestData; + } + + public function instanciate($url, $requestData) + { + $this->url = $url; + $this->params = $url->page['params']; $this->data = $requestData; } diff --git a/application/class/Logger.php b/application/class/Logger.php new file mode 100644 index 0000000..6e75f67 --- /dev/null +++ b/application/class/Logger.php @@ -0,0 +1,25 @@ +user . ']' . PHP_EOL . $browser->userAgent . PHP_EOL . $what; + if (is_file($file)) { + file_put_contents($file, PHP_EOL . $what, FILE_APPEND | LOCK_EX); + } else { + file_put_contents($file, $what); + } + } + +} \ No newline at end of file diff --git a/application/class/Url.php b/application/class/Url.php index b250d4e..64fa2be 100644 --- a/application/class/Url.php +++ b/application/class/Url.php @@ -10,7 +10,8 @@ class Url public $registre; - public function __construct(){ + public function __construct($method, $appRequest) + { //on créé le registre des modules symfony $this->registre = new \MVC\Classe\ModularRegister(); @@ -77,11 +78,33 @@ class Url if($page['control']){ $pageFile = TRAITEMENT_PATH . DIRECTORY_SEPARATOR . $page['name'] . '.php'; }else { - $pageFile = CONTROLLERS_PATH . DIRECTORY_SEPARATOR . $page['name'] . '.php'; + //recherche du fichier controlleur correpondant HTTP1.1 ou HTTP1.0 + switch ($method) { + //cas des requètes HTTP1.1 + case 'PUT': + case 'DELETE': + case 'GET': + case 'POST': + if ($appRequest) { + $page['name'] = ucfirst($page['name']); + $pageFile = CONTROLLER_PATH . DIRECTORY_SEPARATOR . $page['name'] . 'HttpReponse.php'; + } else { + $page['name'] = lcfirst($page['name']); + $pageFile = CONTROLLERS_PATH . DIRECTORY_SEPARATOR . $page['name'] . '.php'; + if (!file_exists($pageFile)) { + $page['name'] = ucfirst($page['name']); + $pageFile = CONTROLLER_PATH . DIRECTORY_SEPARATOR . $page['name'] . 'HttpReponse.php'; + } + } + } } - if(!file_exists($pageFile)){ - $page['name'] = 'error'; + if (!file_exists($pageFile)) { + if ($appRequest) { + $page['name'] = 'error'; + } else { + $page['name'] = 'Error'; + } } $this->page = $page; @@ -115,4 +138,22 @@ class Url return '/' . 'control' . '/' . $page . $stringParams; } + static public function absolute_link_rewrite($isControlPatern, $page, $params = array()) + { + $url = $_SERVER['HTTP_HOST']; + if ($isControlPatern) { + $uri = self::controlLink_rewrite($page, $params); + } else { + $uri = self::link_rewrite_slashParam($page, $params); + } + if (isset($_SERVER['REQUEST_SCHEME'])) { + $scheme = $_SERVER['REQUEST_SCHEME']; + } else { + $scheme = 'http'; + } + + return ($scheme . "://" . $url . $uri); + + } + } diff --git a/application/class/VueVide.php b/application/class/VueVide.php new file mode 100644 index 0000000..29547b0 --- /dev/null +++ b/application/class/VueVide.php @@ -0,0 +1,15 @@ +render('action', array('var1' => $var1, 'var2' => $var2, 'var3' => $var3)); + } + + public function variableSlug($data) + { + + /**your action algorythm**/ + if (isset($data[0])) { + $var1 = $data[0]; + } else { + $var1 = 1; + } + if (isset($data[1])) { + $var2 = $data[1]; + } else { + $var2 = 2; + } + if (isset($data[2])) { + $var3 = $data[2]; + } else { + $var3 = 3; + } + + return $this->render('action', array('var1' => $var1, 'var2' => $var2, 'var3' => $var3)); + } + + public function makeHttp11($data) + { + + $data = array('myval' => 25); + + $request = new HttpMethodRequete(); + //$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->get($data); + //$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->post($data); + $request->setUrl(Url::absolute_link_rewrite(false, 'accueil', ['var10' => 'val10']))->put($data); + //$request->setUrl(Url::absolute_link_rewrite(false,'accueil',['var10'=>'val10']))->delete($data); + } +} diff --git a/application/include/controlleurs/AcceuilHttpReponse.php b/application/include/controlleurs/AcceuilHttpReponse.php deleted file mode 100644 index 4f4ac54..0000000 --- a/application/include/controlleurs/AcceuilHttpReponse.php +++ /dev/null @@ -1,16 +0,0 @@ -params . "
" . $this->data; - } - - public function delete() - { - - } -} \ No newline at end of file diff --git a/application/include/controlleurs/AccueilHttpReponse.php b/application/include/controlleurs/AccueilHttpReponse.php new file mode 100644 index 0000000..023f0df --- /dev/null +++ b/application/include/controlleurs/AccueilHttpReponse.php @@ -0,0 +1,45 @@ +params); + Dumper::dump($this->data); + $text = ob_get_clean(); + Logger::addLog('put', '____Hello Put____' . PHP_EOL . $text); + } + public function delete() + { + ob_start(); + Dumper::dump($this->params); + Dumper::dump($this->data); + $text = ob_get_clean(); + Logger::addLog('delete', '____Hello Delete:____' . PHP_EOL . $text); + + } + + public function get() + { + ob_start(); + Dumper::dump($this->params); + Dumper::dump($this->data); + $text = ob_get_clean(); + Logger::addLog('get', '____Hello GET____' . PHP_EOL . $text); + } + + public function post() + { + ob_start(); + Dumper::dump($this->params); + Dumper::dump($this->data); + $text = ob_get_clean(); + Logger::addLog('post', '____Hello POST____' . PHP_EOL . $text); + } +} \ No newline at end of file diff --git a/application/include/controlleurs/ErrorHttpReponse.php b/application/include/controlleurs/ErrorHttpReponse.php new file mode 100644 index 0000000..09a411e --- /dev/null +++ b/application/include/controlleurs/ErrorHttpReponse.php @@ -0,0 +1,27 @@ +'blade',"templating_b"=>'twig',"templating_c"=>'edge'); \ No newline at end of file + + +use MVC\Classe\Logger; + +$templateData = array("templating_a"=>'blade',"templating_b"=>'twig',"templating_c"=>'edge'); +Logger::addLog('ok', 'Hello world'); \ No newline at end of file diff --git a/application/include/vues/view/accueil.blade.php b/application/include/vues/view/accueil.blade.php index 05e3b37..6468eaa 100644 --- a/application/include/vues/view/accueil.blade.php +++ b/application/include/vues/view/accueil.blade.php @@ -13,5 +13,10 @@
{{$templating_a}}::{{$templating_b}}::{{$templating_c}} + {{\MVC\Classe\ControlleurAction::inserer('default',[])}} + {{\MVC\Classe\ControlleurAction::inserer('default.default',[4,5,6])}} + {{\MVC\Classe\ControlleurAction::inserer('default.variableSlug',['var1','var2','var3'])}} + {{\MVC\Classe\ControlleurAction::inserer('default.makeHttp11',[])}} + @endsection diff --git a/application/include/vues/view/action.blade.php b/application/include/vues/view/action.blade.php new file mode 100644 index 0000000..a9ffa17 --- /dev/null +++ b/application/include/vues/view/action.blade.php @@ -0,0 +1 @@ +{{$var1}}::{{$var2}}::{{$var3}} \ No newline at end of file diff --git a/composer.json b/composer.json index ce63a4a..061d263 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,8 @@ "require": { "php": "^7.1.3", + "ext-json": "*", + "ext-curl": "*", "windwalker/renderer": "3.*", "illuminate/view": "4.*", "hybridauth/hybridauth": "~3.0"