First release of domframework
git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@1207 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
99
auth.php
Normal file
99
auth.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
class auth
|
||||
{
|
||||
/** Display the authentication page
|
||||
The message is displayed to the user in case of error
|
||||
The url is the caller url to go back if authentication is correct */
|
||||
public function pageHTML ($message="", $url="")
|
||||
{
|
||||
$res = "";
|
||||
$res .= "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"";
|
||||
$res .= " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
|
||||
$res .= "<html>\n";
|
||||
$res .= "<head>\n";
|
||||
$res .= "<title>Title</title>\n";
|
||||
$res .= "<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'";
|
||||
$res .= " />\n";
|
||||
$res .= "<script src='public/js/jquery.min.js' type='text/javascript'>";
|
||||
$res .= "</script>\n";
|
||||
$res .= "<script type='text/javascript' src='public/js/bootstrap.js'>";
|
||||
$res .= "</script>\n";
|
||||
$res .= "<link type='text/css' rel='stylesheet' href='";
|
||||
$res .= "public/css/bootstrap.css'/>\n";
|
||||
$res .= " <style type='text/css'>\n";
|
||||
$res .= "body { padding-top: 40px; padding-bottom: 40px;";
|
||||
$res .= " background-color: #eee; }\n";
|
||||
$res .= ".form-signin { max-width: 330px;padding:15px;margin:0 auto;}\n";
|
||||
$res .= ".form-signin .form-signin-heading, .form-signin .checkbox {";
|
||||
$res .= " margin-bottom: 10px; }\n";
|
||||
$res .= ".form-signin .checkbox { font-weight: normal; }\n";
|
||||
$res .= ".form-signin .form-control {";
|
||||
$res .= "position: relative; font-size: 16px; height: auto;";
|
||||
$res .= "padding: 10px; -webkit-box-sizing: border-box;";
|
||||
$res .= "-moz-box-sizing: border-box; box-sizing: border-box; }\n";
|
||||
$res .= ".form-signin .form-control:focus { z-index: 2; }\n";
|
||||
$res .= ".form-signin input[type='text'] { margin-bottom: -1px;";
|
||||
$res .= "border-bottom-left-radius: 0; border-bottom-right-radius: 0; }\n";
|
||||
$res .= ".form-signin input[type='password'] {";
|
||||
$res .= "margin-bottom: 10px; border-top-left-radius: 0;";
|
||||
$res .= "border-top-right-radius: 0; }\n";
|
||||
$res .= " </style>\n";
|
||||
$res .= " </head>\n";
|
||||
$res .= " <body>\n";
|
||||
$res .= "<div class='container'>\n";
|
||||
$res .= " <form class='form-signin' role='form' method='post' ";
|
||||
$res .= "action='#'>\n";
|
||||
$res .= " <h2 class='form-signin-heading'>"._("Please sign in");
|
||||
$res .= "</h2>\n";
|
||||
$res .= " <input type='text' class='form-control' name='email' ";
|
||||
$res .= "placeholder='"._("Email address")."' required autofocus/>\n";
|
||||
$res .= " <input type='password' class='form-control' name='password' ";
|
||||
$res .= "placeholder='"._("Password")."' required/>\n";
|
||||
$res .= " <label class='checkbox'>";
|
||||
$res .= "<input type='checkbox' name='remember-me'/>"._("Remember me");
|
||||
$res .= "</label>\n";
|
||||
$res .= " <button class='btn btn-lg btn-primary btn-block' ";
|
||||
$res .= "type='submit'>"._("Sign in")."</button>\n";
|
||||
if ($message !== "")
|
||||
$res .= "<div class='alert alert-danger'>$message</div>";
|
||||
$res .= " </form>\n";
|
||||
$res .= "</div>\n";
|
||||
$res .= "</body>\n";
|
||||
$res .= "</html>\n";
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** Establish the connection to authentication server */
|
||||
public function connect ()
|
||||
{
|
||||
throw new Exception (_("No connect to authentication available"), 405);
|
||||
}
|
||||
|
||||
/** Check if the email and password are correct
|
||||
Return TRUE if the authentication is correct
|
||||
Return an exception if there is a problem */
|
||||
public function authentication ($email, $password)
|
||||
{
|
||||
throw new exception (_("No authentication available"), 405);
|
||||
}
|
||||
|
||||
/** Return all the parameters recorded for the authenticate user */
|
||||
public function getdetails ()
|
||||
{
|
||||
throw new exception (_("No getdetails available"), 405);
|
||||
}
|
||||
|
||||
/** Method to change the password */
|
||||
public function changepassword ($oldpassword, $newpassword)
|
||||
{
|
||||
throw new exception (_("No password change available"), 405);
|
||||
}
|
||||
|
||||
/** List all the users available in the database
|
||||
Return firstname, lastname, mail, with mail is an array */
|
||||
public function listusers ()
|
||||
{
|
||||
throw new exception (_("No List User available"), 405);
|
||||
}
|
||||
}
|
||||
125
authldap.php
Normal file
125
authldap.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/** User authentication against LDAP server */
|
||||
class authldap extends auth
|
||||
{
|
||||
/** LDAP server : can be ldaps://server.domain.tld if LDAPS */
|
||||
public $ldapserver="localhost";
|
||||
public $ldapport=389;
|
||||
public $ldaptimeout=5;
|
||||
/** LDAP authentication to search user */
|
||||
public $ldapauth = "";
|
||||
public $ldappwd = "";
|
||||
public $ldapbase = "";
|
||||
/** Filter used to search user */
|
||||
public $ldapfilter = "(mail=%s)";
|
||||
public $ldapfield = "mail";
|
||||
/** Filter used to find the available datas of an authenticated user */
|
||||
public $ldapfiltersearch = "(objectClass=inetOrgPerson)";
|
||||
|
||||
private $ldapconn = NULL;
|
||||
private $ldapdnuser = NULL;
|
||||
|
||||
function __construct ()
|
||||
{
|
||||
if (!function_exists ("ldap_connect"))
|
||||
throw new Exception ("LDAP support unavailable in PHP", 500);
|
||||
}
|
||||
|
||||
/** Establish a connection to a LDAP server
|
||||
$server can be "ldaps://ldap.domain:636"
|
||||
If $user is "", there is no authentication (anonymous mode) */
|
||||
public function connect ()
|
||||
{
|
||||
$this->ldapconn = ldap_connect ($this->ldapserver, $this->ldapport);
|
||||
if (!$this->ldapconn)
|
||||
throw new Exception ("Can't contact LDAP server", 500);
|
||||
|
||||
ldap_set_option ($this->ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
ldap_set_option($this->ldapconn, LDAP_OPT_TIMELIMIT, $this->ldaptimeout);
|
||||
$ldapbind = ldap_bind ($this->ldapconn, $this->ldapauth, $this->ldappwd);
|
||||
if (ldap_errno ($this->ldapconn) !== 0)
|
||||
throw new Exception ("Authentication error in pre-auth LDAP", 500);
|
||||
}
|
||||
|
||||
/** Try to authenticate the email/password of the user */
|
||||
public function authentication ($email, $password)
|
||||
{
|
||||
$filter = sprintf ($this->ldapfilter, $email, $email, $email, $email);
|
||||
$search = ldap_search ($this->ldapconn, $this->ldapbase, $filter,
|
||||
array ($this->ldapfield));
|
||||
if ($search === FALSE)
|
||||
throw new Exception ("Unable to search in LDAP", 500);
|
||||
$info = ldap_get_entries ($this->ldapconn, $search);
|
||||
if (!isset ($info["count"]) || $info["count"] !== 1 || !isset ($info[0]) ||
|
||||
!isset ($info[0]["dn"]))
|
||||
throw new Exception ("Unable to find the user : '$email'", 401);
|
||||
$dn = $info[0]["dn"];
|
||||
$ldapbind2 = @ldap_bind ($this->ldapconn, $dn, $password);
|
||||
if ($ldapbind2 !== TRUE)
|
||||
throw new Exception ("Bad password for '$email'", 401);
|
||||
$this->ldapdnuser = $dn;
|
||||
}
|
||||
|
||||
/** Return all the parameters recorded for the authenticate user */
|
||||
public function getdetails ()
|
||||
{
|
||||
if ($this->ldapdnuser === NULL)
|
||||
throw new Exception ("No user authenticated !", 401);
|
||||
$search = ldap_search ($this->ldapconn, $this->ldapdnuser,
|
||||
$this->ldapfiltersearch);
|
||||
if ($search === FALSE)
|
||||
throw new Exception ("Can not found the details for user", 401);
|
||||
$datas = ldap_get_entries ($this->ldapconn, $search);
|
||||
$res = array ();
|
||||
if (isset ($datas[0]))
|
||||
{
|
||||
$res = array ("lastname"=>$datas[0]["sn"][0],
|
||||
"firstname"=>$datas[0]["givenname"][0],
|
||||
"email"=>$datas[0]["mail"][0]);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** Method to change the password */
|
||||
public function changepassword ($oldpassword, $newpassword)
|
||||
{
|
||||
throw new Exception (_("The password can't be change for LDAP users"), 405);
|
||||
}
|
||||
|
||||
/** List all the users available in the database
|
||||
Return firstname, lastname, mail, with mail is an array */
|
||||
public function listusers ()
|
||||
{
|
||||
if ($this->ldapconn === NULL)
|
||||
throw new Exception ("No established LDAP connection", 500);
|
||||
$search = ldap_search ($this->ldapconn,$this->ldapbase,
|
||||
$this->ldapfiltersearch,
|
||||
array ("mail","sn","givenname"));
|
||||
if ($search === FALSE)
|
||||
throw new Exception ("Unable to search the users in LDAP", 500);
|
||||
$info = ldap_get_entries ($this->ldapconn, $search);
|
||||
$datas = array ();
|
||||
foreach ($info as $key=>$vals)
|
||||
{
|
||||
if ($key === "count") continue;
|
||||
if (isset ($vals["sn"][0]) && isset ($vals["givenname"][0]) &&
|
||||
isset ($vals["mail"]))
|
||||
{
|
||||
$datas[$key] = array ("lastname"=>$vals["sn"][0],
|
||||
"firstname"=>$vals["givenname"][0],
|
||||
"email"=>$vals["mail"][0]);
|
||||
}
|
||||
|
||||
unset ($datas[$key]["mail"]["count"]);
|
||||
}
|
||||
|
||||
return $datas;
|
||||
}
|
||||
|
||||
function __destruct ()
|
||||
{
|
||||
if (isset ($this->ldapconn))
|
||||
ldap_close ($this->ldapconn);
|
||||
}
|
||||
}
|
||||
64
authorization.php
Normal file
64
authorization.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/** All the needed functions to authorize or deny access to an authenticated
|
||||
user */
|
||||
class authorization
|
||||
{
|
||||
private $separator = "/";
|
||||
|
||||
/** Establish a connexion to the authorization database */
|
||||
public function connect ()
|
||||
{
|
||||
}
|
||||
|
||||
/** Return if the user right is NONE, READ, WRITE, EXECUTE
|
||||
if the object doesn't exists, or is not readable, throw an exception */
|
||||
public function validate ($object)
|
||||
{
|
||||
}
|
||||
|
||||
/** Add a new object, with owner and group, and mode bits */
|
||||
public function add ($object, $owner, $group, $modbits)
|
||||
{
|
||||
}
|
||||
|
||||
/** Remove the informations about an object */
|
||||
public function drop ($object)
|
||||
{
|
||||
}
|
||||
|
||||
/** Change the owner of an object
|
||||
Need to be the root administrator */
|
||||
public function chown ($object, $owner)
|
||||
{
|
||||
}
|
||||
|
||||
/** Change the group of an object
|
||||
Need to be the owner of the object or the root administrator */
|
||||
public function chgrp ($object, $group)
|
||||
{
|
||||
}
|
||||
|
||||
/** Change mode bits for an object
|
||||
Need to be the owner of the object or the root administrator */
|
||||
public function chmod ($object, $mod)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the mode bits for an object if all his parents are readable for
|
||||
the user */
|
||||
public function lsmod ($object)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the owner for an object if all his parents are readable for
|
||||
the user */
|
||||
public function lsown ($object)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the owner for an object if all his parents are readable for
|
||||
the user */
|
||||
public function lsgrp ($object)
|
||||
{
|
||||
}
|
||||
}
|
||||
41
authparams.php
Normal file
41
authparams.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/** Takes the email and the password of the user */
|
||||
class authparams
|
||||
{
|
||||
/** Get informations from $POST variables */
|
||||
public function post()
|
||||
{
|
||||
if (!isset ($_POST["email"]) || !isset ($_POST["password"]))
|
||||
throw new Exception ("No POST provided", 401);
|
||||
return array ("email"=>$_POST["email"], "password"=>$_POST["password"]);
|
||||
}
|
||||
|
||||
/** Get informations from previous recorded session */
|
||||
public function session()
|
||||
{
|
||||
if (!isset ($_SESSION))
|
||||
throw new Exception ("No session previously opened", 401);
|
||||
if (!isset ($_SESSION["auth"]["email"]) ||
|
||||
!isset ($_SESSION["auth"]["password"]))
|
||||
throw new Exception ("No previous email in session", 401);
|
||||
return array ("email"=>$_SESSION["auth"]["email"],
|
||||
"password"=>$_SESSION["auth"]["email"]);
|
||||
}
|
||||
|
||||
/** Get informations from a HTTP authentication */
|
||||
public function http()
|
||||
{
|
||||
$realm = _("Restricted access");
|
||||
if (!isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
header("WWW-Authenticate: Basic realm=\"$realm\"");
|
||||
header("HTTP/1.0 401 Unauthorized");
|
||||
die ($realm);
|
||||
}
|
||||
else
|
||||
{
|
||||
return array ("email"=>$_SERVER["PHP_AUTH_USER"],
|
||||
"password"=>$_SERVER["PHP_AUTH_PW"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
authsession.php
Normal file
41
authsession.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/** User authentication against SESSION */
|
||||
class authsession extends auth
|
||||
{
|
||||
function __construct ()
|
||||
{
|
||||
if (!isset ($_SESSION))
|
||||
throw new Exception ("No session previously opened", 401);
|
||||
}
|
||||
|
||||
/** No connection to session */
|
||||
public function connect ()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/** Try to authenticate the email/password of the user */
|
||||
public function authentication ($email, $password)
|
||||
{
|
||||
if (!isset ($_SESSION["auth"]["email"]) ||
|
||||
!isset ($_SESSION["auth"]["password"]))
|
||||
throw new Exception ("No previous email in session", 401);
|
||||
if ($_SESSION["auth"]["email"] !== $email)
|
||||
throw new Exception ("Unable to authenticate user '$email'", 401);
|
||||
if ($_SESSION["auth"]["password"] !== $password)
|
||||
throw new Exception ("Bad password for '$email'", 401);
|
||||
}
|
||||
|
||||
public function getdetails ()
|
||||
{
|
||||
return array ("lastname"=>$_SESSION["auth"]["lastname"],
|
||||
"firstname"=>$_SESSION["auth"]["firstname"],
|
||||
"email"=>$_SESSION["auth"]["email"]);
|
||||
}
|
||||
|
||||
public function changepassword ($oldpassword, $newpassword)
|
||||
{
|
||||
throw new Exception (_("The password can't be change for SESSION users"),
|
||||
405);
|
||||
}
|
||||
}
|
||||
224
dblayer.php
Normal file
224
dblayer.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
// dblayer.php
|
||||
|
||||
/* Documentation :
|
||||
The dbLayer provide an abstraction layer on PDO to be easier on all the CRUD
|
||||
(Create, Read, Update, Delete) operations, accross all the databases engines.
|
||||
To use it, extends in your code this class, and define the attributes :
|
||||
- protected $table : name of the table you want to use
|
||||
- protected $fields : description of all the fields in the database like :
|
||||
protected $fields = array (
|
||||
"id"=>array ("integer", "not null", "autoincrement"),
|
||||
"zone"=>array ("varchar", "255", "not null"),
|
||||
"viewname"=>array ("varchar", "255"),
|
||||
"viewclients"=>array ("varchar", "255"),
|
||||
"comment"=>array ("varchar", "1024"),
|
||||
"opendate"=>array ("datetime", "not null"),
|
||||
"closedate"=>array ("datetime"),
|
||||
);
|
||||
- protected $primary = "id" ; the primary key of the table (in text). Actually
|
||||
the dbLayer abstraction don't supports primary key on multiples columns
|
||||
|
||||
Optionnaly, you can add the
|
||||
- protected $debug = TRUE : enable the debug on screen (NOT FOR PROD !!)
|
||||
*/
|
||||
|
||||
/** Permit abstraction on the differents SQL databases available */
|
||||
class dblayer extends PDO
|
||||
{
|
||||
protected $fields = array ();
|
||||
protected $primary = null;
|
||||
protected $db = null;
|
||||
public $debug = FALSE;
|
||||
/** Return all the tables available in the database */
|
||||
function listTables ()
|
||||
{
|
||||
$driver = $this->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
$rc = @include_once ("dbLayer".ucfirst ($driver).".php");
|
||||
if ($rc === FALSE)
|
||||
throw new Exception ("dbLayer driver $driver not available");
|
||||
}
|
||||
|
||||
// TODO !!
|
||||
/** Create Table creation from $this->fields with engine abstraction
|
||||
Example in sqlite3 id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
in MySQL id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, */
|
||||
|
||||
// TODO !!
|
||||
/** Create automatic creation of $fields from .schema of sqlite3/
|
||||
show create table `NomTable`; for MySQL*/
|
||||
|
||||
/** Connection to the database engine
|
||||
See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format */
|
||||
function __construct ($dsn, $username=null, $password=null,
|
||||
$driver_options=null)
|
||||
{
|
||||
$this->db = new PDO ($dsn, $username, $password, $driver_options);
|
||||
$this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
/** Create a new entry in the table. Datas must be an indexed array */
|
||||
function create ($datas)
|
||||
{
|
||||
if ($this->db === null)
|
||||
throw new Exception ("Database not connected");
|
||||
$datasOK = array ();
|
||||
// Check for missing parameters
|
||||
foreach ($this->fields as $key=>$params)
|
||||
{
|
||||
if (in_array ("autoincrement", $params))
|
||||
$datas[$key] = null;
|
||||
if (in_array ("not null", $params) && !array_key_exists ($key, $datas))
|
||||
throw new Exception ("Mandatory field '$key' not provided");
|
||||
// TODO : Check for type inconsistancies before create $datasOK
|
||||
if (array_key_exists ($key, $datas))
|
||||
$datasOK[$key] = $datas[$key];
|
||||
}
|
||||
|
||||
$req = "INSERT INTO `".$this->table."` ";
|
||||
$req .= "(".implode (",", array_keys ($datasOK)).")";
|
||||
$req .= " VALUES ";
|
||||
$req .= "(:".implode (",:", array_keys ($datasOK)).")";
|
||||
if ($this->debug) echo "DEBUG : $req\n";
|
||||
$st = $this->db->prepare ($req);
|
||||
foreach ($datasOK as $key=>$val)
|
||||
{
|
||||
if ($this->debug) echo "DEBUG BIND : $key->".var_export ($val, TRUE)."\n";
|
||||
if ($val === null)
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_NULL);
|
||||
elseif ($this->fields[$key][0] === "integer")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_INT);
|
||||
elseif ($this->fields[$key][0] === "varchar")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_STR);
|
||||
elseif ($this->fields[$key][0] === "datetime")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_STR);
|
||||
else
|
||||
throw new Exception ("TO BE DEVELOPPED : ".$this->fields[$key][0]);
|
||||
}
|
||||
|
||||
$st->execute ();
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/** Read all the table or only one line defined by the primary key */
|
||||
function read ($selectkey=null)
|
||||
{
|
||||
if ($this->db === null)
|
||||
throw new Exception ("Database not connected");
|
||||
$req = "SELECT ";
|
||||
$req .= implode (",", array_keys ($this->fields));
|
||||
$req .= " FROM `".$this->table."`";
|
||||
if ($selectkey !== NULL)
|
||||
$req .= " WHERE $this->primary=:primary";
|
||||
|
||||
if ($this->debug) echo "DEBUG : $req\n";
|
||||
$st = $this->db->prepare ($req);
|
||||
if ($selectkey !== NULL)
|
||||
{
|
||||
if ($this->debug) echo "DEBUG BIND : primary->".
|
||||
var_export ($selectkey, TRUE)."\n";
|
||||
$st->bindValue (":primary", $selectkey);
|
||||
}
|
||||
$st->execute ();
|
||||
$res = array ();
|
||||
while ($d = $st->fetch (PDO::FETCH_ASSOC))
|
||||
$res[] = $d;
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** Update the key tuple with the provided datas */
|
||||
function update ($updatekey, $datas)
|
||||
{
|
||||
if ($this->db === null)
|
||||
throw new Exception ("Database not connected");
|
||||
$datasOK = array ();
|
||||
// Check for missing parameters
|
||||
foreach ($this->fields as $key=>$params)
|
||||
{
|
||||
// TODO : Check for type inconsistancies before create $datasOK
|
||||
if (array_key_exists ($key, $datas))
|
||||
$datasOK[$key] = $datas[$key];
|
||||
}
|
||||
|
||||
$req = "UPDATE `".$this->table."` SET ";
|
||||
$i = 0;
|
||||
foreach ($datasOK as $key=>$val)
|
||||
{
|
||||
if ($i>0) $req .= ",";
|
||||
$req .= "$key=:$key";
|
||||
$i++;
|
||||
}
|
||||
$req .= " WHERE $this->primary=:primary";
|
||||
if ($this->debug) echo "DEBUG : $req\n";
|
||||
$st = $this->db->prepare ($req);
|
||||
if ($this->debug) echo "DEBUG BIND : primary->".
|
||||
var_export ($updatekey, TRUE)."\n";
|
||||
$st->bindValue (":primary", $updatekey);
|
||||
foreach ($datasOK as $key=>$val)
|
||||
{
|
||||
if ($this->debug) echo "DEBUG BIND : $key->".var_export ($val, TRUE)."\n";
|
||||
if ($val === null)
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_NULL);
|
||||
elseif ($this->fields[$key][0] === "integer")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_INT);
|
||||
elseif ($this->fields[$key][0] === "varchar")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_STR);
|
||||
elseif ($this->fields[$key][0] === "datetime")
|
||||
$st->bindValue (":$key", $val, PDO::PARAM_STR);
|
||||
else
|
||||
throw new Exception ("TO BE DEVELOPPED : ".$this->fields[$key][0]);
|
||||
}
|
||||
|
||||
$st->execute ();
|
||||
}
|
||||
|
||||
/** Delete a tuple identified by its primary key */
|
||||
function delete ($deletekey)
|
||||
{
|
||||
if ($this->db === null)
|
||||
throw new Exception ("Database not connected");
|
||||
$req = "DELETE FROM `".$this->table."` ";
|
||||
$req .= "WHERE $this->primary = :primary";
|
||||
$st = $this->db->prepare ($req);
|
||||
if ($this->debug) echo "DEBUG : $req\n";
|
||||
if ($this->debug) echo "DEBUG BIND : primary->".
|
||||
var_export ($deletekey, TRUE)."\n";
|
||||
$st->bindValue (":primary", $deletekey);
|
||||
$st->execute ();
|
||||
}
|
||||
}
|
||||
|
||||
/** POC :
|
||||
error_reporting (E_ALL);
|
||||
require_once ("domframework/dbLayer.php");
|
||||
class zone extends dbLayer
|
||||
{
|
||||
// The database must be initialized with
|
||||
// CREATE TABLE `dns_zones` (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
// zone VARCHAR(255) NOT NULL,
|
||||
// viewname VARCHAR(255),
|
||||
// viewclients VARCHAR(255),
|
||||
// comment VARCHAR(1024),
|
||||
// opendate DATETIME NOT NULL,
|
||||
// closedate DATETIME,
|
||||
// UNIQUE (zone,viewname));
|
||||
protected $table = "dns_zones";
|
||||
protected $fields = array (
|
||||
"id"=>array ("integer", "not null", "autoincrement"),
|
||||
"zone"=>array ("varchar", "255", "not null"),
|
||||
"viewname"=>array ("varchar", "255"),
|
||||
"viewclients"=>array ("varchar", "255"),
|
||||
"comment"=>array ("varchar", "1024"),
|
||||
"opendate"=>array ("datetime", "not null"),
|
||||
"closedate"=>array ("datetime"),
|
||||
);
|
||||
protected $primary = "id";
|
||||
}
|
||||
|
||||
ini_set ("date.timezone", "Europe/Paris");
|
||||
$zone = new zone ("sqlite:datas/database.db");
|
||||
$last = $zone->create (array ("zone"=>"testZone", "opendate"=>date("Y-m-d H:i:s")));
|
||||
//print_r ($zone->read ());
|
||||
$zone->update (2040, array ("zone"=>"testZone2"));
|
||||
print_r ($zone->delete ($last));
|
||||
|
||||
15
docs/TODO
Normal file
15
docs/TODO
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
TODO
|
||||
----
|
||||
- Check if the access to model is well closed
|
||||
- Create the html output with views support and layout
|
||||
- Do authorization model and restict access to the pages
|
||||
- Automatic routing to do (to be confirmed by a attribute (off by default)) :
|
||||
call controller by default, with class/method/param1/param2...
|
||||
- Automatic typing of document .txt=>outputtxt, .xml=>outputxml... off by
|
||||
default
|
||||
- Routing : check if "URL === ROUTE (No variables)" part is needed (can be
|
||||
catched by regex too)
|
||||
- Routing : add REST functionnality (to pass the type in the header and provide
|
||||
the result with HTTP error codes)
|
||||
|
||||
185
docs/USAGE
Normal file
185
docs/USAGE
Normal file
@@ -0,0 +1,185 @@
|
||||
DOMFRAMEWORK DOCUMENTATION
|
||||
==========================
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
The DomFramework is a PHP framework used in CLI or Web sites.
|
||||
It actually supports some mandatory functionnalities of a framework : routing,
|
||||
url beautifier, authentication, outputs multiple formats (like html, csvn, json,
|
||||
xml...).
|
||||
|
||||
2. Starting a new project
|
||||
-------------------------
|
||||
To start a new project with this framework, put the domframework dir in a folder
|
||||
defined in "include_path" constant of PHP.ini. Usually, there is a . in it, so
|
||||
you can add the framework directely in the base of a project if you want, or in
|
||||
a global system directory.
|
||||
|
||||
You can start a new project. The following text will be project in
|
||||
/var/www/project.
|
||||
You must add a .htaccess file with :
|
||||
Options -Indexes
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
# if your app is in a subfolder
|
||||
# RewriteBase /my_app/
|
||||
# test string is a valid files
|
||||
RewriteCond %{SCRIPT_FILENAME} !-f
|
||||
# test string is a valid directory
|
||||
RewriteCond %{SCRIPT_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?uri=/$1 [NC,L,QSA]
|
||||
# with QSA flag (query string append),
|
||||
# forces the rewrite engine to append a query string part of the
|
||||
# substitution string to the existing string, instead of replacing it.
|
||||
</IfModule>
|
||||
|
||||
# Allow to see a /.html file without having a Forbidden due to Apache conf
|
||||
<FilesMatch "^\.html">
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
</FilesMatch>
|
||||
|
||||
Then start a index.php in the same directory. That's it, the project is started.
|
||||
|
||||
3. Creating the folder structure
|
||||
--------------------------------
|
||||
DomFramework waits for at least one special folder : controllers.
|
||||
In this folder, you will create the controllers for your application, with the
|
||||
name "controller_<CLASS>.php". This file will contain the class <CLASS>.
|
||||
|
||||
DomFramework use a folder named "views". It will contains the differents HTML
|
||||
views rendered on the user browser.
|
||||
|
||||
You can create a folder "models" to respect the MVC model. DomFramework forbid
|
||||
access to this directory directely.
|
||||
|
||||
4. Controllers
|
||||
--------------
|
||||
A controller is a PHP class which will do something. It shouldn't access to
|
||||
databases directely (as it is the model part). It can provide methods to access
|
||||
to database model.
|
||||
|
||||
The methods in the controller will be the only access from the framework.
|
||||
The controllers shouldn't write directly to stdout. They should return the
|
||||
result of their work to the caller.
|
||||
|
||||
Example :
|
||||
<?php
|
||||
class blog
|
||||
{
|
||||
public function get ($articleid = FALSE)
|
||||
{
|
||||
if ($articleid === "5" || $articleid === FALSE)
|
||||
return array ("5"=>"Article very important");
|
||||
throw new Exception (_("Article not found"), 404);
|
||||
}
|
||||
}
|
||||
|
||||
The errors can be returned with an Exception.
|
||||
|
||||
5. Routing and beautifier URL
|
||||
-----------------------------
|
||||
In a Web site, the philosophy is to have a URL for each action.
|
||||
You can do a beautiful URL with DomFramework http://localhost/project/blog/page
|
||||
you will allow the class "blog" to be launch with the parameter "page".
|
||||
|
||||
This is the routing. You need to add the routes in your index.php file with :
|
||||
require_once ("domframework/route.php");
|
||||
$route = new route ();
|
||||
$res = $route->routingCollection (array (
|
||||
"blog/{page}" => array ("class", "method", "{page}"),
|
||||
));
|
||||
|
||||
The routes are read sequentially. The first which match the class/method wins.
|
||||
It start a new instance of "class" and apply the method "method" with the
|
||||
parameters need to launch the action. The result of the action is returned to
|
||||
the main script to be outputed.
|
||||
The parameters are puts between {}. You must put the parameters in the right
|
||||
order needed by your method.
|
||||
|
||||
There is a special action named "redirect" in the "route" class. It provide the
|
||||
capability to re-route the Web browser to another page. Put in action :
|
||||
array ("route", "redirect", "nextPage/", FALSE),
|
||||
If the URL match the requested search, the Web browser will load immediately a
|
||||
new page named "nextPage/". The FALSE will be change in case of modular
|
||||
application (see the MODULAR APPLICATION chapter)
|
||||
|
||||
6. Output : the renderer
|
||||
------------------------
|
||||
When a controller has finished his job, the result returned to the main class of
|
||||
routing to be displayed. It can be displayed in a lot of formats : HTML, csv,
|
||||
json, xml.
|
||||
The allowed extensions are puts in the routingCollection in the position you
|
||||
want by adding them between parenthesis. Example :
|
||||
require_once ("domframework/route.php");
|
||||
$route = new route ();
|
||||
$res = $route->routingCollection (array (
|
||||
"{page}" => array ("class", "method", "{parameter}"),
|
||||
));
|
||||
print_r ($res);
|
||||
|
||||
It can be used by the renderer system (generally run by controller) :
|
||||
$renderer = new renderer ();
|
||||
$renderer->result = $res;
|
||||
$renderer->output = "html";
|
||||
$renderer->run ();
|
||||
|
||||
In controllers, the renderer can be called too. There is a flash method. The
|
||||
flash messages will be displayed on next page, in case of HTML page. In CLI, it
|
||||
is immediately displayed.
|
||||
|
||||
7. Layout
|
||||
---------
|
||||
In HTML, there is a presentation layer, named layout. The layout is common to
|
||||
all the site pages.
|
||||
All the pages are coded in "views" directory. The renderer call them before
|
||||
displaying the result.
|
||||
By default, the layout is a page named "layout.html", in the views directory.
|
||||
It contains the HTML page with some special parts : the tokens. Tokens are
|
||||
written like {content} or {title}. The renderer replace them by the result of
|
||||
replacement attibute.
|
||||
|
||||
8. Debug
|
||||
--------
|
||||
When creating a routingCollection, a lot of errors can be done. There is in
|
||||
DomFramework the capability to debug the application. You can activate the debug
|
||||
by putting 1 in the associated method. Example :
|
||||
$route = new route ();
|
||||
$route->debug = 1;
|
||||
|
||||
The screen will display the actions to help the debug :
|
||||
==== DEBUG : ROUTING START ====
|
||||
blog/5 ?? blog/{page} => blog->get({page}) : FOUND : URL === REGEX : Call blog()->get(5)
|
||||
==== DEBUG : ROUTING END ====
|
||||
|
||||
XX. CLI usage
|
||||
-------------
|
||||
The DomFramework is designed to be used in console line too.
|
||||
TBC !!
|
||||
|
||||
XX. Modular application
|
||||
-----------------------
|
||||
THe DomFramework can be used on modular applications. Each application (or
|
||||
module) will have a complete autonomy. The structure will be :
|
||||
/Project/
|
||||
/Project/module1/
|
||||
/Project/module2/
|
||||
[/Project/domframework/ is optional]
|
||||
/ ... /
|
||||
|
||||
Only one instance of DomFramework is needed. It can be put outside the project.
|
||||
In this mode, the routing must be adapted to use the modular mode :
|
||||
$route = new route ();
|
||||
$route->module = TRUE;
|
||||
If you use the route redirect method, think to change the last parameter to
|
||||
TRUE.
|
||||
|
||||
Each module will have its controllers/models/views folders.
|
||||
|
||||
XX. Plugin developpment
|
||||
-----------------------
|
||||
DomeFramework is based on plugins. You can develop a new plugin to an other
|
||||
output type (like a graph...), a new authentication method, etc.
|
||||
|
||||
Usually, this is done by extending the main class and adding the specificity of
|
||||
the new methods.
|
||||
21
examples/blog/.htaccess
Normal file
21
examples/blog/.htaccess
Normal file
@@ -0,0 +1,21 @@
|
||||
Options -Indexes
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
# if your app is in a subfolder
|
||||
# RewriteBase /my_app/
|
||||
# test string is a valid files
|
||||
RewriteCond %{SCRIPT_FILENAME} !-f
|
||||
# test string is a valid directory
|
||||
RewriteCond %{SCRIPT_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?uri=/$1 [NC,L,QSA]
|
||||
# with QSA flag (query string append),
|
||||
# forces the rewrite engine to append a query string part of the
|
||||
# substitution string to the existing string, instead of replacing it.
|
||||
</IfModule>
|
||||
|
||||
# Allow to see a /.html file without having a Forbidden due to Apache conf
|
||||
<FilesMatch "^\.html">
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
</FilesMatch>
|
||||
|
||||
127
examples/blog/controllers/controller_blog.php
Normal file
127
examples/blog/controllers/controller_blog.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
error_reporting (E_ALL);
|
||||
class blog
|
||||
{
|
||||
/** Return an article */
|
||||
private function get ($articleid = FALSE)
|
||||
{
|
||||
require_once ("models/model_file.php");
|
||||
$data = new model_file();
|
||||
return $data->get ($articleid);
|
||||
}
|
||||
|
||||
/** Return an article in text */
|
||||
public function getTxt ($articleid = FALSE)
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->get ($articleid);
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "txt";
|
||||
$renderer->result = $res;
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e) {};
|
||||
}
|
||||
|
||||
/** Return an article in xml */
|
||||
public function getXml ($articleid = FALSE)
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->get ($articleid);
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "xml";
|
||||
$renderer->result = $res;
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e) {};
|
||||
}
|
||||
|
||||
/** Return an article in csv */
|
||||
public function getCsv ($articleid = FALSE)
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->get ($articleid);
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "csv";
|
||||
$renderer->result = $res;
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e) {};
|
||||
}
|
||||
|
||||
/** Return an article in json */
|
||||
public function getJson ($articleid = FALSE)
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->get ($articleid);
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "json";
|
||||
$renderer->result = $res;
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e) {};
|
||||
}
|
||||
|
||||
/** Return an article in HTML */
|
||||
public function getHtml ($articleid = FALSE)
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->get ($articleid);
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "html";
|
||||
$renderer->result = $res;
|
||||
$renderer->viewClass = "view_blog";
|
||||
$renderer->viewMethod = "get";
|
||||
$renderer->layout = "layout";
|
||||
// $renderer->title = "Super Title";
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// TODO !!
|
||||
echo "404 with ".$e->getMessage();
|
||||
exit;
|
||||
};
|
||||
}
|
||||
|
||||
/** Return the listing of all the recorded articles */
|
||||
public function listing ()
|
||||
{
|
||||
require_once ("models/model_file.php");
|
||||
$data = new model_file();
|
||||
return $data->listing ();
|
||||
}
|
||||
|
||||
/** Return the listing of all the recorded articles in HTML */
|
||||
public function listingHtml ()
|
||||
{
|
||||
try
|
||||
{
|
||||
$res = $this->listing ();
|
||||
$renderer = new renderer ();
|
||||
$renderer->output = "html";
|
||||
$renderer->result = $res;
|
||||
$renderer->viewClass = "view_blog";
|
||||
$renderer->viewMethod = "listing";
|
||||
$renderer->layout = "layout";
|
||||
$renderer->run ();
|
||||
exit;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// TODO !!
|
||||
echo "404 with ".$e->getMessage();
|
||||
exit;
|
||||
};
|
||||
}
|
||||
}
|
||||
1
examples/blog/datas/.htaccess
Normal file
1
examples/blog/datas/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
2
examples/blog/datas/5
Normal file
2
examples/blog/datas/5
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Article 5</h1>
|
||||
<p>Lorem ipsum</p>
|
||||
16
examples/blog/index.php
Normal file
16
examples/blog/index.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
require_once ("domframework/route.php");
|
||||
require_once ("domframework/renderer.php");
|
||||
$route = new route ();
|
||||
$route->debug =0 ;
|
||||
$res = $route->routingCollection (array (
|
||||
//"" => array ("route", "redirect", "/1", FALSE),
|
||||
"" => array ("blog", "listingHtml"),
|
||||
"{page}.xml" => array ("blog", "getXml", "{page}"),
|
||||
"{page}.html" => array ("blog", "getHtml", "{page}"),
|
||||
"{page}.csv" => array ("blog", "getCsv", "{page}"),
|
||||
"{page}.json" => array ("blog", "getJson", "{page}"),
|
||||
"{page}.txt" => array ("blog", "getTxt", "{page}"),
|
||||
"{page}" => array ("blog", "getHtml", "{page}"),
|
||||
));
|
||||
echo "404 !";
|
||||
36
examples/blog/models/model_file.php
Normal file
36
examples/blog/models/model_file.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/** Model_file : store the blog datas in files */
|
||||
class model_file
|
||||
{
|
||||
public $dataPath = "datas/";
|
||||
|
||||
/** Return a provided article */
|
||||
function get ($articleid = FALSE)
|
||||
{
|
||||
$this->dataPath = realpath ($this->dataPath);
|
||||
if ($this->dataPath === FALSE)
|
||||
throw new Exception (_("Folder data not available"), 500);
|
||||
$fileArticle = $this->dataPath."/".$articleid;
|
||||
if (! file_exists ($fileArticle))
|
||||
throw new Exception (_("Article not found"), 404);
|
||||
$fileArticle = realpath ($fileArticle);
|
||||
if (substr ($fileArticle, 0, strlen ($this->dataPath)) !== $this->dataPath)
|
||||
throw new Exception (_("Asked article not in data path"), 404);
|
||||
if ($fileArticle === FALSE)
|
||||
throw new Exception (_("Article not found"), 404);
|
||||
return file_get_contents ($fileArticle);
|
||||
}
|
||||
|
||||
/** Return a list of all the articles ID */
|
||||
function listing ()
|
||||
{
|
||||
$list = glob ($this->dataPath."/*");
|
||||
if ($list === FALSE || empty ($list))
|
||||
throw new Exception (_("No article found"), 404);
|
||||
foreach ($list as $key=>$val)
|
||||
$list[$key] = basename ($val);
|
||||
return $list;
|
||||
}
|
||||
|
||||
}
|
||||
10
examples/blog/views/layout.html
Normal file
10
examples/blog/views/layout.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
{content}
|
||||
</body>
|
||||
</html>
|
||||
21
examples/blog/views/view_blog.php
Normal file
21
examples/blog/views/view_blog.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
class view_blog
|
||||
{
|
||||
function get ($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
function listing ($data)
|
||||
{
|
||||
$content = "<ul>\n";
|
||||
foreach ($data as $val)
|
||||
{
|
||||
$content .= " <li>";
|
||||
$content .= "<a href='".urlencode ($val)."'>".htmlentities ($val)."</a>";
|
||||
$content .= "</li>\n";
|
||||
}
|
||||
$content .= "</ul>\n";
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
406
form.php
Normal file
406
form.php
Normal file
@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
error_reporting (E_ALL);
|
||||
class form
|
||||
{
|
||||
/** This class permit to create easily some forms to HTML (or text mode in
|
||||
future).
|
||||
Each field can be checked in AJAX or HTML. */
|
||||
|
||||
private $fields = NULL;
|
||||
private $formName;
|
||||
public $debug=0;
|
||||
|
||||
function __construct ($formName = "form")
|
||||
{
|
||||
$this->formName = $formName;
|
||||
}
|
||||
|
||||
public function fields ($fields)
|
||||
{
|
||||
/** Save the fields into the structure.
|
||||
Available :
|
||||
- name : name of the field in the HTML page
|
||||
- label : label written to the describe the field
|
||||
- [titles] : text written in radio/checkboxes
|
||||
- [defaults] : default values. Must be array for checkbox/select, and
|
||||
string for others
|
||||
- [type] : text, password, hidden, checkbox, select, radio, submit
|
||||
text by default
|
||||
- [multiple] : Multiple selection are possible (if the type supports it)
|
||||
- [group] : define a fieldset and define the title with groupe name
|
||||
Warning : all the elements of the same group must be
|
||||
consecutive !
|
||||
- [readonly] : put a read-only flag on the field (the user see it but
|
||||
can't interract on it. The value will be sent to next
|
||||
page
|
||||
- [verify] : Tests to verify with error priority and associated
|
||||
message (%s is replaced by field selected value). Order
|
||||
test from main tests to minor tests.
|
||||
\$tmpfield can be used as a copy of the current field,
|
||||
to check the defaults per example
|
||||
- [error] : array containing (error|warning) => message
|
||||
*/
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
public function verify (&$fieldsVerify, $valuesVerify = NULL)
|
||||
{
|
||||
/** Return TRUE if the value associated to a field is correct. Return an
|
||||
array with a severity and a message to explain why a field is not
|
||||
correct.
|
||||
Fields can be an array with just one element, then only this element is
|
||||
checked */
|
||||
$ret = array ();
|
||||
if ($this->debug)
|
||||
echo "<pre>";
|
||||
foreach ($fieldsVerify as $field)
|
||||
{
|
||||
if (!isset ($field->verify))
|
||||
continue;
|
||||
if (!isset ($valuesVerify[$field->name]))
|
||||
throw new Exception ("No value provided for $field->name", 500);
|
||||
foreach ($field->verify as $test => $message)
|
||||
{
|
||||
$func = sprintf ($test, addslashes ($valuesVerify[$field->name]));
|
||||
if ($this->debug)
|
||||
echo "VERIFY: \"$func\" => ";
|
||||
$tmpfield = $field;
|
||||
$res = addslashes (serialize ($tmpfield));
|
||||
// TODO : http://fr2.php.net/manual/en/reflectionfunction.invokeargs.php
|
||||
// to remove eval ?
|
||||
$rc = eval ("\$tmpfield=unserialize(stripslashes('$res'));".
|
||||
"return $func;");
|
||||
if ($this->debug)
|
||||
var_dump ($rc);
|
||||
if ($rc !== FALSE)
|
||||
{
|
||||
$ret[$field->name] = $message;
|
||||
$field->error = $message;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "RESULT: ";
|
||||
var_dump ($ret);
|
||||
echo "</pre>";
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function printHTML ($method = 'post', $values = NULL)
|
||||
{
|
||||
/** Return the fields in HTML code. If $values is provided, use it in place
|
||||
of default values. In case of select boxes, $values are the selected
|
||||
elements
|
||||
$method is the method written in method field of <form> */
|
||||
// TODO : textarea, file
|
||||
$res = "";
|
||||
$res = "<form action='#' method='$method'";
|
||||
if ($this->formName != "")
|
||||
$res .= " id='$this->formName'";
|
||||
$res .= ">\n";
|
||||
$group = "";
|
||||
foreach ($this->fields as $field)
|
||||
{
|
||||
if (isset ($field->group) && $field->group !== $group)
|
||||
{
|
||||
$res .= "<fieldset>\n";
|
||||
$res .= " <legend>$field->group</legend>\n";
|
||||
$group = $field->group;
|
||||
}
|
||||
|
||||
$res .=" ";
|
||||
switch ($field->type)
|
||||
{
|
||||
case "checkbox":
|
||||
// No $field->multiple
|
||||
// values !
|
||||
$res .= "<div class='form-group";
|
||||
if (isset ($field->error))
|
||||
$res .= " has-".key ($field->error);
|
||||
$res .= "'>\n";
|
||||
$res .= " <label class='control-label' for='".$this->formName."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."_0'>";
|
||||
$res .= htmlspecialchars ($field->label)."</label>\n";
|
||||
$res .= " <div class='controls'>\n";
|
||||
if (is_string ($field->defaults))
|
||||
$field->defaults = array ($field->defaults);
|
||||
foreach ($field->titles as $key=>$val)
|
||||
{
|
||||
$res .= " <input type='hidden'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."][$key]'";
|
||||
$res .= " value='unset'";
|
||||
$res .= "/>";
|
||||
$res .= "<input type='checkbox'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."][$key]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."_$key'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " disabled='disabled'";
|
||||
if (isset ($values[$field->name][$key]) &&
|
||||
$values[$field->name][$key] !== "unset")
|
||||
$res .= " checked='checked'";
|
||||
elseif (isset ($field->defaults[$key]) &&
|
||||
$field->defaults[$key] !== "")
|
||||
$res .= " checked='checked'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= "/>";
|
||||
$res .= "$val\n";
|
||||
}
|
||||
|
||||
if (isset ($field->error))
|
||||
$res .= " <span class='help-block'>".reset ($field->error).
|
||||
"</span>\n";
|
||||
$res .= " </div>\n"; // End controls
|
||||
$res .= " </div>\n"; // End form-group
|
||||
break;
|
||||
|
||||
case "hidden":
|
||||
// No $field->label, $field->multiple, $field->readonly
|
||||
$res .= "<input type='hidden'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'";
|
||||
if (isset ($values[$field->name]))
|
||||
$res .= " value='".htmlspecialchars ($values[$field->name])."'";
|
||||
else
|
||||
$res .= " value='".htmlspecialchars ($field->defaults)."'";
|
||||
$res .= "/>\n";
|
||||
break;
|
||||
|
||||
case "password":
|
||||
// No $field->multiple
|
||||
$res .= "<div class='form-group";
|
||||
if (isset ($field->error))
|
||||
$res .= " has-".key ($field->error);
|
||||
$res .= "'>\n";
|
||||
$res .= " <label class='control-label' for='".$this->formName."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'>";
|
||||
$res .= htmlspecialchars ($field->label)."</label>\n";
|
||||
$res .= " <div class='controls'>\n";
|
||||
$res .= " <input type='password'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'";
|
||||
if (isset ($values[$field->name]))
|
||||
$res .= " value='".htmlspecialchars ($values[$field->name],
|
||||
ENT_QUOTES)."'";
|
||||
else
|
||||
$res .= " value='".htmlspecialchars ($field->defaults, ENT_QUOTES).
|
||||
"'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " readonly='readonly'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= "/>\n";
|
||||
if (isset ($field->error))
|
||||
$res .= " <span class='help-block'>".reset ($field->error).
|
||||
"</span>\n";
|
||||
$res .= " </div>\n"; // End controls
|
||||
$res .= " </div>\n"; // End form-group
|
||||
break;
|
||||
|
||||
case "radio":
|
||||
// No $field->multiple
|
||||
$res .= "<div class='form-group";
|
||||
if (isset ($field->error))
|
||||
$res .= " has-".key ($field->error);
|
||||
$res .= "'>\n";
|
||||
$res .= " <label class='control-label' for='".$this->formName."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."_0'>";
|
||||
$res .= htmlspecialchars ($field->label)."</label>\n";
|
||||
$res .= " <div class='controls'>\n";
|
||||
if (is_string ($field->defaults))
|
||||
$field->defaults = array ($field->defaults);
|
||||
$res .= " <input type='hidden'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " value='unset'";
|
||||
$res .= "/>\n";
|
||||
foreach ($field->titles as $key=>$val)
|
||||
{
|
||||
$res .= " <label class='radio'>";
|
||||
$res .= "<input type='radio'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."_$key'";
|
||||
$res .= " value='".htmlspecialchars ($val, ENT_QUOTES)."'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " readonly='readonly'";
|
||||
if (isset ($values[$field->name]) &&
|
||||
$values[$field->name] === $val)
|
||||
$res .= " checked='checked'";
|
||||
elseif (isset ($field->defaults[0]) &&
|
||||
$field->defaults[0] === $val)
|
||||
$res .= " checked='checked'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= "/>";
|
||||
$res .= "$val";
|
||||
$res .= "</label>\n"; // End label radio
|
||||
}
|
||||
|
||||
if (isset ($field->error))
|
||||
$res .= " <span class='help-block'>".reset ($field->error).
|
||||
"</span>\n";
|
||||
$res .= " </div>\n"; // End controls
|
||||
$res .= " </div>\n"; // End form-group
|
||||
break;
|
||||
|
||||
case "select":
|
||||
// $values->$field
|
||||
$res .= "<div class='form-group";
|
||||
if (isset ($field->error))
|
||||
$res .= " has-".key ($field->error);
|
||||
$res .= "'>\n";
|
||||
$res .= " <label class='control-label' for='".$this->formName."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'>";
|
||||
$res .= htmlspecialchars ($field->label)."</label>\n";
|
||||
$res .= " <div class='controls'>\n";
|
||||
if (isset ($field->defaults) && is_array ($field->defaults))
|
||||
{
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
{
|
||||
foreach ($field->defaults as $key=>$val)
|
||||
{
|
||||
$res .= "<input type='hidden'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."][".
|
||||
htmlspecialchars ($key, ENT_QUOTES)."]'";
|
||||
$res .= " value='";
|
||||
$res .= htmlspecialchars ($val, ENT_QUOTES)."'";
|
||||
$res .= "/>";
|
||||
}
|
||||
}
|
||||
|
||||
$res .= " <select";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]";
|
||||
if (isset ($field->multiple) && $field->multiple !== FALSE)
|
||||
$res .= "[]";
|
||||
$res .= "'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'";
|
||||
if (isset ($field->multiple) && $field->multiple !== FALSE)
|
||||
$res .= " multiple='multiple'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " disabled='disabled'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= ">\n";
|
||||
foreach ($field->defaults as $key=>$val)
|
||||
{
|
||||
$res .= " <option value='";
|
||||
$res .= htmlspecialchars ($key, ENT_QUOTES)."'";
|
||||
if (isset ($values[$field->name]) &&
|
||||
is_string ($values[$field->name]) &&
|
||||
$values[$field->name] == $key)
|
||||
$res .= " selected='selected'";
|
||||
elseif (isset ($values[$field->name]) &&
|
||||
is_array ($values[$field->name]) &&
|
||||
in_array ($key, $values[$field->name]))
|
||||
$res .= " selected='selected'";
|
||||
$res .= ">";
|
||||
$res .= htmlspecialchars ($val);
|
||||
$res .= "</option>\n";
|
||||
}
|
||||
|
||||
$res .= " </select>\n";
|
||||
if (isset ($field->error))
|
||||
$res .= " <span class='help-block'>".reset ($field->error).
|
||||
"</span>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$res .= _("No value provided");
|
||||
}
|
||||
|
||||
$res .= " </div>\n"; // End controls
|
||||
$res .= " </div>\n"; // End form-group
|
||||
break;
|
||||
|
||||
case "submit":
|
||||
// No $field->label, $field->multiple, $field->error
|
||||
$res .= "<input type='submit'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " disabled='disabled'";
|
||||
if (isset ($field->defaults))
|
||||
$res .= " value='".htmlspecialchars ($field->defaults, ENT_QUOTES).
|
||||
"'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= "/>\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
// No $field->multiple, $field->titles
|
||||
$res .= "<div class='form-group";
|
||||
if (isset ($field->error))
|
||||
$res .= " has-".key ($field->error);
|
||||
$res .= "'>\n";
|
||||
$res .= " <label class='control-label' for='".$this->formName."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'>";
|
||||
$res .= htmlspecialchars ($field->label)."</label>\n";
|
||||
//$res .= " <div class='controls'>\n";
|
||||
$res .= " <input type='text'";
|
||||
$res .= " name='$this->formName"."[".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."]'";
|
||||
$res .= " id='$this->formName"."_".
|
||||
htmlspecialchars ($field->name, ENT_QUOTES)."'";
|
||||
if (isset ($values[$field->name]))
|
||||
$res .= " value='".htmlspecialchars ($values[$field->name],
|
||||
ENT_QUOTES)."'";
|
||||
else
|
||||
$res .= " value='".htmlspecialchars ($field->defaults, ENT_QUOTES).
|
||||
"'";
|
||||
if (isset ($field->readonly) && $field->readonly !== FALSE)
|
||||
$res .= " readonly='readonly'";
|
||||
$res .= " class='form-control'";
|
||||
$res .= "/>\n";
|
||||
if (isset ($field->error))
|
||||
$res .= " <span class='help-block'>".reset ($field->error).
|
||||
"</span>\n";
|
||||
//$res .= " </div>\n"; // End controls
|
||||
$res .= " </div>\n"; // End form-group
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset ($field->group) && $field->group !== $group ||
|
||||
!isset ($field->group) && $group !== "")
|
||||
{
|
||||
$res .="</fieldset>\n";
|
||||
$group = "";
|
||||
}
|
||||
}
|
||||
|
||||
$res .= "</form>\n";
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
||||
class formfield
|
||||
{
|
||||
public $name;
|
||||
public $label;
|
||||
public $titles;
|
||||
public $defaults;
|
||||
public $type;
|
||||
public $multiple;
|
||||
public $group;
|
||||
public $readonly;
|
||||
public $verify;
|
||||
public $error;
|
||||
function __construct ($name, $label)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->label = $label;
|
||||
}
|
||||
}
|
||||
55
http.php
Normal file
55
http.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
class http
|
||||
{
|
||||
/** Choose the best choice from user choices.
|
||||
Can be used for languages (HTTP_ACCEPT_LANGUAGE), type of pages
|
||||
(HTTP_ACCEPT)...
|
||||
Ex. fr, en-gb;q=0.8, en;q=0.7
|
||||
Ex. text/html,application/xhtml+xml,application/xml;q=0.9,* /*;q=0.8
|
||||
If available is empty, then return the best priority defined by user,
|
||||
and throw an exception if nothing is provided for by the user.
|
||||
If nothing match, return $default
|
||||
*/
|
||||
function bestChoice ($uservar, $available=array(), $default=FALSE)
|
||||
{
|
||||
$uservar = str_replace (" ", "", $uservar);
|
||||
$userchoices = explode (",", $uservar);
|
||||
if (!isset ($userchoices[0]))
|
||||
{
|
||||
if ($default === FALSE)
|
||||
throw new Exception ("No user choice provided to bestChoice", 500);
|
||||
return $default;
|
||||
}
|
||||
// Remove weights (provided by the order of the user)
|
||||
// TODO : Reorganise the order if the weights are not in the right order
|
||||
foreach ($userchoices as $key=>$val)
|
||||
{
|
||||
$vals = @explode (";q", $val);
|
||||
$userchoices[$key] = $vals[0];
|
||||
}
|
||||
|
||||
if (count ($available) === 0)
|
||||
return $userchoices[0];
|
||||
|
||||
// Look at the best existing solution
|
||||
foreach ($userchoices as $choice)
|
||||
{
|
||||
foreach ($available as $avail)
|
||||
{
|
||||
if (strtolower ($avail) === strtolower ($choice))
|
||||
return $avail;
|
||||
// Case en_US
|
||||
$availTmp = str_replace ("_", "-", $avail);
|
||||
if (strtolower ($availTmp) === strtolower ($choice))
|
||||
return $avail;
|
||||
// Case text/xml, application/csv (just compare xml or csv)
|
||||
$mimes = explode ("/", $choice);
|
||||
if (isset ($mimes[1]) && strtolower ($availTmp) === $mimes[1])
|
||||
return $avail;
|
||||
}
|
||||
}
|
||||
|
||||
// No best solution found. Use the default available solution
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
9
output.php
Normal file
9
output.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/** Class used to display datas */
|
||||
class output
|
||||
{
|
||||
public function out ($data)
|
||||
{
|
||||
throw new Exception ("No type of output selected");
|
||||
}
|
||||
}
|
||||
22
outputcsv.php
Normal file
22
outputcsv.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
require_once ("output.php");
|
||||
class outputcsv extends output
|
||||
{
|
||||
public function out ($data)
|
||||
{
|
||||
if (!function_exists ("fputcsv"))
|
||||
throw new Exception ("CSV support not available in PHP !", 500);
|
||||
if (!is_array ($data))
|
||||
$data = array ($data);
|
||||
@header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
@header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
@header('Last-Modified: '.gmdate ('D, d M Y H:i:s').' GMT');
|
||||
@header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
@header('Pragma: no-cache');
|
||||
@header ("Content-Type: text/csv");
|
||||
// TODO : return $csv
|
||||
$out = fopen ('php://output', 'w');
|
||||
fputcsv ($out, $data);
|
||||
fclose ($out);
|
||||
}
|
||||
}
|
||||
42
outputhtml.php
Normal file
42
outputhtml.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
require_once ("output.php");
|
||||
class outputhtml extends output
|
||||
{
|
||||
/** Data is printed by viewClass->viewmethod, in the middle of $layout
|
||||
title is put in the title of the HTML page
|
||||
$replacement modify the result (it can do title too :
|
||||
array ("{title}"=>"title to display") */
|
||||
public function out ($data, $title = FALSE,
|
||||
$viewClass = FALSE, $viewMethod = FALSE,
|
||||
$layout = FALSE, $replacement = array())
|
||||
{
|
||||
@header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
@header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
@header('Last-Modified: '.gmdate ('D, d M Y H:i:s').' GMT');
|
||||
@header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
@header('Pragma: no-cache');
|
||||
@header ("Content-Type: text/html");
|
||||
$resView = $data;
|
||||
if ($viewClass !== FALSE && $viewMethod !== FALSE)
|
||||
{
|
||||
require ("views/$viewClass.php");
|
||||
$reflection = new ReflectionMethod ($viewClass, $viewMethod);
|
||||
$resView = $reflection->invokeArgs (new $viewClass, array ($data));
|
||||
}
|
||||
|
||||
if ($layout !== FALSE)
|
||||
{
|
||||
$layoutPage = file_get_contents ("views/$layout.html");
|
||||
$resView = str_replace ("{content}", $resView, $layoutPage);
|
||||
}
|
||||
|
||||
// Do the title replacement in the replacement structure
|
||||
if (! isset ($replacement["{title}"]))
|
||||
$replacement["{title}"] = $title;
|
||||
|
||||
foreach ($replacement as $key=>$val)
|
||||
$resView = str_replace ($key, $val, $resView);
|
||||
|
||||
return $resView;
|
||||
}
|
||||
}
|
||||
18
outputjson.php
Normal file
18
outputjson.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
require_once ("output.php");
|
||||
class outputjson extends output
|
||||
{
|
||||
public function out ($data)
|
||||
{
|
||||
if (!function_exists ("json_encode"))
|
||||
throw new Exception ("JSON support not available in PHP ! apt-get ".
|
||||
"install php5-json", 500);
|
||||
@header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
@header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
@header('Last-Modified: '.gmdate ('D, d M Y H:i:s').' GMT');
|
||||
@header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
@header('Pragma: no-cache');
|
||||
@header ("Content-Type: application/json");
|
||||
echo json_encode ($data);
|
||||
}
|
||||
}
|
||||
28
outputtxt.php
Normal file
28
outputtxt.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
require_once ("output.php");
|
||||
class outputtxt extends output
|
||||
{
|
||||
public function out ($data)
|
||||
{
|
||||
@header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
@header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
@header('Last-Modified: '.gmdate ('D, d M Y H:i:s').' GMT');
|
||||
@header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
@header('Pragma: no-cache');
|
||||
@header ("Content-Type: text/plain");
|
||||
if ($data === TRUE)
|
||||
echo "OK\n";
|
||||
elseif ($data === FALSE)
|
||||
echo "FALSE\n";
|
||||
elseif (is_string ($data))
|
||||
echo "$data\n";
|
||||
elseif (is_integer ($data))
|
||||
echo "$data\n";
|
||||
elseif (is_array ($data))
|
||||
echo substr (print_r ($data, TRUE), 8, -3)."\n";
|
||||
elseif ($data === NULL)
|
||||
echo "NULL\n";
|
||||
else
|
||||
echo "TODO : ".gettype ($rc)." on ".__FILE__.":".__LINE__."\n";
|
||||
}
|
||||
}
|
||||
40
outputxml.php
Normal file
40
outputxml.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
require_once ("output.php");
|
||||
class outputxml extends output
|
||||
{
|
||||
public function out ($data)
|
||||
{
|
||||
@header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
@header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
|
||||
@header('Last-Modified: '.gmdate ('D, d M Y H:i:s').' GMT');
|
||||
@header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
@header('Pragma: no-cache');
|
||||
@header ("Content-Type: text/xml");
|
||||
$xml = new SimpleXMLElement ("<?xml version=\"1.0\"?><root></root>");
|
||||
// function call to convert array to xml
|
||||
if (!is_array ($data))
|
||||
$data = array ($data);
|
||||
$this->array_to_xml ($data, $xml);
|
||||
//saving generated xml file
|
||||
print $xml->asXML();
|
||||
}
|
||||
|
||||
// function defination to convert array to xml
|
||||
private function array_to_xml ($data, &$xml)
|
||||
{
|
||||
foreach($data as $key => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
{
|
||||
$key = is_numeric($key) ? "item$key" : $key;
|
||||
$subnode = $xml->addChild("$key");
|
||||
array_to_xml($value, $subnode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = is_numeric($key) ? "item$key" : $key;
|
||||
$xml->addChild("$key","$value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
renderer.php
Normal file
86
renderer.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
class renderer
|
||||
{
|
||||
public $result = NULL;
|
||||
public $output = NULL;
|
||||
public $title = " "; // Title by default : space to be compatible with HTML5
|
||||
/** Filename of class containing the presentation layer */
|
||||
public $viewClass = FALSE;
|
||||
/** Method apply to class object to display the $result */
|
||||
public $viewMethod = FALSE;
|
||||
/** Filename in views containing the HTML layout. Without .html at the end */
|
||||
public $layout = FALSE;
|
||||
|
||||
/** Display the $this->result result in the output model defined by
|
||||
$this->output */
|
||||
public function run ()
|
||||
{
|
||||
if (!@require_once ("output$this->output.php"))
|
||||
throw new Exception ("Renderer '$this->output' not found", 500);
|
||||
$class = "output$this->output";
|
||||
$reflection = new ReflectionMethod ($class, "out");
|
||||
$res = $reflection->invokeArgs (new $class,
|
||||
array ($this->result, $this->title,
|
||||
$this->viewClass, $this->viewMethod, $this->layout));
|
||||
echo $res;
|
||||
}
|
||||
|
||||
/** Add a flash message to the user, on the next HTML page.
|
||||
In CLI, display the message immediately.
|
||||
Message must be translated before sending to the function
|
||||
Priority is 1:success, 2:info, 3:warning, 4:error
|
||||
or textual : SUCCESS, INFO, WARNING, ERROR */
|
||||
static public function flash ($priority, $message)
|
||||
{
|
||||
if (php_sapi_name () === "cli")
|
||||
{
|
||||
switch ($priority)
|
||||
{
|
||||
case 1:
|
||||
case "SUCCESS":
|
||||
echo "SUCCESS: $message\n";
|
||||
break;
|
||||
case 2:
|
||||
case "INFO":
|
||||
echo "INFO: $message\n";
|
||||
break;
|
||||
case 3:
|
||||
case "WARNING":
|
||||
echo "WARNING: $message\n";
|
||||
break;
|
||||
case 4:
|
||||
case "ERROR":
|
||||
echo "ERROR: $message\n";
|
||||
break;
|
||||
default:
|
||||
throw new Exception ("Unknown flash priority '$priority'", 500);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! isset ($_SESSION))
|
||||
throw new Exception ("No session available to store flash", 500);
|
||||
switch ($priority)
|
||||
{
|
||||
case 1:
|
||||
case "SUCCESS":
|
||||
$_SESSION["renderer"]["flash"][] = array (1, $message);
|
||||
break;
|
||||
case 2:
|
||||
case "INFO":
|
||||
$_SESSION["renderer"]["flash"][] = array (2, $message);
|
||||
break;
|
||||
case 3:
|
||||
case "WARNING":
|
||||
$_SESSION["renderer"]["flash"][] = array (3, $message);
|
||||
break;
|
||||
case 4:
|
||||
case "ERROR":
|
||||
$_SESSION["renderer"]["flash"][] = array (4, $message);
|
||||
break;
|
||||
default:
|
||||
throw new Exception ("Unknown flash priority '$priority'", 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
391
route.php
Normal file
391
route.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
error_reporting (E_ALL);
|
||||
class route
|
||||
{
|
||||
private $baseURL = "";
|
||||
private $baseURLmodule = "";
|
||||
public $module = NULL;
|
||||
public $debug=0; // 0:NoDebug, 1:routing, 2:more debug (developpement)
|
||||
//public $defaultOutput = "html"; // Default renderer : html
|
||||
function __construct ()
|
||||
{
|
||||
}
|
||||
|
||||
/** Return the baseURL of the site
|
||||
Always finish with a slash */
|
||||
function baseURL ($module = FALSE)
|
||||
{
|
||||
if ($this->module === NULL)
|
||||
$this->module = $module;
|
||||
if ($this->baseURL !== "")
|
||||
return $this->baseURL;
|
||||
if (isset ($_SERVER["SCRIPT_NAME"]))
|
||||
$this->baseURL = dirname ($_SERVER["SCRIPT_NAME"]);
|
||||
if (isset ($_SERVER["SERVER_NAME"]))
|
||||
$this->baseURL = "//".$_SERVER["SERVER_NAME"].$this->baseURL;
|
||||
if (isset ($_SERVER["HTTPS"]))
|
||||
$this->baseURL = "https:".$this->baseURL;
|
||||
else
|
||||
$this->baseURL = "http:".$this->baseURL;
|
||||
if (substr ($this->baseURL, -1) !== "/")
|
||||
$this->baseURL .= "/";
|
||||
$this->baseURLmodule = $this->baseURL;
|
||||
// Only != NOT !== (cause : $this->module can be converted in string "0")
|
||||
if ($this->module != FALSE)
|
||||
{
|
||||
$this->baseURLmodule = $this->baseURL;
|
||||
$this->baseURL = dirname ($this->baseURL)."/";
|
||||
}
|
||||
|
||||
return $this->baseURL;
|
||||
}
|
||||
|
||||
/** Return the baseURL of the module
|
||||
Always finish with a slash */
|
||||
function baseURLmodule ()
|
||||
{
|
||||
if ($this->baseURLmodule !== "")
|
||||
return $this->baseURLmodule;
|
||||
$this->baseURL ($this->module);
|
||||
return $this->baseURLmodule;
|
||||
}
|
||||
|
||||
function baseURLset ($baseURL)
|
||||
{
|
||||
$this->baseURL = $baseURL;
|
||||
}
|
||||
|
||||
/** Return the complete URL used to see this page */
|
||||
function requestURL ()
|
||||
{
|
||||
if (isset ($_SERVER["HTTPS"]))
|
||||
$url = "https:";
|
||||
else
|
||||
$url = "http:";
|
||||
if (isset ($_SERVER["SERVER_NAME"]))
|
||||
$url .= "//".$_SERVER["SERVER_NAME"];
|
||||
if (isset ($_SERVER["REQUEST_URI"]))
|
||||
$url .= $_SERVER["REQUEST_URI"];
|
||||
return $url;
|
||||
}
|
||||
|
||||
/** Do all the routing with redirections
|
||||
$destURL can be absolute or relative
|
||||
If module is set, the site is modular and a directory is named with module
|
||||
name */
|
||||
function redirect ($destURL, $module)
|
||||
{
|
||||
if (php_sapi_name () === "cli")
|
||||
exit;
|
||||
$destURL = trim ($destURL);
|
||||
$baseURL = $this->baseURL ($module);
|
||||
$requestURL = $this->requestURL ();
|
||||
if (substr ($requestURL, -1) !== "/")
|
||||
$requestURL .= "/";
|
||||
if ($destURL[0] === "/")
|
||||
{
|
||||
// Absolute : return to project base
|
||||
$destURL = $baseURL.substr ($destURL, 1);
|
||||
}
|
||||
if (substr ($destURL, 0, 4) !== "http")
|
||||
{
|
||||
// Relative to parameters : continue
|
||||
$destURL = $requestURL.$destURL;
|
||||
}
|
||||
|
||||
// Else http : keep the complete URL
|
||||
if ($destURL === "")
|
||||
throw new Exception ("Destination URL is empty", 500);
|
||||
if ($destURL === $requestURL)
|
||||
throw new Exception ("Redirect to myself", 508);
|
||||
if (substr ($destURL, 0, strlen ($baseURL)) !== $baseURL)
|
||||
throw new Exception ("Can't redirect outside this site (Base $baseURL)",
|
||||
405);
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "<pre>\n";
|
||||
echo "==== DEBUG : REDIRECT START ====\n";
|
||||
echo "BASEURL=$baseURL\n";
|
||||
echo "REQUURL=$requestURL\n";
|
||||
echo "destURL=$destURL\n";
|
||||
echo " ---> Redirect to <a href='$destURL'>$destURL</a>\n";
|
||||
echo "==== DEBUG : REDIRECT END ====\n";
|
||||
echo "</pre>\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (! headers_sent ())
|
||||
{
|
||||
header ("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header ("Pragma: no-cache");
|
||||
header ("Location: $destURL");
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<script type='text/javascript'>\n";
|
||||
echo "window.location.replace('$destURL');</script>";
|
||||
echo "<a href='$destURL'>Redirect to $destURL</a>";
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/** Do all the routing actions
|
||||
wait an array with search=>action
|
||||
- search can be the end of URL and optionnal parameters in {var1} format
|
||||
{var1} must be the name of the parameter of the method
|
||||
- action is an array with (0=>CLASS, 1=>method, 2...=>parameters) */
|
||||
function routingCollection ($routes)
|
||||
{
|
||||
if ($this->debug)
|
||||
echo "<pre>==== DEBUG : ROUTING START ====\n";
|
||||
foreach ($routes as $route=>$action)
|
||||
{
|
||||
$url = substr ($this->requestURL (), strlen ($this->baseURLmodule ()));
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "==> $url ?? $route => ".$action[0]."->".$action[1]."(";
|
||||
echo implode (", ", array_slice ($action, 2)).") : ";
|
||||
// Flush to debug redirect if javascript is disabled
|
||||
ob_flush ();
|
||||
flush ();
|
||||
}
|
||||
|
||||
$class = $action[0];
|
||||
$method = $action[1];
|
||||
$params = array_slice ($action, 2);
|
||||
|
||||
/* This part is actually disabled to be simpler
|
||||
// Asked output
|
||||
$outputAuthorized = array ("html");
|
||||
// -- Look at authorized outputs
|
||||
$regex = "#\((.+)\)#U";
|
||||
unset ($matches);
|
||||
$rcRegex = preg_match ($regex, $route, $matchesExt);
|
||||
if ($rcRegex !== FALSE && $rcRegex !== 0)
|
||||
{
|
||||
// Defined output provided
|
||||
$outputAuthorized = explode (".", $matchesExt[1]);
|
||||
$routeOutput = $matchesExt[0];
|
||||
$regexOutput = "(?P<extension>";
|
||||
foreach ($outputAuthorized as $k=>$m)
|
||||
{
|
||||
if ($m === "")
|
||||
{
|
||||
$regexOutput .= "";
|
||||
}
|
||||
else
|
||||
{
|
||||
$outputAuthorized[$k] = ".$m";
|
||||
$regexOutput .= "|\\.$m";
|
||||
}
|
||||
}
|
||||
$regexOutput .= ")";
|
||||
}
|
||||
|
||||
if ($this->debug)
|
||||
echo "\n";
|
||||
if ($this->debug > 1)
|
||||
{
|
||||
echo " -- AUTHORIZED OUTPUT\n";
|
||||
echo "routeOutput = $routeOutput\n";
|
||||
echo "regexOutput = ".htmlentities ($regexOutput)."\n";
|
||||
echo "outputAuthorized = ";print_r ($outputAuthorized);
|
||||
echo " -- LOOK AT EXTENSION IN URL : SAVE IT AND REMOVE IF FOUND\n";
|
||||
}
|
||||
|
||||
$regex = "#^$route$#U";
|
||||
$regex = str_replace ("{", "(?P<", $regex);
|
||||
$regex = str_replace ("}", ">.+)", $regex);
|
||||
$regex = str_replace ($routeOutput, $regexOutput, $regex);
|
||||
if ($this->debug > 1)
|
||||
echo "regex = ".htmlentities ($regex)."\n";
|
||||
unset ($matches);
|
||||
$rcRegex = preg_match ($regex, $url, $matches);
|
||||
if ($rcRegex !== FALSE && $rcRegex !== 0)
|
||||
{
|
||||
if ($this->debug > 1)
|
||||
{
|
||||
echo "MATCHES=";print_r ($matches);
|
||||
}
|
||||
if (isset ($matches["extension"]) && $matches["extension"] !== "")
|
||||
{
|
||||
// Authorized extension found : save it and remove it from URL
|
||||
$this->output = substr ($matches["extension"], 1);
|
||||
if ($this->debug)
|
||||
echo "Extension found in url : output='".$this->output."'\n";
|
||||
// Remove numerical indexes and extension : new URL without output
|
||||
// extension
|
||||
$url = "";
|
||||
foreach ($matches as $key=>$val)
|
||||
{
|
||||
if (is_numeric ($key)) continue;
|
||||
if ($key === "extension") continue;
|
||||
$url .= $val;
|
||||
}
|
||||
|
||||
if ($this->debug > 1)
|
||||
echo "After removing extension : url='$url'\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->output = $this->defaultOutput;
|
||||
if ($this->debug)
|
||||
echo "Extension empty found in url : default output '".
|
||||
"$this->output'\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->output = $this->defaultOutput;
|
||||
if ($this->debug)
|
||||
echo "Extension not found in url : default output '$this->output'\n";
|
||||
}
|
||||
if ($this->debug > 1)
|
||||
echo " -- REMOVE EXTENSION TEST IN ROUTE\n";
|
||||
$route = str_replace ($routeOutput, "", $route);
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "URL='";print_r ($url); echo "'\n";
|
||||
echo "ROUTE='";print_r ($route); echo "'\n";
|
||||
}*/
|
||||
|
||||
|
||||
// URL === ROUTE (No variables)
|
||||
if ($url === $route)
|
||||
{
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "FOUND : URL === ROUTE (No variables) : ";
|
||||
echo "Call $class->$method()\n";
|
||||
echo "==== DEBUG : ROUTING END ====</pre>\n";
|
||||
}
|
||||
|
||||
// For loading user modules controllers
|
||||
$rc = @include_once ("controllers/controller_$class.php");
|
||||
// For loading framework classes
|
||||
if ($rc === FALSE) @include_once ("$class.php");
|
||||
|
||||
try
|
||||
{
|
||||
$reflection = new ReflectionMethod ($class, $method);
|
||||
$res = $reflection->invokeArgs(new $class, $params);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$res = "ERROR : ". $e->getMessage();
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// URL === REGEXP ROUTE
|
||||
// Variables are exposed in url/{var1}/{var2}
|
||||
$regex = "#^$route$#U";
|
||||
$regex = str_replace ("{", "(?P<", $regex);
|
||||
$regex = str_replace ("}", ">.+)", $regex);
|
||||
unset ($matches);
|
||||
$rcRegex = preg_match ($regex, $url, $matches);
|
||||
if ($rcRegex !== FALSE && $rcRegex !== 0)
|
||||
{
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "FOUND : URL === REGEX : ";
|
||||
}
|
||||
|
||||
// seach->replace with the matches
|
||||
$search = array_keys ($matches);
|
||||
array_walk ($search, function(&$n) { $n = "{".$n."}"; });
|
||||
$replace = $matches;
|
||||
|
||||
// For loading user modules controllers
|
||||
$rc = @include_once ("controllers/controller_$class.php");
|
||||
// For loading framework classes
|
||||
if ($rc === FALSE) $rc = @include_once ("$class.php");
|
||||
if ($rc === FALSE && $this->debug)
|
||||
echo "NO MATCH (missing class file)\n";
|
||||
if ($rc === FALSE)
|
||||
continue;
|
||||
|
||||
// Check if a parameter is for the constructor of the class
|
||||
$passConstruct = array ();
|
||||
try
|
||||
{
|
||||
// If there is no constructor in the controller, an exception is
|
||||
// raised
|
||||
$reflectionClass = new ReflectionMethod ($class, "__construct");
|
||||
foreach ($reflectionClass->getParameters() as $key=>$param)
|
||||
{
|
||||
if (isset ($matches[$param->getName ()]))
|
||||
$passConstruct[] = $matches[$param->getName ()];
|
||||
elseif ($param->isOptional ())
|
||||
$passConstruct[] = $matches[$param->getDefaultValue ()];
|
||||
else
|
||||
{
|
||||
// Missing parameters : abort this route test
|
||||
if ($this->debug)
|
||||
echo "NO MATCH (missing constructor parameter)\n";
|
||||
continue (2);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
}
|
||||
|
||||
//echo "passConstruct=";print_r ($passConstruct);
|
||||
// Check if the method need parameters
|
||||
$reflection = new ReflectionMethod ($class, $method);
|
||||
$passMethod = array();
|
||||
//echo "getParameters=";var_dump ($reflection->getParameters());
|
||||
foreach($reflection->getParameters() as $key=>$param)
|
||||
{
|
||||
if (isset ($matches[$param->getName ()]))
|
||||
$passMethod[] = $matches[$param->getName ()];
|
||||
elseif (isset ($params[$key]))
|
||||
$passMethod[] =str_replace ($search, $replace, $params[$key]);
|
||||
elseif ($param->isOptional ())
|
||||
$passMethod[] = $matches[$param->getDefaultValue ()];
|
||||
else
|
||||
{
|
||||
if ($this->debug)
|
||||
echo "NO MATCH (missing method parameter)\n";
|
||||
// Missing parameters : abort this route test
|
||||
continue (2);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "Call $class(".implode (",", $passConstruct).")->$method(";
|
||||
echo implode (",", $passMethod).")\n";
|
||||
echo "==== DEBUG : ROUTING END ====</pre>\n";
|
||||
}
|
||||
|
||||
//echo "matches=";print_r ($matches);
|
||||
//echo "passMethod=";print_r ($passMethod);
|
||||
try
|
||||
{
|
||||
$refclass = new ReflectionClass ($class);
|
||||
$refClassInst = $refclass->newInstanceArgs ($passConstruct);
|
||||
$res = $reflection->invokeArgs ($refClassInst, $passMethod);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$res = "ERROR : ". $e->getMessage();
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
if ($this->debug)
|
||||
{
|
||||
echo "NO MATCH\n";
|
||||
}
|
||||
}
|
||||
if ($this->debug)
|
||||
echo "==== DEBUG : ROUTING END : No route found====</pre>\n";
|
||||
// TODO : ERROR 404 !
|
||||
echo "404";
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user