Skip to content

Commit dfab0d2

Browse files
author
ymejias
committed
Initial Code
1 parent dc3f720 commit dfab0d2

5 files changed

Lines changed: 376 additions & 0 deletions

File tree

MiniController/.htaccess

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<IfModule authz_core_module>
2+
Require all denied
3+
</IfModule>
4+
<IfModule !authz_core_module>
5+
Deny from all
6+
</IfModule>

MiniController/Controller.php

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
namespace MiniCtrl;
3+
if(!class_exists('MiniCtrl\\Controller')){
4+
/**
5+
* Clase de la que deben extender los controladores del sistema.
6+
* <b>NOTAS IMPORTANTES:</b><br>
7+
* Para ocultar el archivo PHP de la dirección URI, se recomienda usar la siguiente regla en el archivo <b>.htaccess</b>,<br>
8+
* en la misma carpeta del index.php que se quiere ocultar:
9+
* <code>
10+
* # Redirección para ocultar el archivo en la URL
11+
* RewriteEngine On
12+
* RewriteCond %{REQUEST_FILENAME} !-f
13+
* RewriteRule ^(.*)$ %{ENV:BASE}index.php/$0 [QSA,L]
14+
* </code>
15+
* Para bloquear el acceso a las controladores, se recomienda usar la siguiente regla en el archivo <b>.htaccess</b>,<br>
16+
* en la carpeta de los contorladores:
17+
* <code>
18+
* <IfModule authz_core_module>
19+
* Require all denied
20+
* </IfModule>
21+
* <IfModule !authz_core_module>
22+
* Deny from all
23+
* </IfModule>
24+
* </code>
25+
* Class Controller
26+
* @package MiniCtrl
27+
* @see Controller::_init()
28+
*/
29+
abstract class Controller{
30+
/**
31+
* Si se define este valor, siempre se ejecutará una misma función. El nombre de esta función se verá afectada por ({@see MiniController::$_enable_RESTful})
32+
* @var null|string
33+
*/
34+
protected static $_unique_fn=null;
35+
/**
36+
* Este es el nombre de la función que se ejecuta si el nombre no se puede obtener de la dirección
37+
* @var string
38+
*/
39+
protected static $_default_fn='index';
40+
/**
41+
* Si es <b>TRUE</b>, las funciones que se ejecutan a través de un request, deben tener el método del request como prefijo.<br>
42+
* Ejemplo, al llamar la URL "/miclase/mifn" por el método GET, se ejecutaría la función llamada "GET_mifn", así como el método PUT de esa misma URL ejecutaría la función "PUT_mifn".<br>
43+
* Si es <b>FALSE</b>, las funciones no tendrían el método como prefijo, por lo que, sin importar el método que se use, la función a ejecutar por la URL "/miclase/mifn" siempre sería "mifn"
44+
* @var bool Default: TRUE. Define si es un controlador RESTful o no.
45+
* @see MiniController::$method_accepted
46+
*/
47+
protected static $_enable_RESTful=true;
48+
/**
49+
* Si en el controlador está habilitado el RESTful ({@see MiniController::$_enable_RESTful}), esta es la lista de métodos aceptados en la API
50+
* @var array
51+
*/
52+
protected static $_method_accepted=array('GET','POST','PUT','DELETE');
53+
54+
/**
55+
* MiniController constructor.
56+
* @throws MiniCtrlError
57+
*/
58+
public function __construct(){
59+
if(Controller::_getInstance()){
60+
throw new MiniCtrlError('Ya existe un controlador en proceso');
61+
}
62+
}
63+
64+
private static $_instance=null;
65+
66+
/**
67+
* Devuelve en controlador que está actualmente en proceso
68+
* @return Controller|null
69+
*/
70+
final public static function &_getInstance(){
71+
return Controller::$_instance;
72+
}
73+
74+
/**
75+
* @param string $path
76+
* @param string $default_controller
77+
* @param string $c_suffix
78+
* @throws MiniCtrlError
79+
* @throws \ErrorException
80+
*/
81+
public static function _init($path, $default_controller='index', $c_suffix='.ctrl.php'){
82+
if(Controller::_getInstance()){
83+
throw new MiniCtrlError('Ya existe un controlador en proceso');
84+
}
85+
if(headers_sent($file,$line)){
86+
throw new \ErrorException('Los headers ya fueron enviados: '.$file.' ['.$line.']');
87+
}
88+
unset($file,$line);
89+
/* Los headers permiten acceso desde otro dominio (CORS) a nuestro REST API o desde un cliente remoto via HTTP
90+
* Removiendo las lineas header() limitamos el acceso a nuestro RESTfull API a el mismo dominio
91+
* Nótese los métodos permitidos en Access-Control-Allow-Methods. Esto nos permite limitar los métodos de consulta a nuestro RESTfull API
92+
* Mas información: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
93+
**/
94+
header("Access-Control-Allow-Origin: *");
95+
header('Access-Control-Allow-Credentials: true');
96+
//header('Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS');
97+
header("Access-Control-Allow-Headers: X-Requested-With");
98+
header('Content-Type: text/html; charset=utf-8');
99+
header('P3P: CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"');
100+
$c_path=realpath($path);
101+
if(!$c_path){
102+
throw new MiniCtrlError('Directorio de controladores no encontrado');
103+
}
104+
$c_path.='/';
105+
$PATH_INFO=trim(isset($_SERVER['PATH_INFO'])?substr($_SERVER['PATH_INFO'],1):'');
106+
if(!$PATH_INFO){
107+
$PATH_INFO=$default_controller;
108+
}
109+
if($PATH_INFO==''){
110+
throw (new MiniCtrlError('Nombre del controlador no recibido'))->typeNotFound();
111+
}
112+
$c_params=explode('/', $PATH_INFO);
113+
unset($PATH_INFO);
114+
$c_name_parts=array();
115+
do{
116+
$c_class=array_shift($c_params);
117+
$c_name_parts[]=$c_class;
118+
$c_dir=$c_path.implode('/', $c_name_parts);
119+
$c_file=$c_dir.$c_suffix;
120+
}while(count($c_params)>0 && is_dir($c_dir) && !is_file($c_file));
121+
define('MINICTRL_ENDPOINT',implode('/',$c_name_parts));
122+
define('MINICTRL_PARAMS',implode('/',$c_params));
123+
unset($c_name_parts);
124+
unset($c_dir);
125+
if(!is_file($c_file)){
126+
throw (new MiniCtrlError('Controlador no encontrado'))->typeNotFound();
127+
}
128+
include($c_file);
129+
unset($c_file);
130+
if(__NAMESPACE__){
131+
$c_class=__NAMESPACE__.'\\'.$c_class;
132+
}
133+
if(!class_exists($c_class)){
134+
throw (new MiniCtrlError('Controlador no válido'))->typeNotFound();
135+
}
136+
if(!in_array(Controller::class, class_parents($c_class))){
137+
throw (new MiniCtrlError('La clase encontrada no es un controlador'))->typeNotFound();
138+
}
139+
140+
// Validación de la función
141+
$c_vars=get_class_vars($c_class);
142+
if(is_array($c_vars['_method_accepted']) && count($c_vars['_method_accepted'])){
143+
header('Access-Control-Allow-Methods: '.implode(', ', $c_vars['_method_accepted']));
144+
if(!in_array(Request::getMethod(),$c_vars['_method_accepted'])){
145+
throw (new MiniCtrlError('Method no aceptado por el controlador'))->typeMethodNotAllowed();
146+
}
147+
}
148+
$c_fn=null;
149+
if($c_vars['_unique_fn']){
150+
$c_fn=$c_vars['_unique_fn'];
151+
}
152+
if(!$c_fn){
153+
$c_fn=array_shift($c_params);
154+
}
155+
if(!$c_fn && $c_vars['_default_fn']){
156+
$c_fn=$c_vars['_default_fn'];
157+
}
158+
if(substr($c_fn, 0,1)=='_'){
159+
throw (new MiniCtrlError('EndPoint de la API no encontrado'))->typeNotFound();
160+
}
161+
if($c_fn && $c_vars['_enable_RESTful'] && Request::getMethod()){
162+
$c_fn=Request::getMethod().'_'.$c_fn;
163+
}
164+
unset($c_vars);
165+
$fn_validator=null;
166+
try{
167+
$fn_validator=new \ReflectionMethod($c_class, $c_fn);
168+
}catch(\ReflectionException $e){
169+
}
170+
if(!$fn_validator){
171+
throw (new MiniCtrlError('EndPoint de la API no encontrado'))->typeNotFound();
172+
}
173+
if(!$fn_validator->isPublic()){
174+
throw (new MiniCtrlError('EndPoint de la API no encontrado'))->typeNotFound();
175+
}
176+
if($fn_validator->isStatic()){
177+
throw (new MiniCtrlError('EndPoint de la API no encontrado'))->typeNotFound();
178+
}
179+
unset($fn_validator);
180+
181+
// Ejecución de la función
182+
$result=null;
183+
Controller::$_instance=new $c_class();
184+
call_user_func_array(array(Controller::$_instance, $c_fn),$c_params);
185+
// Se destruye el controlador
186+
Controller::$_instance=null;
187+
}
188+
}
189+
}

MiniController/Exceptions.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
namespace MiniCtrl;
3+
if(!class_exists('MiniCtrl\\MiniCtrlError')){
4+
class MiniCtrlError extends \ErrorException{
5+
public $http_code=500;
6+
7+
function &http_code($http_code){
8+
if(is_int($http_code) && $http_code>0){
9+
$this->http_code=$http_code;
10+
}
11+
return $this;
12+
}
13+
14+
function &typeBadRequest(){
15+
return $this->http_code(400);
16+
}
17+
18+
19+
function &typeUnauthorized(){
20+
return $this->http_code(401);
21+
}
22+
23+
function &typeForbidden(){
24+
return $this->http_code(403);
25+
}
26+
27+
function &typeNotFound(){
28+
return $this->http_code(404);
29+
}
30+
31+
function &typeMethodNotAllowed(){
32+
return $this->http_code(405);
33+
}
34+
35+
function &typeConflict(){
36+
return $this->http_code(409);
37+
}
38+
}
39+
40+
}

MiniController/Request.php

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
namespace MiniCtrl;
3+
if(!class_exists('MiniCtrl\\Request')){
4+
/**
5+
* Provee las funciones básicas para la lectura de datos del Request
6+
* Class Request
7+
* @package MiniCtrl
8+
*/
9+
class Request{
10+
const CONTENTYPE_NONE='';
11+
const CONTENTYPE_PLAIN='text/plain';
12+
const CONTENTYPE_HTML='text/html';
13+
const CONTENTYPE_JSON='application/json';
14+
const CONTENTYPE_XML='application/xml';
15+
const CONTENTYPE_FORM_URLENCODED='application/x-www-form-urlencoded';
16+
const CONTENTYPE_FORM_DATA='multipart/form-data';
17+
18+
static final function isAjax(){
19+
return (self::getHeader('X-Requested-With')=='XMLHttpRequest');
20+
}
21+
22+
static final function getMethod(){
23+
return (isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'');
24+
}
25+
26+
/**
27+
* Se recomienda recibir datos por este medio solo si el método del Request es POST
28+
* @return bool
29+
*/
30+
static final function isMultipart_FormData(){
31+
$ct=self::getContentType(true);
32+
return ($ct[0]==self::CONTENTYPE_FORM_DATA);
33+
}
34+
35+
static final function getContentType($asArray=false){
36+
$ct=(isset($_SERVER['CONTENT_TYPE'])?$_SERVER['CONTENT_TYPE']:'');
37+
if($asArray){
38+
$ct=explode(';', $ct);
39+
$ct=array_map('trim', $ct);
40+
}
41+
return $ct;
42+
}
43+
44+
static final function getInput(){
45+
return file_get_contents('php://input');
46+
}
47+
48+
/**
49+
* @param array $content_types
50+
* @param bool $throw_required
51+
* @return bool|false|mixed|\SimpleXMLElement|string|null
52+
* @throws MiniCtrlError
53+
*/
54+
static final function getInputDecoded($content_types=array(), $throw_required=false){
55+
$ct=self::getContentType(true);
56+
if(count($content_types)>0 && !in_array($ct[0], $content_types)){
57+
if($throw_required){
58+
if(empty($ct[0])){
59+
throw (new MiniCtrlError('Content-Type no recibido'))->typeBadRequest();
60+
}
61+
else{
62+
throw (new MiniCtrlError('Content-Type no permitido: '.$ct[0]))->typeBadRequest();
63+
}
64+
}
65+
else{
66+
return false;
67+
}
68+
}
69+
$input_data=null;
70+
if($ct[0]==self::CONTENTYPE_NONE){
71+
return null;
72+
}
73+
elseif($ct[0]==self::CONTENTYPE_PLAIN || $ct[0]==self::CONTENTYPE_HTML){
74+
$input_data=self::getInput();
75+
}
76+
elseif($ct[0]==self::CONTENTYPE_JSON){
77+
$input_data=self::getInput_JSON();
78+
}
79+
elseif($ct[0]==self::CONTENTYPE_XML){
80+
$input_data=self::getInput_XML();
81+
}
82+
elseif($ct[0]==self::CONTENTYPE_FORM_DATA){
83+
$input_data=null;
84+
}
85+
elseif($ct[0]==self::CONTENTYPE_FORM_URLENCODED){
86+
$input_data=self::getInput_UrlEncoded();
87+
}
88+
if($input_data===null || $input_data===false){
89+
if($throw_required){
90+
throw (new MiniCtrlError('Content-Type fallo durante lectura'))->typeBadRequest();
91+
}
92+
}
93+
return $input_data;
94+
}
95+
96+
static final function getInput_JSON($assoc=false){
97+
return json_decode(self::getInput(), $assoc);
98+
}
99+
100+
static final function getInput_XML(){
101+
return simplexml_load_string(self::getInput());
102+
}
103+
104+
static final function getInput_UrlEncoded(){
105+
$result=null;
106+
parse_str(self::getInput(), $result);
107+
return $result;
108+
}
109+
110+
static final function getAllHeaders(){
111+
$headers=array();
112+
foreach($_SERVER AS $k=>$v){
113+
if(substr($k,0,5)=='HTTP_'){
114+
$k=mb_convert_case(str_replace('_','-',substr($k, 5)), MB_CASE_TITLE);
115+
$headers[$k]=$v;
116+
}
117+
}
118+
return $headers;
119+
}
120+
121+
/**
122+
* @param $name
123+
* @return mixed|null
124+
*/
125+
static final function getHeader($name){
126+
$index='HTTP_'.strtoupper(str_replace('-', '_', $name));
127+
if(isset($_SERVER[$index])){
128+
return $_SERVER[$index];
129+
}
130+
return null;
131+
}
132+
133+
static final function getIpCliente(){
134+
return $_SERVER['REMOTE_ADDR'];
135+
}
136+
}
137+
}

MiniController/loader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
require __DIR__.'/Exceptions.php';
3+
require __DIR__.'/Request.php';
4+
require __DIR__.'/Controller.php';

0 commit comments

Comments
 (0)