diff --git a/Tests/AuthTest.php b/Tests/AuthTest.php index 85c324c..6af9869 100644 --- a/Tests/AuthTest.php +++ b/Tests/AuthTest.php @@ -1,4 +1,5 @@ @@ -12,40 +13,40 @@ use Domframework\Auth; /** Test the authentication */ class AuthTest extends \PHPUnit_Framework_TestCase { - public function test_page_1 () - { - $auth = new Auth (); - $res = $auth->pageHTML ("http://localhost"); - $this->assertSame (!! strpos ($res, "
pageHTML("http://localhost"); + $this->assertSame(!! strpos($res, "pageHTML ("http://localhost", "MESSAGE"); - $this->assertSame (!! strpos ($res, "MESSAGE"), true); - } + public function test_Message() + { + $auth = new Auth(); + $res = $auth->pageHTML("http://localhost", "MESSAGE"); + $this->assertSame(!! strpos($res, "MESSAGE"), true); + } - public function test_URL_1 () - { - $auth = new Auth (); - $res = $auth->pageHTML ("http://localhost", "MESSAGE", "URL/TEST"); - $this->assertSame (!! strpos ($res, "URL/TEST"), true); - } + public function test_URL_1() + { + $auth = new Auth(); + $res = $auth->pageHTML("http://localhost", "MESSAGE", "URL/TEST"); + $this->assertSame(!! strpos($res, "URL/TEST"), true); + } - public function test_alreadyAuth_1 () - { - // Not Authenticated - $auth = new Auth (); - $res = $auth->pageHTML ("http://localhost", "MESSAGE", "URL/TEST", false); - $this->assertSame (!! strpos ($res, "Please sign in"), true); - } + public function test_alreadyAuth_1() + { + // Not Authenticated + $auth = new Auth(); + $res = $auth->pageHTML("http://localhost", "MESSAGE", "URL/TEST", false); + $this->assertSame(!! strpos($res, "Please sign in"), true); + } - public function test_alreadyAuth_2 () - { - // Authenticated - $auth = new Auth (); - $res = $auth->pageHTML ("http://localhost", "", "", "AUTHENTICATED USER"); - $this->assertSame (!! strpos ($res, "AUTHENTICATED USER"), true); - } + public function test_alreadyAuth_2() + { + // Authenticated + $auth = new Auth(); + $res = $auth->pageHTML("http://localhost", "", "", "AUTHENTICATED USER"); + $this->assertSame(!! strpos($res, "AUTHENTICATED USER"), true); + } } diff --git a/Tests/AuthhtpasswdTest.php b/Tests/AuthhtpasswdTest.php index e071411..87daac7 100644 --- a/Tests/AuthhtpasswdTest.php +++ b/Tests/AuthhtpasswdTest.php @@ -1,4 +1,5 @@ @@ -12,55 +13,57 @@ use Domframework\Authhtpasswd; /** Test the Authhtpasswd.php file */ class AuthhtpasswdTest extends \PHPUnit_Framework_TestCase { - public function test_clean () - { - if (file_exists ("/tmp/htpasswd.file")) - unlink ("/tmp/htpasswd.file"); - file_put_contents ("/tmp/htpasswd.file", - 'toto@toto.com:$2y$05$dO7qyX4simzg3pMgWyqHgeAjFauXEyUdPdyrwDMVNj4fTuE24TGuq' - ."\n". - 'titi@titi.com:$2y$05$dO7qyX4simzg3pMgWyqHgeAjFauXEyUdPdyrwDMVNj4fTuE24TGuq' - ."\n" - ); - } + public function test_clean() + { + if (file_exists("/tmp/htpasswd.file")) { + unlink("/tmp/htpasswd.file"); + } + file_put_contents( + "/tmp/htpasswd.file", + 'toto@toto.com:$2y$05$dO7qyX4simzg3pMgWyqHgeAjFauXEyUdPdyrwDMVNj4fTuE24TGuq' + . "\n" . + 'titi@titi.com:$2y$05$dO7qyX4simzg3pMgWyqHgeAjFauXEyUdPdyrwDMVNj4fTuE24TGuq' + . "\n" + ); + } - public function test_connect () - { - $authhtpasswd = new Authhtpasswd (); - $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; - $res = $authhtpasswd->connect (); - $this->assertSame ($res, null); - } + public function test_connect() + { + $authhtpasswd = new Authhtpasswd(); + $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; + $res = $authhtpasswd->connect(); + $this->assertSame($res, null); + } - public function test_authentication1 () - { - $authhtpasswd = new Authhtpasswd (); - $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; - $res = $authhtpasswd->authentication ("toto@toto.com", "toto123"); - $this->assertSame ($res, true); - } + public function test_authentication1() + { + $authhtpasswd = new Authhtpasswd(); + $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; + $res = $authhtpasswd->authentication("toto@toto.com", "toto123"); + $this->assertSame($res, true); + } - public function test_authentication2 () - { - $authhtpasswd = new Authhtpasswd (); - $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; - $this->setExpectedException ("Exception"); - $res = $authhtpasswd->authentication ("UNKNOWN@toto.com", "toto123"); - } + public function test_authentication2() + { + $authhtpasswd = new Authhtpasswd(); + $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; + $this->setExpectedException("Exception"); + $res = $authhtpasswd->authentication("UNKNOWN@toto.com", "toto123"); + } - public function test_authentication3 () - { - $authhtpasswd = new Authhtpasswd (); - $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; - $this->setExpectedException ("Exception"); - $res = $authhtpasswd->authentication ("toto@toto.com", "BAD PASSWD"); - } + public function test_authentication3() + { + $authhtpasswd = new Authhtpasswd(); + $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; + $this->setExpectedException("Exception"); + $res = $authhtpasswd->authentication("toto@toto.com", "BAD PASSWD"); + } - public function test_authentication4 () - { - $authhtpasswd = new Authhtpasswd (); - $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; - $res = $authhtpasswd->authentication ("titi@titi.com", "toto123"); - $this->assertSame ($res, true); - } + public function test_authentication4() + { + $authhtpasswd = new Authhtpasswd(); + $authhtpasswd->htpasswdFile = "/tmp/htpasswd.file"; + $res = $authhtpasswd->authentication("titi@titi.com", "toto123"); + $this->assertSame($res, true); + } } diff --git a/Tests/AuthjwtTest.php b/Tests/AuthjwtTest.php index 1a2df96..316752c 100644 --- a/Tests/AuthjwtTest.php +++ b/Tests/AuthjwtTest.php @@ -1,4 +1,5 @@ @@ -12,234 +13,254 @@ use Domframework\Authjwt; /** Test the Authjwt.php file */ class AuthjwtTest extends \PHPUnit_Framework_TestCase { - public function __construct () - { - $this->cacheDir = "/tmp/testDFWJWT-".time (); - $this->serverKey = "123456789012345678901234"; - $this->cipherKey = "EC17kIvjD66fBJHbQRkPguhu"; - $this->token = null; - } + public function __construct() + { + $this->cacheDir = "/tmp/testDFWJWT-" . time(); + $this->serverKey = "123456789012345678901234"; + $this->cipherKey = "EC17kIvjD66fBJHbQRkPguhu"; + $this->token = null; + } - public function __destruct () - { - exec ("rm -rf $this->cacheDir"); - } + public function __destruct() + { + exec("rm -rf $this->cacheDir"); + } /** Create a valid token as email is provided * payload = ["email" => "toto@example.com", "password" => "ToTo"]; */ - public function testJWT1 () + public function testJWT1() // {{{ - { - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $auth = ["email" => "toto@example.com", "password" => "ToTo"]; - $this->token = $authjwt->createJwtToken ($auth); - $this->assertSame (strlen ($this->token), 145); - } + { + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $auth = ["email" => "toto@example.com", "password" => "ToTo"]; + $this->token = $authjwt->createJwtToken($auth); + $this->assertSame(strlen($this->token), 145); + } // }}} /** Check if the authentication work */ - public function testAuthValid1 () + public function testAuthValid1() // {{{ - { - $authjwt = new Authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer ".$this->token; - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - $this->assertSame ($res, - ["email" => "toto@example.com", "password" => "ToTo"]); - } + { + $authjwt = new Authjwt(); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer " . $this->token; + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + $this->assertSame( + $res, + ["email" => "toto@example.com", "password" => "ToTo"] + ); + } // }}} /** Invalid Token : reject with invalid signature */ - public function testInvalidToken1 () + public function testInvalidToken1() // {{{ - { - $this->expectException ("Exception", "JWT Signature not readable", 403); - $authjwt = new Authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer ".$this->token."NO"; - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException("Exception", "JWT Signature not readable", 403); + $authjwt = new Authjwt(); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer " . $this->token . "NO"; + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Invalid Token : reject with bad algorithm */ - public function testInvalidToken2 () + public function testInvalidToken2() // {{{ - { - $this->expectException ("Exception", "JWT with Empty algorithm", 403); - $authjwt = new Authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer "."NO".$this->token; - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException("Exception", "JWT with Empty algorithm", 403); + $authjwt = new Authjwt(); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer " . "NO" . $this->token; + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Invalid Token : No token provided */ - public function testInvalidToken3 () + public function testInvalidToken3() // {{{ - { - $this->expectException ("Exception", "No Authentication available", 401); - $authjwt = new Authjwt (); - unset ($_SERVER["HTTP_AUTHENTICATION"]); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException("Exception", "No Authentication available", 401); + $authjwt = new Authjwt(); + unset($_SERVER["HTTP_AUTHENTICATION"]); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Invalid Token : No Bearer authentication */ - public function testInvalidToken4 () + public function testInvalidToken4() // {{{ - { - $this->expectException ("Exception", "No Bearer Authentication available", - 401); - $authjwt = new Authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer"; - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException( + "Exception", + "No Bearer Authentication available", + 401 + ); + $authjwt = new Authjwt(); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer"; + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Invalid Token : no email in it */ - public function testInvalidToken5 () + public function testInvalidToken5() // {{{ - { - $this->expectException ("Exception", - "AuthJWT : No email available in auth", 403); - $auth = ["password" => "ToTo"]; - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $token = $authjwt->createJwtToken ($auth); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException( + "Exception", + "AuthJWT : No email available in auth", + 403 + ); + $auth = ["password" => "ToTo"]; + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $token = $authjwt->createJwtToken($auth); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Anonymous payload */ - public function testAnonymous1 () + public function testAnonymous1() // {{{ - { - $this->expectException ("Exception", - "AuthJWT : can not create token for anonymous", 403); - $auth = ["email" => "anonymous"]; - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $token = $authjwt->createJwtToken ($auth); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; - $authjwt->authentication ("unused", "unused"); - $res = $authjwt->getdetails (); - } + { + $this->expectException( + "Exception", + "AuthJWT : can not create token for anonymous", + 403 + ); + $auth = ["email" => "anonymous"]; + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $token = $authjwt->createJwtToken($auth); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; + $authjwt->authentication("unused", "unused"); + $res = $authjwt->getdetails(); + } // }}} /** Logout */ - public function testLogout1 () + public function testLogout1() // {{{ - { - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $this->token"; - $res = $authjwt->logout (); - $this->assertSame ($res, true); - } + { + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $this->token"; + $res = $authjwt->logout(); + $this->assertSame($res, true); + } // }}} /** Logout : No Auth provided */ - public function testLogout2 () + public function testLogout2() // {{{ - { - $this->expectException ("Exception", "No Authentication available", 401); - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - unset ($_SERVER["HTTP_AUTHENTICATION"]); - $res = $authjwt->logout (); - } + { + $this->expectException("Exception", "No Authentication available", 401); + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + unset($_SERVER["HTTP_AUTHENTICATION"]); + $res = $authjwt->logout(); + } // }}} /** Logout : No Bearer available */ - public function testLogout3 () + public function testLogout3() // {{{ - { - $this->expectException ("Exception", "No Bearer Authentication available", - 401); - $authjwt = new Authjwt (); - $authjwt->cacheDir = $this->cacheDir; - $authjwt->serverKey = $this->serverKey; - $authjwt->cipherKey = $this->cipherKey; - $_SERVER["HTTP_AUTHENTICATION"] = "Another auth"; - $res = $authjwt->logout (); - } + { + $this->expectException( + "Exception", + "No Bearer Authentication available", + 401 + ); + $authjwt = new Authjwt(); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $_SERVER["HTTP_AUTHENTICATION"] = "Another auth"; + $res = $authjwt->logout(); + } // }}} /** Not needed function connect */ - public function testUnusedFunctions1 () + public function testUnusedFunctions1() // {{{ - { - $authjwt = new Authjwt (); - $res = $authjwt->connect (); - $this->assertSame ($res, true); - } + { + $authjwt = new Authjwt(); + $res = $authjwt->connect(); + $this->assertSame($res, true); + } // }}} /** Not needed function changepassword */ - public function testUnusedFunctions2 () + public function testUnusedFunctions2() // {{{ - { - $this->expectException ("Exception", - "The password can't be change for JWT users", 405); - $authjwt = new Authjwt (); - $res = $authjwt->changepassword ("unused", "unused"); - } + { + $this->expectException( + "Exception", + "The password can't be change for JWT users", + 405 + ); + $authjwt = new Authjwt(); + $res = $authjwt->changepassword("unused", "unused"); + } // }}} /** Not needed function overwritepassword */ - public function testUnusedFunctions3 () + public function testUnusedFunctions3() // {{{ - { - $this->expectException ("Exception", - "The password can't be overwrite for JWT users", 405); - $authjwt = new Authjwt (); - $res = $authjwt->overwritepassword ("unused", "unused"); - } + { + $this->expectException( + "Exception", + "The password can't be overwrite for JWT users", + 405 + ); + $authjwt = new Authjwt(); + $res = $authjwt->overwritepassword("unused", "unused"); + } // }}} } diff --git a/Tests/AuthsympaTest.php b/Tests/AuthsympaTest.php index a90ced9..ad66577 100644 --- a/Tests/AuthsympaTest.php +++ b/Tests/AuthsympaTest.php @@ -1,4 +1,5 @@ @@ -12,77 +13,75 @@ use Domframework\Authsympa; /** Test the authentication on Sympa Service */ class AuthsympaTest extends \PHPUnit_Framework_TestCase { - public function test_connect_1 () - { - // Empty - $authsympa = new Authsympa (); - $this->expectException (); - $authsympa->connect (); - } + public function test_connect_1() + { + // Empty + $authsympa = new Authsympa(); + $this->expectException(); + $authsympa->connect(); + } - public function test_connect_2 () - { - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->connect (); - $res = $authsympa->getDetails (); - $this->assertSame ($res, null); - } + public function test_connect_2() + { + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->connect(); + $res = $authsympa->getDetails(); + $this->assertSame($res, null); + } - public function test_auth_1 () - { - // Invalid password - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; - $authsympa->connect (); - $this->expectException (); - $res = $authsympa->authentication ("richard.heral@grenoble.cnrs.fr", "XXXX"); - } + public function test_auth_1() + { + // Invalid password + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; + $authsympa->connect(); + $this->expectException(); + $res = $authsympa->authentication("richard.heral@grenoble.cnrs.fr", "XXXX"); + } - public function test_auth_2 () - { - // Unknown user - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; - $authsympa->connect (); - $this->expectException (); - $res = $authsympa->authentication ("Unknown@grenoble.cnrs.fr", "XXXX"); - } + public function test_auth_2() + { + // Unknown user + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; + $authsympa->connect(); + $this->expectException(); + $res = $authsympa->authentication("Unknown@grenoble.cnrs.fr", "XXXX"); + } - public function test_auth_3 () - { - // OK ! - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; - $authsympa->connect (); - $res = $authsympa->authentication ("richard.heral@grenoble.cnrs.fr", "Lavchdn7!"); - $this->assertSame ($res, true); - } + public function test_auth_3() + { + // OK ! + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->list = "listtest@listes.grenoble.cnrs.fr"; + $authsympa->connect(); + $res = $authsympa->authentication("richard.heral@grenoble.cnrs.fr", "Lavchdn7!"); + $this->assertSame($res, true); + } - public function test_auth_4 () - { - // Unknown list - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->list = "unknown@listes.grenoble.cnrs.fr"; - $authsympa->connect (); - $this->expectException (); - $res = $authsympa->authentication ("richard.heral@grenoble.cnrs.fr", "Lavchdn8!"); - } + public function test_auth_4() + { + // Unknown list + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->list = "unknown@listes.grenoble.cnrs.fr"; + $authsympa->connect(); + $this->expectException(); + $res = $authsympa->authentication("richard.heral@grenoble.cnrs.fr", "Lavchdn8!"); + } - public function test_auth_5 () - { - // User not in list - $authsympa = new Authsympa (); - $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; - $authsympa->list = "admins@listes.grenoble.cnrs.fr"; - $authsympa->connect (); - $this->expectException (); - $res = $authsympa->authentication ("richard.heral@grenoble.cnrs.fr", "Lavchdn8!"); - } + public function test_auth_5() + { + // User not in list + $authsympa = new Authsympa(); + $authsympa->wsdl = "https://listes.grenoble.cnrs.fr/sympa/wsdl"; + $authsympa->list = "admins@listes.grenoble.cnrs.fr"; + $authsympa->connect(); + $this->expectException(); + $res = $authsympa->authentication("richard.heral@grenoble.cnrs.fr", "Lavchdn8!"); + } } - - diff --git a/Tests/AuthzgroupsTest.php b/Tests/AuthzgroupsTest.php index 9e014f5..7fbd35e 100644 --- a/Tests/AuthzgroupsTest.php +++ b/Tests/AuthzgroupsTest.php @@ -1,4 +1,5 @@ @@ -12,320 +13,396 @@ use Domframework\Authzgroups; /** Test the Authzgroups.php file */ class AuthzgroupsTest extends \PHPUnit_Framework_TestCase { - private $dbconfig = array ( + private $dbconfig = array ( "dsn" => "sqlite:/tmp/databaseAuthzGroups.db", "username" => null, "password" => null, "driver_options" => null, "tableprefix" => "", - ); - public function test_Initialization () - { - if (file_exists ("/tmp/databaseAuthzGroups.db")) - unlink ("/tmp/databaseAuthzGroups.db"); - } + ); + public function test_Initialization() + { + if (file_exists("/tmp/databaseAuthzGroups.db")) { + unlink("/tmp/databaseAuthzGroups.db"); + } + } - public function test_createTables1 () - { - $authz = new Authzgroups (); - $this->setExpectedException ("Exception"); - $authz->createTables (); - } + public function test_createTables1() + { + $authz = new Authzgroups(); + $this->setExpectedException("Exception"); + $authz->createTables(); + } - public function test_connect () - { - // Must use the model to create the database structure as there is no - // creation of tables in controller - $authz = new Authzgroups (); - $res = $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $this->assertSame (true, $res); - } + public function test_connect() + { + // Must use the model to create the database structure as there is no + // creation of tables in controller + $authz = new Authzgroups(); + $res = $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $this->assertSame(true, $res); + } - public function test_createTables2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->createTables (); - $this->assertSame (true, $res); - } + public function test_createTables2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->createTables(); + $this->assertSame(true, $res); + } //////////////// // OBJECT // //////////////// - public function test_objectCreate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectAdd ("MODULE", "/object"); - $this->assertSame ("1", $res); - } + public function test_objectCreate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectAdd("MODULE", "/object"); + $this->assertSame("1", $res); + } - public function test_objectUpdate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectUpdate ("MODULE", "/object", "/object2"); - $this->assertSame (1, $res); - } + public function test_objectUpdate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectUpdate("MODULE", "/object", "/object2"); + $this->assertSame(1, $res); + } - public function test_objectDelete1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The object was renamed and is not available - $this->setExpectedException ("Exception"); - $res = $authz->objectDel ("MODULE", "/object"); - } + public function test_objectDelete1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The object was renamed and is not available + $this->setExpectedException("Exception"); + $res = $authz->objectDel("MODULE", "/object"); + } //////////////// // GROUPS // //////////////// - public function test_groupCreate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupAdd ("MODULE", "group"); - $this->assertSame ("1", $res); - } + public function test_groupCreate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupAdd("MODULE", "group"); + $this->assertSame("1", $res); + } - public function test_groupUpdate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupUpdate ("MODULE", "group", "group2"); - $this->assertSame (1, $res); - } + public function test_groupUpdate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupUpdate("MODULE", "group", "group2"); + $this->assertSame(1, $res); + } - public function test_groupDelete1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupDel ("MODULE", "group"); - } + public function test_groupDelete1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupDel("MODULE", "group"); + } ///////////////////// // GROUPMEMBER // ///////////////////// - public function test_groupmemberCreate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberAdd ("MODULE", "group", "userKnown"); - } + public function test_groupmemberCreate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberAdd("MODULE", "group", "userKnown"); + } - public function test_groupmemberCreate2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberAdd ("MODULE", "group2", "userKnown"); - $this->assertSame ("1", $res); - } + public function test_groupmemberCreate2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberAdd("MODULE", "group2", "userKnown"); + $this->assertSame("1", $res); + } - public function test_groupmemberDelete1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberDel ("MODULE", "group","userKnown"); - } + public function test_groupmemberDelete1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberDel("MODULE", "group", "userKnown"); + } - public function test_groupmemberReadGroup1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberReadGroup ("MODULE", "group"); - } + public function test_groupmemberReadGroup1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberReadGroup("MODULE", "group"); + } - public function test_groupmemberReadGroup2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberReadGroup ("MODULE", "group2"); - $this->assertSame (array (array ("user"=>"userKnown")), $res); - } + public function test_groupmemberReadGroup2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberReadGroup("MODULE", "group2"); + $this->assertSame(array (array ("user" => "userKnown")), $res); + } - public function test_groupmemberReadUser1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberReadUser ("MODULE", "userKnown"); - $this->assertSame (array (1=>"group2"), $res); - } + public function test_groupmemberReadUser1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberReadUser("MODULE", "userKnown"); + $this->assertSame(array (1 => "group2"), $res); + } //////////////// // RIGHTS // //////////////// - public function test_rightCreate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->rightAdd ("MODULE", "group2","/object2", "RW"); - $this->assertSame ("1", $res); - } + public function test_rightCreate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->rightAdd("MODULE", "group2", "/object2", "RW"); + $this->assertSame("1", $res); + } - public function test_rightUpdate1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->rightUpdate ("MODULE", "group2", "/object2", "RO"); - $this->assertSame (1, $res); - } + public function test_rightUpdate1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->rightUpdate("MODULE", "group2", "/object2", "RO"); + $this->assertSame(1, $res); + } - public function test_rightDelete1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The object doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->rightDel ("MODULE", "group2", "/object"); - } + public function test_rightDelete1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The object doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->rightDel("MODULE", "group2", "/object"); + } ////////////////////////////////////////////// // CLEANING DATABASE : REMOVING ENTRIES // ////////////////////////////////////////////// - public function test_deleteGroupmember2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberDel ("MODULE", "group2","userKnown"); - $this->assertSame (1, $res); - } + public function test_deleteGroupmember2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberDel("MODULE", "group2", "userKnown"); + $this->assertSame(1, $res); + } - public function test_deleteObject2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectDel ("MODULE", "/object2"); - $this->assertSame (1, $res); - } + public function test_deleteObject2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectDel("MODULE", "/object2"); + $this->assertSame(1, $res); + } - public function test_deleteGroup2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupDel ("MODULE", "group2"); - $this->assertSame (1, $res); - } + public function test_deleteGroup2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupDel("MODULE", "group2"); + $this->assertSame(1, $res); + } ///////////////////// // USER RIGHTS // ///////////////////// - public function test_userrightsget1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // Create infos to tests the userrightsget method - $authz->objectAdd ("MODULE1", "/"); - $authz->objectAdd ("MODULE1", "/rep1"); - $authz->objectAdd ("MODULE1", "/rep1/rep2"); - $authz->objectAdd ("MODULE1", "/rep1/rep2/rep3"); - $authz->objectAdd ("MODULE2", "/"); - $authz->objectAdd ("MODULE2", "/rep1"); - $authz->objectAdd ("MODULE2", "/rep1/rep2"); - $authz->objectAdd ("MODULE2", "/rep1/rep2/rep3"); - $authz->groupAdd ("MODULE1", "group1"); - $authz->groupAdd ("MODULE1", "group2"); - $authz->groupAdd ("MODULE1", "group3"); - $authz->groupAdd ("MODULE2", "group3"); - $authz->groupmemberAdd ("MODULE1", "group2", "userKnown"); - $authz->groupmemberAdd ("MODULE1", "group3", "userKnown"); - $authz->groupmemberAdd ("MODULE2", "group3", "userKnown"); - $authz->rightAdd ("MODULE1", "group2","/rep1/rep2","RW"); - $authz->rightAdd ("MODULE1", "group3","/rep1/rep2","RO"); + public function test_userrightsget1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // Create infos to tests the userrightsget method + $authz->objectAdd("MODULE1", "/"); + $authz->objectAdd("MODULE1", "/rep1"); + $authz->objectAdd("MODULE1", "/rep1/rep2"); + $authz->objectAdd("MODULE1", "/rep1/rep2/rep3"); + $authz->objectAdd("MODULE2", "/"); + $authz->objectAdd("MODULE2", "/rep1"); + $authz->objectAdd("MODULE2", "/rep1/rep2"); + $authz->objectAdd("MODULE2", "/rep1/rep2/rep3"); + $authz->groupAdd("MODULE1", "group1"); + $authz->groupAdd("MODULE1", "group2"); + $authz->groupAdd("MODULE1", "group3"); + $authz->groupAdd("MODULE2", "group3"); + $authz->groupmemberAdd("MODULE1", "group2", "userKnown"); + $authz->groupmemberAdd("MODULE1", "group3", "userKnown"); + $authz->groupmemberAdd("MODULE2", "group3", "userKnown"); + $authz->rightAdd("MODULE1", "group2", "/rep1/rep2", "RW"); + $authz->rightAdd("MODULE1", "group3", "/rep1/rep2", "RO"); - $res = $authz->userrightsget ("MODULE1", "userKnown"); - $this->assertSame (array ("/rep1/rep2"=>"RW"), $res); - } + $res = $authz->userrightsget("MODULE1", "userKnown"); + $this->assertSame(array ("/rep1/rep2" => "RW"), $res); + } - public function test_allow1 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function test_allow1() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow2 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $authz->rightAdd ("MODULE1", "group2","/","RW"); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function test_allow2() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $authz->rightAdd("MODULE1", "group2", "/", "RW"); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow3 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $authz->rightAdd ("MODULE1", "group2","/rep1","RO"); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function test_allow3() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $authz->rightAdd("MODULE1", "group2", "/rep1", "RO"); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow4 () - { - $authz = new Authzgroups (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2/rep3"); - $this->assertSame ("NO", $res); - } + public function test_allow4() + { + $authz = new Authzgroups(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2/rep3"); + $this->assertSame("NO", $res); + } } diff --git a/Tests/AuthzgroupsooTest.php b/Tests/AuthzgroupsooTest.php index 641ceaf..3bc1c73 100644 --- a/Tests/AuthzgroupsooTest.php +++ b/Tests/AuthzgroupsooTest.php @@ -1,4 +1,5 @@ @@ -12,320 +13,396 @@ use Domframework\Authzgroupsoo; /** Test the Authzgroupsoo.php file */ class AuthzgroupsooTest extends \PHPUnit_Framework_TestCase { - private $dbconfig = array ( + private $dbconfig = array ( "dsn" => "sqlite:/tmp/databaseAuthzGroupsoo.db", "username" => null, "password" => null, "driver_options" => null, "tableprefix" => "", - ); - public function test_Initialization () - { - if (file_exists ("/tmp/databaseAuthzGroupsoo.db")) - unlink ("/tmp/databaseAuthzGroupsoo.db"); - } + ); + public function testInitialization() + { + if (file_exists("/tmp/databaseAuthzGroupsoo.db")) { + unlink("/tmp/databaseAuthzGroupsoo.db"); + } + } - public function test_createTables1 () - { - $authz = new Authzgroupsoo (); - $this->setExpectedException ("Exception"); - $authz->createTables (); - } + public function testCreateTables1() + { + $authz = new Authzgroupsoo(); + $this->setExpectedException("Exception"); + $authz->createTables(); + } - public function test_connect () - { - // Must use the model to create the database structure as there is no - // creation of tables in controller - $authz = new Authzgroupsoo (); - $res = $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $this->assertSame (true, $res); - } + public function testConnect() + { + // Must use the model to create the database structure as there is no + // creation of tables in controller + $authz = new Authzgroupsoo(); + $res = $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $this->assertSame(true, $res); + } - public function test_createTables2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->createTables (); - $this->assertSame (true, $res); - } + public function testCreateTables2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->createTables(); + $this->assertSame(true, $res); + } //////////////// // OBJECT // //////////////// - public function test_objectCreate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectAdd ("MODULE", "/object"); - $this->assertSame ("1", $res); - } + public function testObjectCreate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectAdd("MODULE", "/object"); + $this->assertSame("1", $res); + } - public function test_objectUpdate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectUpdate ("MODULE", "/object", "/object2"); - $this->assertSame (1, $res); - } + public function testObjectUpdate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectUpdate("MODULE", "/object", "/object2"); + $this->assertSame(1, $res); + } - public function test_objectDelete1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The object was renamed and is not available - $this->setExpectedException ("Exception"); - $res = $authz->objectDel ("MODULE", "/object"); - } + public function testObjectDelete1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The object was renamed and is not available + $this->setExpectedException("Exception"); + $res = $authz->objectDel("MODULE", "/object"); + } //////////////// // GROUPS // //////////////// - public function test_groupCreate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupAdd ("MODULE", "group"); - $this->assertSame ("1", $res); - } + public function testGroupCreate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupAdd("MODULE", "group"); + $this->assertSame("1", $res); + } - public function test_groupUpdate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupUpdate ("MODULE", "group", "group2"); - $this->assertSame (1, $res); - } + public function testGroupUpdate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupUpdate("MODULE", "group", "group2"); + $this->assertSame(1, $res); + } - public function test_groupDelete1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupDel ("MODULE", "group"); - } + public function testGroupDelete1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupDel("MODULE", "group"); + } ///////////////////// // GROUPMEMBER // ///////////////////// - public function test_groupmemberCreate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberAdd ("MODULE", "group", "userKnown"); - } + public function testGroupmemberCreate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberAdd("MODULE", "group", "userKnown"); + } - public function test_groupmemberCreate2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberAdd ("MODULE", "group2", "userKnown"); - $this->assertSame ("1", $res); - } + public function testGroupmemberCreate2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberAdd("MODULE", "group2", "userKnown"); + $this->assertSame("1", $res); + } - public function test_groupmemberDelete1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberDel ("MODULE", "group","userKnown"); - } + public function testGroupmemberDelete1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberDel("MODULE", "group", "userKnown"); + } - public function test_groupmemberReadGroup1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The group doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->groupmemberReadGroup ("MODULE", "group"); - } + public function testGroupmemberReadGroup1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The group doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->groupmemberReadGroup("MODULE", "group"); + } - public function test_groupmemberReadGroup2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberReadGroup ("MODULE", "group2"); - $this->assertSame (array (array ("user"=>"userKnown")), $res); - } + public function testGroupmemberReadGroup2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberReadGroup("MODULE", "group2"); + $this->assertSame(array (array ("user" => "userKnown")), $res); + } - public function test_groupmemberReadUser1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberReadUser ("MODULE", "userKnown"); - $this->assertSame (array (1=>"group2"), $res); - } + public function testGroupmemberReadUser1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberReadUser("MODULE", "userKnown"); + $this->assertSame(array (1 => "group2"), $res); + } //////////////// // RIGHTS // //////////////// - public function test_rightCreate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->rightAdd ("MODULE", "group2","/object2", "RW"); - $this->assertSame ("1", $res); - } + public function testRightCreate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->rightAdd("MODULE", "group2", "/object2", "RW"); + $this->assertSame("1", $res); + } - public function test_rightUpdate1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->rightUpdate ("MODULE", "group2", "/object2", "RO"); - $this->assertSame (1, $res); - } + public function testRightUpdate1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->rightUpdate("MODULE", "group2", "/object2", "RO"); + $this->assertSame(1, $res); + } - public function test_rightDelete1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // The object doesn't exists - $this->setExpectedException ("Exception"); - $res = $authz->rightDel ("MODULE", "group2", "/object"); - } + public function testRightDelete1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // The object doesn't exists + $this->setExpectedException("Exception"); + $res = $authz->rightDel("MODULE", "group2", "/object"); + } ////////////////////////////////////////////// // CLEANING DATABASE : REMOVING ENTRIES // ////////////////////////////////////////////// - public function test_deleteGroupmember2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupmemberDel ("MODULE", "group2","userKnown"); - $this->assertSame (1, $res); - } + public function testDeleteGroupmember2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupmemberDel("MODULE", "group2", "userKnown"); + $this->assertSame(1, $res); + } - public function test_deleteObject2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->objectDel ("MODULE", "/object2"); - $this->assertSame (1, $res); - } + public function testDeleteObject2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->objectDel("MODULE", "/object2"); + $this->assertSame(1, $res); + } - public function test_deleteGroup2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->groupDel ("MODULE", "group2"); - $this->assertSame (1, $res); - } + public function testDeleteGroup2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->groupDel("MODULE", "group2"); + $this->assertSame(1, $res); + } ///////////////////// // USER RIGHTS // ///////////////////// - public function test_userrightsget1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - // Create infos to tests the userrightsget method - $authz->objectAdd ("MODULE1", "/"); - $authz->objectAdd ("MODULE1", "/rep1"); - $authz->objectAdd ("MODULE1", "/rep1/rep2"); - $authz->objectAdd ("MODULE1", "/rep1/rep2/rep3"); - $authz->objectAdd ("MODULE2", "/"); - $authz->objectAdd ("MODULE2", "/rep1"); - $authz->objectAdd ("MODULE2", "/rep1/rep2"); - $authz->objectAdd ("MODULE2", "/rep1/rep2/rep3"); - $authz->groupAdd ("MODULE1", "group1"); - $authz->groupAdd ("MODULE1", "group2"); - $authz->groupAdd ("MODULE1", "group3"); - $authz->groupAdd ("MODULE2", "group3"); - $authz->groupmemberAdd ("MODULE1", "group2", "userKnown"); - $authz->groupmemberAdd ("MODULE1", "group3", "userKnown"); - $authz->groupmemberAdd ("MODULE2", "group3", "userKnown"); - $authz->rightAdd ("MODULE1", "group2","/rep1/rep2","RW"); - $authz->rightAdd ("MODULE1", "group3","/rep1/rep2","RO"); + public function testUserrightsget1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + // Create infos to tests the userrightsget method + $authz->objectAdd("MODULE1", "/"); + $authz->objectAdd("MODULE1", "/rep1"); + $authz->objectAdd("MODULE1", "/rep1/rep2"); + $authz->objectAdd("MODULE1", "/rep1/rep2/rep3"); + $authz->objectAdd("MODULE2", "/"); + $authz->objectAdd("MODULE2", "/rep1"); + $authz->objectAdd("MODULE2", "/rep1/rep2"); + $authz->objectAdd("MODULE2", "/rep1/rep2/rep3"); + $authz->groupAdd("MODULE1", "group1"); + $authz->groupAdd("MODULE1", "group2"); + $authz->groupAdd("MODULE1", "group3"); + $authz->groupAdd("MODULE2", "group3"); + $authz->groupmemberAdd("MODULE1", "group2", "userKnown"); + $authz->groupmemberAdd("MODULE1", "group3", "userKnown"); + $authz->groupmemberAdd("MODULE2", "group3", "userKnown"); + $authz->rightAdd("MODULE1", "group2", "/rep1/rep2", "RW"); + $authz->rightAdd("MODULE1", "group3", "/rep1/rep2", "RO"); - $res = $authz->userrightsget ("MODULE1", "userKnown"); - $this->assertSame (array ("/rep1/rep2"=>"RW"), $res); - } + $res = $authz->userrightsget("MODULE1", "userKnown"); + $this->assertSame(array ("/rep1/rep2" => "RW"), $res); + } - public function test_allow1 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function testAllow1() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow2 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $authz->rightAdd ("MODULE1", "group2","/","RW"); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function testAllow2() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $authz->rightAdd("MODULE1", "group2", "/", "RW"); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow3 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $authz->rightAdd ("MODULE1", "group2","/rep1","RO"); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2"); - $this->assertSame ("RW", $res); - } + public function testAllow3() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $authz->rightAdd("MODULE1", "group2", "/rep1", "RO"); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2"); + $this->assertSame("RW", $res); + } - public function test_allow4 () - { - $authz = new Authzgroupsoo (); - $authz->connect ($this->dbconfig["dsn"], $this->dbconfig["username"], - $this->dbconfig["password"], - $this->dbconfig["driver_options"]); - $res = $authz->allow ("MODULE1", "userKnown", "/rep1/rep2/rep3"); - $this->assertSame ("NO", $res); - } + public function testAllow4() + { + $authz = new Authzgroupsoo(); + $authz->connect( + $this->dbconfig["dsn"], + $this->dbconfig["username"], + $this->dbconfig["password"], + $this->dbconfig["driver_options"] + ); + $res = $authz->allow("MODULE1", "userKnown", "/rep1/rep2/rep3"); + $this->assertSame("NO", $res); + } } diff --git a/Tests/CachefileTest.php b/Tests/CachefileTest.php index c7236af..6eb1a70 100644 --- a/Tests/CachefileTest.php +++ b/Tests/CachefileTest.php @@ -1,4 +1,5 @@ @@ -12,84 +13,83 @@ use Domframework\Cachefile; /** Test the Cachefile.php file */ class CachefileTest extends \PHPUnit_Framework_TestCase { - public function testInit () - { - // Removing the cache file if it previously exists - exec ("rm -rf /tmp/cache"); - } + public function testInit() + { + // Removing the cache file if it previously exists + exec("rm -rf /tmp/cache"); + } // Unknown cache file : return FALSE - public function testRead1 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->read ("id"); - $this->assertFalse ($res); - } + public function testRead1() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->read("id"); + $this->assertFalse($res); + } // Write in cache file - public function testWrite1 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->write ("id","DATA_TO_STORE", 3); - $this->assertTrue ($res); - } + public function testWrite1() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->write("id", "DATA_TO_STORE", 3); + $this->assertTrue($res); + } // Previous cache file : return DATA_TO_STORE - public function testRead2 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->read ("id"); - $this->assertSame ("DATA_TO_STORE", $res); - } + public function testRead2() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->read("id"); + $this->assertSame("DATA_TO_STORE", $res); + } // Sleep 4s to expire the cache - public function testWait1 () - { - sleep (4); - } + public function testWait1() + { + sleep(4); + } // Previous cache file but expired : return false - public function testRead3 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->read ("id"); - $this->assertFalse ($res); - } + public function testRead3() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->read("id"); + $this->assertFalse($res); + } // Write in cache file - public function testWrite2 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->write ("id","DATA_TO_STORE", 30); - $this->assertTrue ($res); - } + public function testWrite2() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->write("id", "DATA_TO_STORE", 30); + $this->assertTrue($res); + } // Create stale lock - public function testLock1 () - { - touch ("/tmp/cache/".sha1 ("id").".lock"); - } + public function testLock1() + { + touch("/tmp/cache/" . sha1("id") . ".lock"); + } // Previous cache in time file but lock : return content after lock timeout // This test takes 10s to wait the lock which will never be released - public function testRead4 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->read ("id"); - $this->assertSame ("DATA_TO_STORE", $res); - } + public function testRead4() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->read("id"); + $this->assertSame("DATA_TO_STORE", $res); + } - public function testDel1 () - { - $c = new Cachefile (); - $c->directory = "/tmp/cache"; - $res = $c->delete ("id"); - } + public function testDel1() + { + $c = new Cachefile(); + $c->directory = "/tmp/cache"; + $res = $c->delete("id"); + } } - diff --git a/Tests/CertificationauthorityTest.php b/Tests/CertificationauthorityTest.php index 9d70ead..d5e2e70 100644 --- a/Tests/CertificationauthorityTest.php +++ b/Tests/CertificationauthorityTest.php @@ -1,4 +1,5 @@ @@ -13,142 +14,163 @@ use Domframework\Certificationauthority; */ class CertificationauthorityTest extends \PHPUnit_Framework_TestCase { - public function test_createCA_1 () - { - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = explode ("\n", $certificationauthority->caCert ()); - $caKey = explode ("\n", $certificationauthority->caKey ()); - $res = $caCert[0] . $caKey[0]; - $this->assertSame ($res, - "-----BEGIN CERTIFICATE----------BEGIN PRIVATE KEY-----"); - } + public function test_createCA_1() + { + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = explode("\n", $certificationauthority->caCert()); + $caKey = explode("\n", $certificationauthority->caKey()); + $res = $caCert[0] . $caKey[0]; + $this->assertSame( + $res, + "-----BEGIN CERTIFICATE----------BEGIN PRIVATE KEY-----" + ); + } - public function test_createCA_2 () - { - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - file_put_contents ("/tmp/test_createCA_2", $caCert); - exec ("openssl x509 -in - -text -noout < /tmp/test_createCA_2", $output); - $res = preg_match ("# CA:TRUE#", - implode ("\n", $output)); - unlink ("/tmp/test_createCA_2"); - $this->assertSame ($res, 1); - } + public function test_createCA_2() + { + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + file_put_contents("/tmp/test_createCA_2", $caCert); + exec("openssl x509 -in - -text -noout < /tmp/test_createCA_2", $output); + $res = preg_match( + "# CA:TRUE#", + implode("\n", $output) + ); + unlink("/tmp/test_createCA_2"); + $this->assertSame($res, 1); + } - public function test_createPK_1 () - { - $certificationauthority = new Certificationauthority (); - $privateKey = $certificationauthority->createPrivateKey () -> privateKey (); - $privateKey = explode ("\n", $privateKey); - $this->assertSame ($privateKey[0], "-----BEGIN PRIVATE KEY-----"); - } + public function test_createPK_1() + { + $certificationauthority = new Certificationauthority(); + $privateKey = $certificationauthority->createPrivateKey() -> privateKey(); + $privateKey = explode("\n", $privateKey); + $this->assertSame($privateKey[0], "-----BEGIN PRIVATE KEY-----"); + } - public function test_createCSR_1 () - { - $certificationauthority = new Certificationauthority (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $csr = explode ("\n", $csr); - $this->assertSame ($csr[0], "-----BEGIN CERTIFICATE REQUEST-----"); - } + public function test_createCSR_1() + { + $certificationauthority = new Certificationauthority(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $csr = explode("\n", $csr); + $this->assertSame($csr[0], "-----BEGIN CERTIFICATE REQUEST-----"); + } - public function test_signCSR_1 () - { - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey); - $cert = explode ("\n", $cert); - $this->assertSame ($cert[0], "-----BEGIN CERTIFICATE-----"); - } + public function test_signCSR_1() + { + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $cert = $certificationauthority->signCSR($csr, $caCert, $caKey); + $cert = explode("\n", $cert); + $this->assertSame($cert[0], "-----BEGIN CERTIFICATE-----"); + } - public function test_signCSR_2 () - { - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey); - file_put_contents ("/tmp/test_signCSR_2", $cert); - exec ("openssl x509 -in - -text -noout < /tmp/test_signCSR_2", $output); - $res = preg_match ("#Subject: C = FR, .+ CN = CSR#", - implode ("\n", $output)); - unlink ("/tmp/test_signCSR_2"); - $this->assertSame ($res, 1); - } + public function test_signCSR_2() + { + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $cert = $certificationauthority->signCSR($csr, $caCert, $caKey); + file_put_contents("/tmp/test_signCSR_2", $cert); + exec("openssl x509 -in - -text -noout < /tmp/test_signCSR_2", $output); + $res = preg_match( + "#Subject: C = FR, .+ CN = CSR#", + implode("\n", $output) + ); + unlink("/tmp/test_signCSR_2"); + $this->assertSame($res, 1); + } - public function test_signCSR_3 () - { - // Check if generated cert X509v3 Extended Key Usage are valid - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey); - file_put_contents ("/tmp/test_signCSR_3", $cert); - exec ("openssl x509 -in - -text -noout < /tmp/test_signCSR_3", $output); - $res = preg_match ( - "#TLS Web Server Authentication, TLS Web Client Authentication#", - implode ("\n", $output)); - unlink ("/tmp/test_signCSR_3"); - $this->assertSame ($res, 1); - } + public function test_signCSR_3() + { + // Check if generated cert X509v3 Extended Key Usage are valid + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $cert = $certificationauthority->signCSR($csr, $caCert, $caKey); + file_put_contents("/tmp/test_signCSR_3", $cert); + exec("openssl x509 -in - -text -noout < /tmp/test_signCSR_3", $output); + $res = preg_match( + "#TLS Web Server Authentication, TLS Web Client Authentication#", + implode("\n", $output) + ); + unlink("/tmp/test_signCSR_3"); + $this->assertSame($res, 1); + } - public function test_signCSR_4 () - { - // Check if generated cert issuer name is valid - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey); - file_put_contents ("/tmp/test_signCSR_4", $cert); - exec ("openssl x509 -in - -text -noout < /tmp/test_signCSR_4", $output); - $res = preg_match ("#Issuer: C = FR, O = FOURNIER38, CN = CATEST#", - implode ("\n", $output)); - unlink ("/tmp/test_signCSR_4"); - $this->assertSame ($res, 1); - } + public function test_signCSR_4() + { + // Check if generated cert issuer name is valid + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $cert = $certificationauthority->signCSR($csr, $caCert, $caKey); + file_put_contents("/tmp/test_signCSR_4", $cert); + exec("openssl x509 -in - -text -noout < /tmp/test_signCSR_4", $output); + $res = preg_match( + "#Issuer: C = FR, O = FOURNIER38, CN = CATEST#", + implode("\n", $output) + ); + unlink("/tmp/test_signCSR_4"); + $this->assertSame($res, 1); + } - public function test_signCSR_5 () - { - // Check if generated cert is not tagged CA - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", "CSR"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey); - file_put_contents ("/tmp/test_signCSR_5", $cert); - exec ("openssl x509 -in - -text -noout < /tmp/test_signCSR_5", $output); - $res = preg_match ("# CA:FALSE#", - implode ("\n", $output)); - unlink ("/tmp/test_signCSR_5"); - $this->assertSame ($res, 1); - } + public function test_signCSR_5() + { + // Check if generated cert is not tagged CA + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR("FR", "FOURNIER38", "CSR"); + $cert = $certificationauthority->signCSR($csr, $caCert, $caKey); + file_put_contents("/tmp/test_signCSR_5", $cert); + exec("openssl x509 -in - -text -noout < /tmp/test_signCSR_5", $output); + $res = preg_match( + "# CA:FALSE#", + implode("\n", $output) + ); + unlink("/tmp/test_signCSR_5"); + $this->assertSame($res, 1); + } - public function test_signCSR_6 () - { - // Check if generated cert has Alternative Names - $certificationauthority = new Certificationauthority (); - $certificationauthority->createCA ("FR", "FOURNIER38", "CATEST"); - $caCert = $certificationauthority->caCert (); - $caKey = $certificationauthority->caKey (); - $csr = $certificationauthority->createCSR ("FR", "FOURNIER38", - "CSR.fournier38.fr"); - $cert = $certificationauthority->signCSR ($csr, $caCert, $caKey, null, - ["ALT1.example.com","ALT2.example.com"]); - file_put_contents ("/tmp/test_signCSR_6", $cert); - exec ("openssl x509 -in - -text -noout < /tmp/test_signCSR_6", $output); - $res = preg_match ("#DNS:CSR.fournier38.fr, DNS:ALT1.example.com, DNS:ALT#", - implode ("\n", $output)); - unlink ("/tmp/test_signCSR_6"); - $this->assertSame ($res, 1); - } + public function test_signCSR_6() + { + // Check if generated cert has Alternative Names + $certificationauthority = new Certificationauthority(); + $certificationauthority->createCA("FR", "FOURNIER38", "CATEST"); + $caCert = $certificationauthority->caCert(); + $caKey = $certificationauthority->caKey(); + $csr = $certificationauthority->createCSR( + "FR", + "FOURNIER38", + "CSR.fournier38.fr" + ); + $cert = $certificationauthority->signCSR( + $csr, + $caCert, + $caKey, + null, + ["ALT1.example.com","ALT2.example.com"] + ); + file_put_contents("/tmp/test_signCSR_6", $cert); + exec("openssl x509 -in - -text -noout < /tmp/test_signCSR_6", $output); + $res = preg_match( + "#DNS:CSR.fournier38.fr, DNS:ALT1.example.com, DNS:ALT#", + implode("\n", $output) + ); + unlink("/tmp/test_signCSR_6"); + $this->assertSame($res, 1); + } } diff --git a/Tests/ConfigTest.php b/Tests/ConfigTest.php index 85e1ecb..96eb339 100644 --- a/Tests/ConfigTest.php +++ b/Tests/ConfigTest.php @@ -1,4 +1,5 @@ @@ -12,252 +13,252 @@ use Domframework\Config; /** Test the Config.php file */ class ConfigTest extends \PHPUnit_Framework_TestCase { + public function testExternFile() + { + if (file_exists("/tmp/testconf.php")) { + unlink("/tmp/testconf.php"); + } + } - public function test_ExternFile () - { - if (file_exists ("/tmp/testconf.php")) - unlink ("/tmp/testconf.php"); - } + public function testParams1() + { + $c = new Config(); + $res = $c->params(); + $this->assertSame(array (), $res); + } - public function test_params1 () - { - $c = new Config (); - $res = $c->params (); - $this->assertSame (array (), $res); - } + public function testGet1() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + $c->default = array ( + "database" => array ( + "dsn" => null, + "username" => null, + "password" => null, + "driver_options" => null, + "tableprefix" => "")); + $res = $c->get("database"); + $this->assertSame(array ( + "dsn" => null, + "username" => null, + "password" => null, + "driver_options" => null, + "tableprefix" => ""), $res); + } - public function testGet1 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "username"=>null, - "password"=>null, - "driver_options"=>null, - "tableprefix"=>"")); - $res = $c->get ("database"); - $this->assertSame (array ( - "dsn" => null, - "username" => null, - "password" => null, - "driver_options" => null, - "tableprefix" => ""), $res); - } + public function testSet1() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $res = $c->set("database", array ("dsn" => 1,"tableprefix" => 3)); + $this->assertSame(true, $res); + } - public function testSet1 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $res = $c->set ("database", array ("dsn"=>1,"tableprefix"=>3)); - $this->assertSame (true, $res); - } - - public function testGet2 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $res = $c->get ("database"); - $this->assertSame (array ( - "dsn" => 1, - "tableprefix" => 3), $res); - } + public function testGet2() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $res = $c->get("database"); + $this->assertSame(array ( + "dsn" => 1, + "tableprefix" => 3), $res); + } /** Can't create file */ - public function testGet3 () - { - $c = new Config (); - $c->confFile = "/tmp/1/2.3/dd/testconf.php"; - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $this->setExpectedException ("Exception"); - $res = $c->get ("database"); - } + public function testGet3() + { + $c = new Config(); + $c->confFile = "/tmp/1/2.3/dd/testconf.php"; + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $this->setExpectedException("Exception"); + $res = $c->get("database"); + } /** Can't read the file */ - public function testGet4 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0222); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $this->setExpectedException ("Exception"); - $res = $c->get ("database"); - } + public function testGet4() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0222); + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $this->setExpectedException("Exception"); + $res = $c->get("database"); + } /** File non exists and can not be created */ - public function testSet2 () - { - $c = new Config (); - $c->confFile = "/tmp/1/2.3/dd/testconf.php"; - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $this->setExpectedException ("Exception"); - $res = $c->set ("database", array ("dsn"=>1,"tableprefix"=>3)); - } + public function testSet2() + { + $c = new Config(); + $c->confFile = "/tmp/1/2.3/dd/testconf.php"; + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $this->setExpectedException("Exception"); + $res = $c->set("database", array ("dsn" => 1,"tableprefix" => 3)); + } /** Can't read the file */ - public function testSet3 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0222); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $this->setExpectedException ("Exception"); - $res = $c->set ("database", array ("dsn"=>1,"tableprefix"=>3)); - } + public function testSet3() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0222); + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $this->setExpectedException("Exception"); + $res = $c->set("database", array ("dsn" => 1,"tableprefix" => 3)); + } /** Can't write the file */ - public function testSet4 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0444); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "tableprefix"=>"")); - $this->setExpectedException ("Exception"); - $res = $c->set ("database", array ("dsn"=>1,"tableprefix"=>3)); - } + public function testSet4() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0444); + $c->default = array ( + "database" => array ( + "dsn" => null, + "tableprefix" => "")); + $this->setExpectedException("Exception"); + $res = $c->set("database", array ("dsn" => 1,"tableprefix" => 3)); + } /** Save TRUE/FALSE/NULL/String values */ - public function testSet5 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0666); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "user"=>null, - "password"=>null, - "tableprefix"=>"")); - $res = $c->set ("database", array ("dsn"=>true, "user"=>null, - "password"=>"text", - "tableprefix"=>false)); - $this->assertSame (true, $res); - } + public function testSet5() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0666); + $c->default = array ( + "database" => array ( + "dsn" => null, + "user" => null, + "password" => null, + "tableprefix" => "")); + $res = $c->set("database", array ("dsn" => true, "user" => null, + "password" => "text", + "tableprefix" => false)); + $this->assertSame(true, $res); + } - public function testGet6 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0666); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "user"=>null, - "password"=>null, - "tableprefix"=>""), - "servers"=>array ( - "not configured"=>array ( - "type"=>"bind", - "username"=>"", + public function testGet6() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0666); + $c->default = array ( + "database" => array ( + "dsn" => null, + "user" => null, + "password" => null, + "tableprefix" => ""), + "servers" => array ( + "not configured" => array ( + "type" => "bind", + "username" => "", ), ) ); - $res = $c->get ("servers"); - $this->assertSame ($res, array ("not configured"=>array ( - "type"=>"bind", - "username"=>"", + $res = $c->get("servers"); + $this->assertSame($res, array ("not configured" => array ( + "type" => "bind", + "username" => "", ))); - } + } - public function testSet7 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0666); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "user"=>null, - "password"=>null, - "tableprefix"=>""), - "servers"=>array ( - "not configured"=>array ( - "type"=>"bind", - "username"=>"", + public function testSet7() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0666); + $c->default = array ( + "database" => array ( + "dsn" => null, + "user" => null, + "password" => null, + "tableprefix" => ""), + "servers" => array ( + "not configured" => array ( + "type" => "bind", + "username" => "", ), ) ); - $res = $c->set ("servers", array ( - "127.0.0.1"=>array ( - "type"=>"BIND", - "username"=>"toto", + $res = $c->set("servers", array ( + "127.0.0.1" => array ( + "type" => "BIND", + "username" => "toto", ))); - } - public function testGet7 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0666); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "user"=>null, - "password"=>null, - "tableprefix"=>""), - "servers"=>array ( - "not configured"=>array ( - "type"=>"bind", - "username"=>"", + } + public function testGet7() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0666); + $c->default = array ( + "database" => array ( + "dsn" => null, + "user" => null, + "password" => null, + "tableprefix" => ""), + "servers" => array ( + "not configured" => array ( + "type" => "bind", + "username" => "", ), ) ); - $res = $c->get ("servers"); - $this->assertSame ($res, array ( - "127.0.0.1"=>array ( - "type"=>"BIND", - "username"=>"toto", + $res = $c->get("servers"); + $this->assertSame($res, array ( + "127.0.0.1" => array ( + "type" => "BIND", + "username" => "toto", ))); - } + } - public function testGet8 () - { - $c = new Config (); - $c->confFile = "/tmp/testconf.php"; - chmod ("/tmp/testconf.php", 0666); - $c->default = array ( - "database"=>array ( - "dsn"=>null, - "user"=>null, - "password"=>null, - "tableprefix"=>""), - "servers"=>array ( - "not configured"=>array ( - "type"=>"bind", - "username"=>"", - "password"=>"", + public function testGet8() + { + $c = new Config(); + $c->confFile = "/tmp/testconf.php"; + chmod("/tmp/testconf.php", 0666); + $c->default = array ( + "database" => array ( + "dsn" => null, + "user" => null, + "password" => null, + "tableprefix" => ""), + "servers" => array ( + "not configured" => array ( + "type" => "bind", + "username" => "", + "password" => "", ), ) ); - $res = $c->get ("servers"); - $this->assertSame ($res, array ( - "127.0.0.1"=>array ( - "type"=>"BIND", - "username"=>"toto", - "password"=>"", + $res = $c->get("servers"); + $this->assertSame($res, array ( + "127.0.0.1" => array ( + "type" => "BIND", + "username" => "toto", + "password" => "", ))); - } + } } diff --git a/Tests/ConvertTest.php b/Tests/ConvertTest.php index 900ff80..4bc568b 100644 --- a/Tests/ConvertTest.php +++ b/Tests/ConvertTest.php @@ -1,4 +1,5 @@ @@ -12,140 +13,151 @@ use Domframework\Convert; /** Test the Conversion of format */ class ConvertTest extends \PHPUnit_Framework_TestCase { - public function test_convertDate1 () - { - $res = Convert::convertDate ("2017-04-13", "Y-m-d", "d/m/Y"); - $this->assertSame ($res, "13/04/2017"); - } + public function test_convertDate1() + { + $res = Convert::convertDate("2017-04-13", "Y-m-d", "d/m/Y"); + $this->assertSame($res, "13/04/2017"); + } - public function test_convertDate2 () - { - $this->setExpectedException ("Exception"); - $res = Convert::convertDate ("2017-13-33", "Y-m-d", "d/m/Y"); - } + public function test_convertDate2() + { + $this->setExpectedException("Exception"); + $res = Convert::convertDate("2017-13-33", "Y-m-d", "d/m/Y"); + } - public function test_convertDate3 () - { - $res = Convert::convertDate ("2017-13-33", "Y-m-d", "d/m/Y", false); - $this->assertSame ($res, "2017-13-33"); - } + public function test_convertDate3() + { + $res = Convert::convertDate("2017-13-33", "Y-m-d", "d/m/Y", false); + $this->assertSame($res, "2017-13-33"); + } - public function test_ucwords_1 () - { - $res = Convert::ucwords (" test yuyu "); - $this->assertSame ($res, " Test Yuyu "); - } + public function test_ucwords_1() + { + $res = Convert::ucwords(" test yuyu "); + $this->assertSame($res, " Test Yuyu "); + } - public function test_ucwords_2 () - { - $res = Convert::ucwords (""); - $this->assertSame ($res, ""); - } + public function test_ucwords_2() + { + $res = Convert::ucwords(""); + $this->assertSame($res, ""); + } - public function test_ucwords_3 () - { - $res = Convert::ucwords ("test"); - $this->assertSame ($res, "Test"); - } + public function test_ucwords_3() + { + $res = Convert::ucwords("test"); + $this->assertSame($res, "Test"); + } - public function test_ucwords_4 () - { - $res = Convert::ucwords ("TEST"); - $this->assertSame ($res, "Test"); - } + public function test_ucwords_4() + { + $res = Convert::ucwords("TEST"); + $this->assertSame($res, "Test"); + } - public function test_ucwords_5 () - { - $res = Convert::ucwords ("édouard étienne"); - $this->assertSame ($res, "Édouard Étienne"); - } + public function test_ucwords_5() + { + $res = Convert::ucwords("édouard étienne"); + $this->assertSame($res, "Édouard Étienne"); + } - public function test_ucwords_6 () - { - $res = Convert::ucwords ("édou-ard d'étienne", " -'"); - $this->assertSame ($res, "Édou-Ard D'Étienne"); - } + public function test_ucwords_6() + { + $res = Convert::ucwords("édou-ard d'étienne", " -'"); + $this->assertSame($res, "Édou-Ard D'Étienne"); + } ///////////////////// // humanSize // ///////////////////// - public function test_humanSize_1 () - { - $res = ""; - for ($i = -8 ; $i <= 8 ; $i++) + public function test_humanSize_1() { - $res .= Convert::humanSize (1.441234 * pow (1000, $i), 2, 1000)."\n"; + $res = ""; + for ($i = -8; $i <= 8; $i++) { + $res .= Convert::humanSize(1.441234 * pow(1000, $i), 2, 1000) . "\n"; + } + $this->assertSame($res, "1.44yB\n1.44zB\n1.44aB\n1.44fB\n1.44pB\n1.44nB\n" . + "1.44uB\n1.44mB\n1.44B\n1.44kB\n1.44MB\n1.44GB\n1.44TB\n1.44PB\n1.44EB\n" . + "1.44ZB\n1.44YB\n"); } - $this->assertSame ($res, "1.44yB\n1.44zB\n1.44aB\n1.44fB\n1.44pB\n1.44nB\n". - "1.44uB\n1.44mB\n1.44B\n1.44kB\n1.44MB\n1.44GB\n1.44TB\n1.44PB\n1.44EB\n". - "1.44ZB\n1.44YB\n"); - } - public function test_humanSize_2 () - { - $res = Convert::humanSize (1441234); - $this->assertSame ($res, "1.44MB"); - } - public function test_humanSize_3 () - { - $res = Convert::humanSize (10441234); - $this->assertSame ($res, "10.44MB"); - } - public function test_humanSize_4 () - { - $res = Convert::humanSize (0.123, 0); - $this->assertSame ($res, "123mB"); - } - public function test_humanSize_5 () - { - $res = Convert::humanSize (0.12345, 2); - $this->assertSame ($res, "123.45mB"); - } + public function test_humanSize_2() + { + $res = Convert::humanSize(1441234); + $this->assertSame($res, "1.44MB"); + } + public function test_humanSize_3() + { + $res = Convert::humanSize(10441234); + $this->assertSame($res, "10.44MB"); + } + public function test_humanSize_4() + { + $res = Convert::humanSize(0.123, 0); + $this->assertSame($res, "123mB"); + } + public function test_humanSize_5() + { + $res = Convert::humanSize(0.12345, 2); + $this->assertSame($res, "123.45mB"); + } - public function test_humanSize_6 () - { - $res = Convert::humanSize (-0.12345, 2); - $this->assertSame ($res, "-123.45mB"); - } + public function test_humanSize_6() + { + $res = Convert::humanSize(-0.12345, 2); + $this->assertSame($res, "-123.45mB"); + } - public function test_humanSize_7 () - { - $res = Convert::humanSize (-12345, 2); - $this->assertSame ($res, "-12.35kB"); - } + public function test_humanSize_7() + { + $res = Convert::humanSize(-12345, 2); + $this->assertSame($res, "-12.35kB"); + } - public function test_humanSize_8 () - { - $res = Convert::humanSize (0, 2); - $this->assertSame ($res, "0.00B"); - } + public function test_humanSize_8() + { + $res = Convert::humanSize(0, 2); + $this->assertSame($res, "0.00B"); + } - public function test_humanSize_error1 () - { - $this->expectException ("Exception", - "convert::humanSize value not numerical : string", 500); - $res = Convert::humanSize ("1441234"); - } + public function test_humanSize_error1() + { + $this->expectException( + "Exception", + "convert::humanSize value not numerical : string", + 500 + ); + $res = Convert::humanSize("1441234"); + } - public function test_humanSize_error2 () - { - $this->expectException ("Exception", - "convert::humanSize decimal not integer : double", 500); - $res = Convert::humanSize (1441234, 0.1); - } + public function test_humanSize_error2() + { + $this->expectException( + "Exception", + "convert::humanSize decimal not integer : double", + 500 + ); + $res = Convert::humanSize(1441234, 0.1); + } - public function test_humanSize_error3 () - { - $this->expectException ("Exception", - "convert::humanSize decimal value negative", 500); - $res = Convert::humanSize (1441234, -1); - } + public function test_humanSize_error3() + { + $this->expectException( + "Exception", + "convert::humanSize decimal value negative", + 500 + ); + $res = Convert::humanSize(1441234, -1); + } - public function test_humanSize_error4 () - { - $this->expectException ("Exception", - "convert::humanSize power value !== 1000 and 1024 : 2000", 500); - $res = Convert::humanSize (1441234, 2, 2000); - } + public function test_humanSize_error4() + { + $this->expectException( + "Exception", + "convert::humanSize power value !== 1000 and 1024 : 2000", + 500 + ); + $res = Convert::humanSize(1441234, 2, 2000); + } } diff --git a/Tests/CsrfTest.php b/Tests/CsrfTest.php index b17836c..6a910f5 100644 --- a/Tests/CsrfTest.php +++ b/Tests/CsrfTest.php @@ -1,4 +1,5 @@ @@ -12,84 +13,90 @@ use Domframework\Csrf; /** Test the Csrf.php file */ class CsrfTest extends \PHPUnit_Framework_TestCase { - public function test_csrf1 () - { - $csrf = new Csrf (); - $res = $csrf->createToken (); - $GLOBALS["CSRFTEST-Token"] = $res; - $this->assertSame (30, strlen ($res)); - } + public function test_csrf1() + { + $csrf = new Csrf(); + $res = $csrf->createToken(); + $GLOBALS["CSRFTEST-Token"] = $res; + $this->assertSame(30, strlen($res)); + } - public function test_csrf2 () - { - $csrf = new Csrf (); - $res = $csrf->createToken (); - $this->assertSame ( - strspn ($res, - "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ") , strlen ($res)); - } + public function test_csrf2() + { + $csrf = new Csrf(); + $res = $csrf->createToken(); + $this->assertSame( + strspn( + $res, + "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ), + strlen($res) + ); + } - public function test_csrf3 () - { - $csrf = new Csrf (); - $this->setExpectedException ("Exception"); - $res = $csrf->checkToken ("NOT VALID TOKEN"); - } + public function test_csrf3() + { + $csrf = new Csrf(); + $this->setExpectedException("Exception"); + $res = $csrf->checkToken("NOT VALID TOKEN"); + } - public function test_csrf4 () - { - $csrf = new Csrf (); - $token = $csrf->createToken (); - $res = $csrf->checkToken ($token); - $this->assertSame (true, $res); - } + public function test_csrf4() + { + $csrf = new Csrf(); + $token = $csrf->createToken(); + $res = $csrf->checkToken($token); + $this->assertSame(true, $res); + } - public function test_csrf5 () - { - $csrf = new Csrf (); - $token = $csrf->createToken (); - $res = $csrf->extendToken ($token); - $this->assertSame (true, $res); - } + public function test_csrf5() + { + $csrf = new Csrf(); + $token = $csrf->createToken(); + $res = $csrf->extendToken($token); + $this->assertSame(true, $res); + } - public function test_csrf6 () - { - $csrf = new Csrf (); - $token = $csrf->createToken (); - $res = $csrf->getToken (); - $this->assertSame ($token, $res); - } + public function test_csrf6() + { + $csrf = new Csrf(); + $token = $csrf->createToken(); + $res = $csrf->getToken(); + $this->assertSame($token, $res); + } - public function test_csrf7 () - { - $csrf = new Csrf (); - $res = $csrf->getToken (); - $this->assertSame (30, strlen ($res)); - } + public function test_csrf7() + { + $csrf = new Csrf(); + $res = $csrf->getToken(); + $this->assertSame(30, strlen($res)); + } - public function test_csrf_multiple_1 () - { - $csrf1 = new Csrf (); - $token1 = $csrf1->createToken (); - $csrf2 = new Csrf (); - $token2 = $csrf2->createToken (); - $this->assertSame (true, - $csrf2->checkToken ($token1) && $csrf2->checkToken ($token2)); - } + public function test_csrf_multiple_1() + { + $csrf1 = new Csrf(); + $token1 = $csrf1->createToken(); + $csrf2 = new Csrf(); + $token2 = $csrf2->createToken(); + $this->assertSame( + true, + $csrf2->checkToken($token1) && $csrf2->checkToken($token2) + ); + } - public function test_csrf_multiple_extend_2 () - { - $csrf = new Csrf (); - $res = $csrf->extendToken ($GLOBALS["CSRFTEST-Token"]); - $this->assertSame (true, $res); - } + public function test_csrf_multiple_extend_2() + { + $csrf = new Csrf(); + $res = $csrf->extendToken($GLOBALS["CSRFTEST-Token"]); + $this->assertSame(true, $res); + } - public function test_csrf_multiple_get () - { - $csrf1 = new Csrf (); - $token1 = $csrf1->createToken (); - $csrf2 = new Csrf (); - $token2 = $csrf2->getToken (); - $this->assertSame ($token1, $token2); - } + public function test_csrf_multiple_get() + { + $csrf1 = new Csrf(); + $token1 = $csrf1->createToken(); + $csrf2 = new Csrf(); + $token2 = $csrf2->getToken(); + $this->assertSame($token1, $token2); + } } diff --git a/Tests/DbjsonTest.php b/Tests/DbjsonTest.php index 36d2ff5..489936e 100644 --- a/Tests/DbjsonTest.php +++ b/Tests/DbjsonTest.php @@ -1,4 +1,5 @@ @@ -12,355 +13,404 @@ use Domframework\Dbjson; /** Test the Dbjson database */ class DbjsonTest extends \PHPUnit_Framework_TestCase { - public function test_insertOne1 () - { - // Document #0 - define ("dbfile", "/tmp/dbjson-".time()); - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->insertOne ("collection", - array ("key1"=>"val1", "key2"=>"val2")); - $this->assertSame ($res, 1); - } + public function test_insertOne1() + { + // Document #0 + define("dbfile", "/tmp/dbjson-" . time()); + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->insertOne( + "collection", + array ("key1" => "val1", "key2" => "val2") + ); + $this->assertSame($res, 1); + } - public function test_insertOne2 () - { - // Document #1 - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->insertOne ("collection", - array ("key1"=>"val1", "key2"=>"val2")); - $this->assertSame ($res, 1); - } + public function test_insertOne2() + { + // Document #1 + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->insertOne( + "collection", + array ("key1" => "val1", "key2" => "val2") + ); + $this->assertSame($res, 1); + } - public function test_insertMany1 () - { - // Error : Invalid array provided (not array of array) - $this->setExpectedException ("Exception"); - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->insertMany ("collection", - array ("key1"=>"val1", "key2"=>"val2")); - } + public function test_insertMany1() + { + // Error : Invalid array provided (not array of array) + $this->setExpectedException("Exception"); + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->insertMany( + "collection", + array ("key1" => "val1", "key2" => "val2") + ); + } - public function test_insertMany2 () - { - // Document #2 and #3 - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->insertMany ("collection", - array (array ("key1"=>"val3", "key2"=>"val2"), - array ("key1"=>"val3", "key2"=>"val4"))); - $this->assertSame ($res, 2); - } + public function test_insertMany2() + { + // Document #2 and #3 + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->insertMany( + "collection", + array (array ("key1" => "val3", "key2" => "val2"), + array ("key1" => "val3", "key2" => "val4")) + ); + $this->assertSame($res, 2); + } - public function test_filter1 () - { - // Return all the keys (filter = array ()) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection", array ()); - $this->assertSame (array_keys ($res), array (0,1,2,3)); - } - public function test_filter2 () - { - // Return the keys where filter = array ("key2"=>"val2")) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection", array ("key2"=>"val2")); - $this->assertSame (array_keys ($res), array (0,1,2)); - } - public function test_filter3 () - { - // Return the keys where filter = array ("key1"=>"val3","key2"=>"val2")) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection", array ("key1"=>"val3", - "key2"=>"val2")); - $this->assertSame (count ($res), 1); - } - public function test_filter4 () - { - // Return the keys where filter = array ("key1"=>array ("val3", "=="), - // "key2"=>array ("val2", "==")) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection",array ("key1"=>array ("val3", "=="), - "key2"=>array ("val2", "=="))); - $this->assertSame (count ($res), 1); - } - public function test_filter5 () - { - // Return the keys where filter = array ("key1"=>array ("val3", "<="), - // "key2"=>array ("val2", "==")) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "=="))); - $this->assertSame (array_keys ($res), array (0,1,2)); - } - public function test_filter6 () - { - // Return the keys where filter = array ("key1"=>array ("val3", "<="), - // "key2"=>array ("val2", ">")) - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->filter ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">"))); - $this->assertSame (count ($res), 1); - } + public function test_filter1() + { + // Return all the keys (filter = array ()) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ()); + $this->assertSame(array_keys($res), array (0,1,2,3)); + } + public function test_filter2() + { + // Return the keys where filter = array ("key2"=>"val2")) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ("key2" => "val2")); + $this->assertSame(array_keys($res), array (0,1,2)); + } + public function test_filter3() + { + // Return the keys where filter = array ("key1"=>"val3","key2"=>"val2")) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ("key1" => "val3", + "key2" => "val2")); + $this->assertSame(count($res), 1); + } + public function test_filter4() + { + // Return the keys where filter = array ("key1"=>array ("val3", "=="), + // "key2"=>array ("val2", "==")) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ("key1" => array ("val3", "=="), + "key2" => array ("val2", "=="))); + $this->assertSame(count($res), 1); + } + public function test_filter5() + { + // Return the keys where filter = array ("key1"=>array ("val3", "<="), + // "key2"=>array ("val2", "==")) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "=="))); + $this->assertSame(array_keys($res), array (0,1,2)); + } + public function test_filter6() + { + // Return the keys where filter = array ("key1"=>array ("val3", "<="), + // "key2"=>array ("val2", ">")) + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->filter("collection", array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">"))); + $this->assertSame(count($res), 1); + } - public function test_find1 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">"))); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val3", - "key2"=>"val4"))); - } - public function test_find2 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">")), - "*"); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val3", - "key2"=>"val4"))); - } - public function test_find3 () - { - // Exception : fields not an array - $this->setExpectedException ("Exception"); - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">")), - "key1"); - } - public function test_find4 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">")), - array ("key1")); - // ["_id"] is random : skip the test - $res = array_values ($res); - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val3"))); - } - public function test_find5 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", ">")), - array ("key1", "key2")); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val3", - "key2"=>"val4"))); - } - public function test_find6 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "==")), - array ("key1", "key2")); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - unset ($res[2]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val1", - "key2"=>"val2"), - 1=>array ("key1"=>"val1", - "key2"=>"val2"), - 2=>array ("key1"=>"val3", - "key2"=>"val2"))); - } - public function test_find7 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "==")), - array ("key2")); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - unset ($res[2]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val2"), - 1=>array ("key2"=>"val2"), - 2=>array ("key2"=>"val2"))); - } - public function test_find8 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "==")), - array ("key2"), 1); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val2"))); - } + public function test_find1() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find("collection", array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">"))); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val3", + "key2" => "val4"))); + } + public function test_find2() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">")), + "*" + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val3", + "key2" => "val4"))); + } + public function test_find3() + { + // Exception : fields not an array + $this->setExpectedException("Exception"); + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">")), + "key1" + ); + } + public function test_find4() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">")), + array ("key1") + ); + // ["_id"] is random : skip the test + $res = array_values($res); + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val3"))); + } + public function test_find5() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", ">")), + array ("key1", "key2") + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val3", + "key2" => "val4"))); + } + public function test_find6() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "==")), + array ("key1", "key2") + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + unset($res[2]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val1", + "key2" => "val2"), + 1 => array ("key1" => "val1", + "key2" => "val2"), + 2 => array ("key1" => "val3", + "key2" => "val2"))); + } + public function test_find7() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "==")), + array ("key2") + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + unset($res[2]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val2"), + 1 => array ("key2" => "val2"), + 2 => array ("key2" => "val2"))); + } + public function test_find8() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "==")), + array ("key2"), + 1 + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val2"))); + } - public function test_deleteOne1 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->deleteOne ("collection", - array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "=="))); - $this->assertSame ($res, 1); - } - public function test_find9 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "==")), - array ("key2")); - $res = array_values ($res); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val2"), - 1=>array ("key2"=>"val2"))); - } + public function test_deleteOne1() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->deleteOne( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", + "==")) + ); + $this->assertSame($res, 1); + } + public function test_find9() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "==")), + array ("key2") + ); + $res = array_values($res); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val2"), + 1 => array ("key2" => "val2"))); + } - public function test_deleteMany1 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->deleteMany ("collection", - array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "=="))); - $this->assertSame ($res, 2); - } - public function test_find10 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->find ("collection", array ("key1"=>array ("val3", "<="), - "key2"=>array ("val2", "==")), - array ("key2")); - // ["_id"] is random : skip the test - unset ($res[1]["_id"]); - unset ($res[2]["_id"]); - $this->assertSame ($res, array ()); - } + public function test_deleteMany1() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->deleteMany( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", + "==")) + ); + $this->assertSame($res, 2); + } + public function test_find10() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->find( + "collection", + array ("key1" => array ("val3", "<="), + "key2" => array ("val2", "==")), + array ("key2") + ); + // ["_id"] is random : skip the test + unset($res[1]["_id"]); + unset($res[2]["_id"]); + $this->assertSame($res, array ()); + } - public function test_find11 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key1"=>"val3", "key2"=>"val4"))); - } + public function test_find11() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key1" => "val3", "key2" => "val4"))); + } - public function test_replace1 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->replace ("collection", array (), array ("key2"=>"val5")); - $this->assertSame ($res, 1); - } - public function test_find12 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val5"))); - } + public function test_replace1() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->replace("collection", array (), array ("key2" => "val5")); + $this->assertSame($res, 1); + } + public function test_find12() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val5"))); + } - public function test_update1 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->update ("collection", array (), array ("key2"=>"val6", - "key5"=>"val5")); - $this->assertSame ($res, 1); - } - public function test_find13 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val6", - "key5"=>"val5"))); - } - public function test_insertOne3 () - { - // Document #4 - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->insertOne ("collection", - array ("key1"=>"val1", "key2"=>"val2")); - $this->assertSame ($res, 1); - } - public function test_find14 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val6", - "key5"=>"val5"), - 1=>array ("key1"=>"val1", - "key2"=>"val2"))); - } + public function test_update1() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->update("collection", array (), array ("key2" => "val6", + "key5" => "val5")); + $this->assertSame($res, 1); + } + public function test_find13() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val6", + "key5" => "val5"))); + } + public function test_insertOne3() + { + // Document #4 + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->insertOne( + "collection", + array ("key1" => "val1", "key2" => "val2") + ); + $this->assertSame($res, 1); + } + public function test_find14() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val6", + "key5" => "val5"), + 1 => array ("key1" => "val1", + "key2" => "val2"))); + } - public function test_update2 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->update ("collection", array (), array ("key2"=>"val7", - "key5"=>"val8")); - $this->assertSame ($res, 2); - } - public function test_find15 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - $this->assertSame ($res, array (0=>array ("key2"=>"val7", - "key5"=>"val8"), - 1=>array ("key1"=>"val1", - "key2"=>"val7", - "key5"=>"val8"))); - } + public function test_update2() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->update("collection", array (), array ("key2" => "val7", + "key5" => "val8")); + $this->assertSame($res, 2); + } + public function test_find15() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + $this->assertSame($res, array (0 => array ("key2" => "val7", + "key5" => "val8"), + 1 => array ("key1" => "val1", + "key2" => "val7", + "key5" => "val8"))); + } - public function test_update3 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = $dbjson->update ("collection", array (), - array ("key2"=>"val9", - "key5"=>"val7", - "_unset"=>array ("key2"))); - $this->assertSame ($res, 2); - } - public function test_find16 () - { - $dbjson = new Dbjson ("dbjson://".dbfile); - $res = array_values ($dbjson->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - $this->assertSame ($res, array (0=>array ("key5"=>"val7"), - 1=>array ("key1"=>"val1", - "key5"=>"val7"))); - } + public function test_update3() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = $dbjson->update( + "collection", + array (), + array ("key2" => "val9", + "key5" => "val7", + "_unset" => array ("key2")) + ); + $this->assertSame($res, 2); + } + public function test_find16() + { + $dbjson = new Dbjson("dbjson://" . dbfile); + $res = array_values($dbjson->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + $this->assertSame($res, array (0 => array ("key5" => "val7"), + 1 => array ("key1" => "val1", + "key5" => "val7"))); + } // Concurrency tests - public function test_concurrency1 () - { - $dbjson1 = new Dbjson ("dbjson://".dbfile); - $dbjson2 = new Dbjson ("dbjson://".dbfile); - $dbjson1->insertOne ("collection", - array ("key1"=>"val1", "key2"=>"val2")); - $res = array_values ($dbjson2->find ("collection")); - // ["_id"] is random : skip the test - unset ($res[0]["_id"]); - unset ($res[1]["_id"]); - unset ($res[2]["_id"]); - $this->assertSame ($res, array (0=>array ("key5"=>"val7"), - 1=>array ("key1"=>"val1", - "key5"=>"val7"), - 2=>array ("key1"=>"val1", - "key2"=>"val2"))); - } + public function test_concurrency1() + { + $dbjson1 = new Dbjson("dbjson://" . dbfile); + $dbjson2 = new Dbjson("dbjson://" . dbfile); + $dbjson1->insertOne( + "collection", + array ("key1" => "val1", "key2" => "val2") + ); + $res = array_values($dbjson2->find("collection")); + // ["_id"] is random : skip the test + unset($res[0]["_id"]); + unset($res[1]["_id"]); + unset($res[2]["_id"]); + $this->assertSame($res, array (0 => array ("key5" => "val7"), + 1 => array ("key1" => "val1", + "key5" => "val7"), + 2 => array ("key1" => "val1", + "key2" => "val2"))); + } } diff --git a/Tests/DblayerComplet.php b/Tests/DblayerComplet.php index 54db245..1ed632d 100644 --- a/Tests/DblayerComplet.php +++ b/Tests/DblayerComplet.php @@ -1,4 +1,5 @@ @@ -9,13 +10,13 @@ namespace Domframework\Tests; use Domframework\Dblayer; -class DblayerTest{ENGINE} extends \PHPUnit_Framework_TestCase +class DblayerTest { ENGINE } extends \PHPUnit_Framework_TestCase { // Test with column name 'group', 'object', 'where', 'with space' // Test with table name 'group', 'object', 'where', 'with space' // For the 3 DB engines - public $engine="{ENGINE}"; + public $engine = "{ENGINE}"; public $confs = array ( "sqlite" => array ( "dsn" => "sqlite:/tmp/databaseDBLayer.db", @@ -41,353 +42,426 @@ class DblayerTest{ENGINE} extends \PHPUnit_Framework_TestCase ); /** @group singleton */ - public function test_dropTable () + public function test_dropTable() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - foreach (array ("users", "grouped", "multiple", "multiple2", "users3", - "readOR") as - $table) - { - $db->table = $table; - try - { - $res = $db->dropTable(); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + foreach ( + array ("users", "grouped", "multiple", "multiple2", "users3", + "readOR") as $table + ) { + $db->table = $table; + try { + $res = $db->dropTable(); + } catch (\Exception $e) { + } } - catch (\Exception $e) - { - } - } - $db->disconnect (); + $db->disconnect(); // Never generate an error, just drop the table if it exists, and do noting // if it doesn't exists } /** @group singleton */ - public function test_createTable1 () + public function test_createTable1() { // Create a table named grouped - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $db->primary = "group"; - $res = $db->createTable (); - $db->disconnect (); - $this->assertSame (0, $res); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $db->primary = "group"; + $res = $db->createTable(); + $db->disconnect(); + $this->assertSame(0, $res); } /** @group singleton */ - public function test_insert1 () + public function test_insert1() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $db->primary = "group"; - $res = $db->insert (array ("group"=>"gr ou\"p", - "object"=>"/éobj%", - "where"=>"\$'\"", - "with space"=>"with space")); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $db->primary = "group"; + $res = $db->insert(array ("group" => "gr ou\"p", + "object" => "/éobj%", + "where" => "\$'\"", + "with space" => "with space")); // SQLite start at 1, MySQL start at 0... - $this->assertSame ($res, "gr ou\"p"); + $this->assertSame($res, "gr ou\"p"); } - public function test_read1 () + public function test_read1() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $res = $db->read (array (array ("group", "gr ou\"p"), + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $res = $db->read(array (array ("group", "gr ou\"p"), array ("object","/éobj%"), array ("where","\$'\""), array ("with space","with space"))); - $this->assertSame (array (0=>array ("group"=>"gr ou\"p", - "object"=>"/éobj%", - "where"=>"\$'\"", - "with space"=>"with space")), $res); + $this->assertSame(array (0 => array ("group" => "gr ou\"p", + "object" => "/éobj%", + "where" => "\$'\"", + "with space" => "with space")), $res); } - public function test_update1 () + public function test_update1() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $db->primary = "group"; + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $db->primary = "group"; // Don't update primary key - $res = $db->update ("gr ou\"p", array ("object"=>"%éàoppp", - "with space"=>"WITH SPACE")); - $this->assertSame (1, $res); + $res = $db->update("gr ou\"p", array ("object" => "%éàoppp", + "with space" => "WITH SPACE")); + $this->assertSame(1, $res); } - public function test_read2 () + public function test_read2() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $res = $db->read (array (array ("group", "gr ou\"p"), + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $res = $db->read(array (array ("group", "gr ou\"p"), array ("object","%éàoppp"), array ("where","\$'\""), array ("with space","WITH SPACE"))); - $this->assertSame (array (0=>array ("group"=>"gr ou\"p", - "object"=>"%éàoppp", - "where"=>"\$'\"", - "with space"=>"WITH SPACE")), $res); + $this->assertSame(array (0 => array ("group" => "gr ou\"p", + "object" => "%éàoppp", + "where" => "\$'\"", + "with space" => "WITH SPACE")), $res); } - public function test_update2 () + public function test_update2() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (array ("group","object")); - $db->primary = "group"; + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (array ("group","object")); + $db->primary = "group"; // Update primary key - $res = $db->update ("gr ou\"p", array ("group"=>"NEW GROUP", - "object"=>"%éàoppp", - "with space"=>"WITH SPACE")); - $this->assertSame (1, $res); + $res = $db->update("gr ou\"p", array ("group" => "NEW GROUP", + "object" => "%éàoppp", + "with space" => "WITH SPACE")); + $this->assertSame(1, $res); } - public function test_read3 () + public function test_read3() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array (); - $res = $db->read (array (array ("group", "NEW GROUP"), + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array (); + $res = $db->read(array (array ("group", "NEW GROUP"), array ("object","%éàoppp"), array ("where","\$'\""), array ("with space","WITH SPACE"))); - $this->assertSame (array (0=>array ("group"=>"NEW GROUP", - "object"=>"%éàoppp", - "where"=>"\$'\"", - "with space"=>"WITH SPACE")), $res); + $this->assertSame(array (0 => array ("group" => "NEW GROUP", + "object" => "%éàoppp", + "where" => "\$'\"", + "with space" => "WITH SPACE")), $res); } - public function test_update3 () + public function test_update3() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "grouped"; - $db->fields = array ("group"=>array ("varchar", "255", "not null"), - "object"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array ("group"); - $db->primary = "group"; + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "grouped"; + $db->fields = array ("group" => array ("varchar", "255", "not null"), + "object" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array ("group"); + $db->primary = "group"; // Update primary key with primary key in unique with same values to test if // the exception is NOT raised - $res = $db->update ("NEW GROUP", array ("group"=>"NEW GROUP", - "object"=>"%éàoppp", - "with space"=>"WITH SPACE")); + $res = $db->update("NEW GROUP", array ("group" => "NEW GROUP", + "object" => "%éàoppp", + "with space" => "WITH SPACE")); // SQLite and PostgreSQL return 1 line modified // MySQL return 0 by default because there is no modification on the line // http://fr2.php.net/manual/en/pdostatement.rowcount.php#104930 // Now, the MYSQL_ATTR_FOUND_ROWS is added to connection to be the same in // all the engines - $this->assertSame (1, $res); + $this->assertSame(1, $res); } /** @group singleton */ // Part to test the foreign keys - public function test_createTable2 () + public function test_createTable2() { // Create a table named group - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->disconnect (); - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "users"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->foreign = array ( - "groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), - ); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->disconnect(); + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "users"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->foreign = array ( + "groupmember" => array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), + ); - $res = $db->createTable (); - $this->assertSame (0, $res); + $res = $db->createTable(); + $this->assertSame(0, $res); } - public function test_insert2 () + public function test_insert2() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "users"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->unique = array ("user"); - $db->primary = "user"; - $db->foreign = array ( - "groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), - ); - $res = $db->insert (array ("user"=>"Us ou\"r", - "groupmember"=>"NEW GROUP", - "where"=>"\$'\"", - "with space"=>"with space")); - $db->disconnect (); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "users"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->unique = array ("user"); + $db->primary = "user"; + $db->foreign = array ( + "groupmember" => array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), + ); + $res = $db->insert(array ("user" => "Us ou\"r", + "groupmember" => "NEW GROUP", + "where" => "\$'\"", + "with space" => "with space")); + $db->disconnect(); // SQLite start at 1, MySQL start at 0... - $this->assertLessThanOrEqual ($res, 2); + $this->assertLessThanOrEqual($res, 2); } // Test the unique feature - public function test_insert3 () + public function test_insert3() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "users"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "users"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); // Unique simple in insert - $db->unique = array ("user"); - $db->primary = "user"; - $db->foreign = array ( - "groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), - ); - $this->setExpectedException ("Exception"); - $res = $db->insert (array ("user"=>"Us ou\"r", - "groupmember"=>"NEW GROUP", - "where"=>"\$'\"", - "with space"=>"with space")); + $db->unique = array ("user"); + $db->primary = "user"; + $db->foreign = array ( + "groupmember" => array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), + ); + $this->setExpectedException("Exception"); + $res = $db->insert(array ("user" => "Us ou\"r", + "groupmember" => "NEW GROUP", + "where" => "\$'\"", + "with space" => "with space")); } - public function test_insert4 () + public function test_insert4() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "users"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "users"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); // Unique multiple in insert - $db->unique = array (array ("user", "groupmember")); - $db->primary = "user"; - $db->foreign = array ( - "groupmember"=>array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), - ); - $this->setExpectedException ("Exception"); - $res = $db->insert (array ("user"=>"Us ou\"r", - "groupmember"=>"NEW GROUP", - "where"=>"\$'\"", - "with space"=>"with space")); + $db->unique = array (array ("user", "groupmember")); + $db->primary = "user"; + $db->foreign = array ( + "groupmember" => array ("grouped", "group", "ON UPDATE CASCADE ON DELETE CASCADE"), + ); + $this->setExpectedException("Exception"); + $res = $db->insert(array ("user" => "Us ou\"r", + "groupmember" => "NEW GROUP", + "where" => "\$'\"", + "with space" => "with space")); } /** @group singleton */ // Test multiple actions in one single connection - public function test_multiple1 () + public function test_multiple1() { // Create a table named group - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "multiple"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db->createTable (); - $db2 = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db2->table = "multiple2"; - $db2->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $db2->createTable (); - $res = $db2->read (array (array ("user", "toto"))); - $res = $db->read (array (array ("user", "toto"))); - $db->disconnect (); - $this->assertSame (array (), $res); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "multiple"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db->createTable(); + $db2 = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db2->table = "multiple2"; + $db2->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $db2->createTable(); + $res = $db2->read(array (array ("user", "toto"))); + $res = $db->read(array (array ("user", "toto"))); + $db->disconnect(); + $this->assertSame(array (), $res); } /** @group singleton */ - public function test_createTable3 () + public function test_createTable3() { // Create a table named group - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "users3"; - $db->fields = array ("user"=>array ("varchar", "255", "not null"), - "groupmember"=>array ("varchar", "255", "not null"), - "where"=>array ("varchar", "255", "not null"), - "with space"=>array ("varchar", "255", "not null")); - $res = $db->createTable (); - $db->disconnect (); - $this->assertSame (0, $res); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "users3"; + $db->fields = array ("user" => array ("varchar", "255", "not null"), + "groupmember" => array ("varchar", "255", "not null"), + "where" => array ("varchar", "255", "not null"), + "with space" => array ("varchar", "255", "not null")); + $res = $db->createTable(); + $db->disconnect(); + $this->assertSame(0, $res); } /** Check the OR feature on the same column with different value */ - public function test_readOR1 () + public function test_readOR1() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayer ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $db->table = "readOR"; - $db->fields = array ("id"=>array ("integer"), - "user"=>array ("varchar", "255", "not null")); - $db->primary = "id"; - $db->unique = array ("id"); - $db->createTable (); - $db->insert (array ("id"=>"0", "user"=>"test0")); - $db->insert (array ("id"=>"1", "user"=>"test1")); - $res = $db->read (array (array ("id", 0), array ("id", 1)), array ("user"), - null, true); - $db->disconnect (); - $this->assertSame (array (0=>array ("user"=>"test0"), - 1=>array ("user"=>"test1")), $res); + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayer( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $db->table = "readOR"; + $db->fields = array ("id" => array ("integer"), + "user" => array ("varchar", "255", "not null")); + $db->primary = "id"; + $db->unique = array ("id"); + $db->createTable(); + $db->insert(array ("id" => "0", "user" => "test0")); + $db->insert(array ("id" => "1", "user" => "test1")); + $res = $db->read( + array (array ("id", 0), array ("id", 1)), + array ("user"), + null, + true + ); + $db->disconnect(); + $this->assertSame(array (0 => array ("user" => "test0"), + 1 => array ("user" => "test1")), $res); + } } -} diff --git a/Tests/DblayerauthzgroupsTest.php b/Tests/DblayerauthzgroupsTest.php index b540588..78fabd0 100644 --- a/Tests/DblayerauthzgroupsTest.php +++ b/Tests/DblayerauthzgroupsTest.php @@ -1,4 +1,5 @@ @@ -12,7 +13,7 @@ use Domframework\Authzgroups; class DblayerauthzgroupsTest extends \PHPUnit_Framework_TestCase { - public $confs = array ( + public $confs = array ( "sqlite" => array ( "dsn" => "sqlite:/tmp/databaseAuthz.db", "username" => null, @@ -21,425 +22,527 @@ class DblayerauthzgroupsTest extends \PHPUnit_Framework_TestCase "tableprefix" => "", )); - public function test_delDB () - { - if (file_exists ("/tmp/databaseAuthz.db")) - unlink ("/tmp/databaseAuthz.db"); - } + public function test_delDB() + { + if (file_exists("/tmp/databaseAuthz.db")) { + unlink("/tmp/databaseAuthz.db"); + } + } - public function test_createTablesAuthzgroups () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $a->createTables (); - $a->groupAdd ("modTest", "group"); - $a->groupmemberAdd ("modTest", "group", "user"); - $a->objectAdd ("modTest", "/"); - $a->objectAdd ("modTest", "/article"); - $a->objectAdd ("modTest", "/article/base"); - $a->objectAdd ("modTest", "/article/base/poub"); - $a->rightAdd ("modTest", "group", "/", "RO"); - $a->rightAdd ("modTest", "group", "/article", "RO"); - $a->rightAdd ("modTest", "group", "/article/base", "RO"); - $res = $a->rightAdd ("modTest", "group", "/article/base/poub", "RW"); - // Should not be verified : it is not a test for authzgroups ! - $this->assertSame ("4", $res); - } + public function test_createTablesAuthzgroups() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $a->createTables(); + $a->groupAdd("modTest", "group"); + $a->groupmemberAdd("modTest", "group", "user"); + $a->objectAdd("modTest", "/"); + $a->objectAdd("modTest", "/article"); + $a->objectAdd("modTest", "/article/base"); + $a->objectAdd("modTest", "/article/base/poub"); + $a->rightAdd("modTest", "group", "/", "RO"); + $a->rightAdd("modTest", "group", "/article", "RO"); + $a->rightAdd("modTest", "group", "/article/base", "RO"); + $res = $a->rightAdd("modTest", "group", "/article/base/poub", "RW"); + // Should not be verified : it is not a test for authzgroups ! + $this->assertSame("4", $res); + } - public function test_createTable () - { - $dbconfig = $this->confs["sqlite"]; - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->disconnect (); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))); - $res = $n->createTable (); - $this->assertSame (0, $res); - } + public function test_createTable() + { + $dbconfig = $this->confs["sqlite"]; + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->disconnect(); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))); + $res = $n->createTable(); + $this->assertSame(0, $res); + } - public function test_insert1 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = $n->insert (array ("zo ne"=>"zone1", - "opendate"=>"2015-05-04 00:11:22")); - $n->disconnect (); - $this->assertSame ("1", $res); - } + public function test_insert1() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = $n->insert(array ("zo ne" => "zone1", + "opendate" => "2015-05-04 00:11:22")); + $n->disconnect(); + $this->assertSame("1", $res); + } // Check if the update of the authzgroups database is OK - public function test_addAuthzgroups () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $res = $a->allow ("modTest", "user", "/article/base/poub/1"); - $this->assertSame ("RW", $res); - } + public function test_addAuthzgroups() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $res = $a->allow("modTest", "user", "/article/base/poub/1"); + $this->assertSame("RW", $res); + } - public function test_insert2 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $n->insert (array ("zo ne"=>"zone2", "opendate"=>"2015-05-04 00:11:22")); - $n->insert (array ("zo ne"=>"zone3", "opendate"=>"2015-05-04 00:11:22")); - $n->insert (array ("zo ne"=>"zone4", "opendate"=>"2015-05-04 00:11:22")); - $res = $n->insert (array ("zo ne"=>"zone5", - "opendate"=>"2015-05-04 00:11:22")); - $n->disconnect (); - $this->assertSame ("5", $res); - } + public function test_insert2() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $n->insert(array ("zo ne" => "zone2", "opendate" => "2015-05-04 00:11:22")); + $n->insert(array ("zo ne" => "zone3", "opendate" => "2015-05-04 00:11:22")); + $n->insert(array ("zo ne" => "zone4", "opendate" => "2015-05-04 00:11:22")); + $res = $n->insert(array ("zo ne" => "zone5", + "opendate" => "2015-05-04 00:11:22")); + $n->disconnect(); + $this->assertSame("5", $res); + } // Access to all the tuples - public function test_read1 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = count ($n->read ()); - $n->disconnect (); - $this->assertSame (5, $res); - } + public function test_read1() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = count($n->read()); + $n->disconnect(); + $this->assertSame(5, $res); + } // Remove the right access to 2 and 4 - public function test_rightDel () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $a->rightDel ("modTest", "group", "/article/base/poub/2"); - $res = $a->rightDel ("modTest", "group", "/article/base/poub/4"); - // Should not be verified : it is not a test for authzgroups ! - $this->assertSame (1, $res); - } + public function test_rightDel() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $a->rightDel("modTest", "group", "/article/base/poub/2"); + $res = $a->rightDel("modTest", "group", "/article/base/poub/4"); + // Should not be verified : it is not a test for authzgroups ! + $this->assertSame(1, $res); + } // Access to 3 of the tuples (2 are blacklisted for the user) - public function test_read2 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = count ($n->read ()); - $n->disconnect (); - $this->assertSame (3, $res); - } + public function test_read2() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = count($n->read()); + $n->disconnect(); + $this->assertSame(3, $res); + } // Del an entry without right -> exception - public function test_delEntry1 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $this->setExpectedException ("Exception"); - $res = $n->delete (2); - } + public function test_delEntry1() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $this->setExpectedException("Exception"); + $res = $n->delete(2); + } // Update a right to RO - public function test_rightRO () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $res = $a->rightUpdate ("modTest", "group", "/article/base/poub/1", "RO"); - // Not necessary to test : authzgroups - $this->assertSame (1, $res); - } + public function test_rightRO() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $res = $a->rightUpdate("modTest", "group", "/article/base/poub/1", "RO"); + // Not necessary to test : authzgroups + $this->assertSame(1, $res); + } // Update an entry with RO right -> exception - public function test_updateEntry2 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $this->setExpectedException ("Exception"); - $res = $n->update (1, array ("zo ne"=>"NOT ALLOWED")); - } + public function test_updateEntry2() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $this->setExpectedException("Exception"); + $res = $n->update(1, array ("zo ne" => "NOT ALLOWED")); + } // Del an entry with the RO right -> exception - public function test_delEntry2 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $this->setExpectedException ("Exception"); - $res = $n->delete (1); - } + public function test_delEntry2() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $this->setExpectedException("Exception"); + $res = $n->delete(1); + } // Update a right to RW - public function test_rightRW () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $res = $a->rightUpdate ("modTest", "group", "/article/base/poub/1", "RW"); - // Not necessary to test : authzgroups - $this->assertSame (1, $res); - } + public function test_rightRW() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $res = $a->rightUpdate("modTest", "group", "/article/base/poub/1", "RW"); + // Not necessary to test : authzgroups + $this->assertSame(1, $res); + } // Update an entry with RW right - public function test_updateEntry3 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = $n->update (1, array ("zo ne"=>"ALLOWED")); - $this->assertSame (1, $res); - } + public function test_updateEntry3() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = $n->update(1, array ("zo ne" => "ALLOWED")); + $this->assertSame(1, $res); + } // Del an entry with the RW right - public function test_delEntry3 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = $n->delete (1); - $this->assertSame (1, $res); - } + public function test_delEntry3() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = $n->delete(1); + $this->assertSame(1, $res); + } // Check if the update of the authzgroups database is OK after deletion - public function test_delAuthzgroups () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $res = $a->objectRead ("modTest", "/article/base/poub/1"); - $this->assertSame (array (), $res); - } + public function test_delAuthzgroups() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $res = $a->objectRead("modTest", "/article/base/poub/1"); + $this->assertSame(array (), $res); + } // Read the zone without id - public function test_read3 () - { - $dbconfig = $this->confs["sqlite"]; - $a = new Authzgroups (); - $a->connect ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $n = new Dblayerauthzgroups ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], - $dbconfig["driver_options"]); - $n->tableSet ("dns zones") - ->fieldsSet (array ( - "id"=>array ("integer", "not null", "autoincrement"), - "zo ne"=>array ("varchar", "255", "not null"), - "vie wname"=>array ("varchar", "255"), - "view clients"=>array ("varchar", "255"), - "comme nt"=>array ("varchar", "1024"), - "opendate"=>array ("datetime", "not null"), - "closedate"=>array ("datetime"))) - ->primarySet ("id") - ->uniqueSet (array ("id", array ("zo ne", "vie wname"))) - ->authzgroupsSet ($a) - ->moduleSet ("modTest") - ->userSet ("user") - ->createGroupSet ("group") - ->pathSet ("/article/base/poub"); - $res = $n->read (null, array ("zo ne", "vie wname")); - $this->assertSame (array (1=>array ("zo ne"=>"zone3", "vie wname"=>null), - 3=>array ("zo ne"=>"zone5", "vie wname"=>null)), - $res); - } + public function test_read3() + { + $dbconfig = $this->confs["sqlite"]; + $a = new Authzgroups(); + $a->connect( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n = new Dblayerauthzgroups( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $n->tableSet("dns zones") + ->fieldsSet(array ( + "id" => array ("integer", "not null", "autoincrement"), + "zo ne" => array ("varchar", "255", "not null"), + "vie wname" => array ("varchar", "255"), + "view clients" => array ("varchar", "255"), + "comme nt" => array ("varchar", "1024"), + "opendate" => array ("datetime", "not null"), + "closedate" => array ("datetime"))) + ->primarySet("id") + ->uniqueSet(array ("id", array ("zo ne", "vie wname"))) + ->authzgroupsSet($a) + ->moduleSet("modTest") + ->userSet("user") + ->createGroupSet("group") + ->pathSet("/article/base/poub"); + $res = $n->read(null, array ("zo ne", "vie wname")); + $this->assertSame( + array (1 => array ("zo ne" => "zone3", "vie wname" => null), + 3 => array ("zo ne" => "zone5", "vie wname" => null)), + $res + ); + } } - diff --git a/Tests/DblayerooComplet.php b/Tests/DblayerooComplet.php index 2bd03f7..c697b0a 100644 --- a/Tests/DblayerooComplet.php +++ b/Tests/DblayerooComplet.php @@ -1,4 +1,5 @@ @@ -9,13 +10,16 @@ namespace Domframework\Tests; use Domframework\Dblayeroo; -class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase +class DblayerooTest +{ + ENGINE +} extends \PHPUnit_Framework_TestCase { // Test with column name 'group', 'object', 'where', 'with space' // Test with table name 'group', 'object', 'where', 'with space' // For the 3 DB engines - public $engine="{ENGINE}"; + public $engine = "{ENGINE}"; public $confs = array ( "sqlite" => array ( "dsn" => "sqlite:/tmp/databaseDBLayeroo.db", @@ -40,353 +44,374 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase ), ); - private function tbl1 () + private function tbl1() { - $dbconfig = $this->confs["{ENGINE}"]; - $tbl1 = new Dblayeroo ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $tbl1->table ("groupedoo"); - $tbl1->fields (array ("group"=>array ("varchar(255)", "not null"), - "object"=>array ("varchar(255)", "not null"), - "where"=>array ("varchar(255)", "not null"), - "with space"=>array ("varchar(255)"))); - $tbl1->unique (array ()); - $tbl1->primary ("group"); - $tbl1->realTypes (array ("group" => "regex(/^\S{1,10}$/)")); - return $tbl1; + $dbconfig = $this->confs["{ENGINE}"]; + $tbl1 = new Dblayeroo( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $tbl1->table("groupedoo"); + $tbl1->fields(array ("group" => array ("varchar(255)", "not null"), + "object" => array ("varchar(255)", "not null"), + "where" => array ("varchar(255)", "not null"), + "with space" => array ("varchar(255)"))); + $tbl1->unique(array ()); + $tbl1->primary("group"); + $tbl1->realTypes(array ("group" => "regex(/^\S{1,10}$/)")); + return $tbl1; } - private function tbl2 () + private function tbl2() { - $dbconfig = $this->confs["{ENGINE}"]; - $tbl2 = new Dblayeroo ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $tbl2->table ("usersoo"); - $tbl2->fields (array ("uid"=>array ("integer", "not null", "autoincrement"), - "gecos"=>array ("varchar(255)", "not null"), - "password"=>array ("varchar(255)", "not null"), + $dbconfig = $this->confs["{ENGINE}"]; + $tbl2 = new Dblayeroo( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $tbl2->table("usersoo"); + $tbl2->fields(array ("uid" => array ("integer", "not null", "autoincrement"), + "gecos" => array ("varchar(255)", "not null"), + "password" => array ("varchar(255)", "not null"), "group" => array ("varchar(255)", "not null"), )); - $tbl2->unique (array ("gecos","password")); - $tbl2->primary ("uid"); - $tbl2->foreign (array ("group" => array ("groupedoo", "group", + $tbl2->unique(array ("gecos","password")); + $tbl2->primary("uid"); + $tbl2->foreign(array ("group" => array ("groupedoo", "group", "ON DELETE CASCADE"))); - return $tbl2; + return $tbl2; } - private function tbl3 () + private function tbl3() { - $dbconfig = $this->confs["{ENGINE}"]; - $tbl3 = new Dblayeroo ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - return $tbl3; + $dbconfig = $this->confs["{ENGINE}"]; + $tbl3 = new Dblayeroo( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + return $tbl3; } - private function tbl4 () + private function tbl4() { - $dbconfig = $this->confs["{ENGINE}"]; - $tbl4 = new Dblayeroo ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - $tbl4->table ("rightsoo"); - $tbl4->fields (array ("id"=>array ("integer", "not null", "autoincrement"), - "name"=>array ("varchar(255)", "not null"), + $dbconfig = $this->confs["{ENGINE}"]; + $tbl4 = new Dblayeroo( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + $tbl4->table("rightsoo"); + $tbl4->fields(array ("id" => array ("integer", "not null", "autoincrement"), + "name" => array ("varchar(255)", "not null"), "group" => array ("varchar(255)", "not null"), )); - $tbl4->unique (array ("name")); - $tbl4->primary ("id"); - $tbl4->foreign (array ("group" => array ("groupedoo", "group", + $tbl4->unique(array ("name")); + $tbl4->primary("id"); + $tbl4->foreign(array ("group" => array ("groupedoo", "group", "ON DELETE CASCADE"))); - return $tbl4; + return $tbl4; } - public function test_dropTable () + public function test_dropTable() { - $dbconfig = $this->confs["{ENGINE}"]; - $db = new Dblayeroo ($dbconfig["dsn"], $dbconfig["username"], - $dbconfig["password"], $dbconfig["driver_options"]); - foreach (array ("rightsoo", "usersoo", "groupedoo", + $dbconfig = $this->confs["{ENGINE}"]; + $db = new Dblayeroo( + $dbconfig["dsn"], + $dbconfig["username"], + $dbconfig["password"], + $dbconfig["driver_options"] + ); + foreach ( + array ("rightsoo", "usersoo", "groupedoo", "multipleoo", "multiple2oo", "users3oo", - "readORoo") as - $table) - { - $db->table ($table); - try - { - $res = $db->dropTable(); + "readORoo") as $table + ) { + $db->table($table); + try { + $res = $db->dropTable(); + } catch (\Exception $e) { + } } - catch (\Exception $e) - { - } - } - $db->disconnect (); + $db->disconnect(); // Never generate an error, just drop the table if it exists, and do noting // if it doesn't exists } - public function test_createTable1 () + public function test_createTable1() { // Create a table named groupedoo - $tbl1 = $this->tbl1 (); - $res = $tbl1->createTable (); - $tbl1->disconnect (); - $this->assertSame (0, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->createTable(); + $tbl1->disconnect(); + $this->assertSame(0, $res); } - public function test_createTable2 () + public function test_createTable2() { // Create a table named usersoo - $tbl2 = $this->tbl2 (); - $res = $tbl2->createTable (); - $tbl2->disconnect (); - $this->assertSame (0, $res); + $tbl2 = $this->tbl2(); + $res = $tbl2->createTable(); + $tbl2->disconnect(); + $this->assertSame(0, $res); } - public function test_createTable4 () + public function test_createTable4() { // Create a table named rightsoo - $tbl4 = $this->tbl4 (); - $res = $tbl4->createTable (); - $tbl4->disconnect (); - $this->assertSame (0, $res); + $tbl4 = $this->tbl4(); + $res = $tbl4->createTable(); + $tbl4->disconnect(); + $this->assertSame(0, $res); } - public function test_select1 () + public function test_select1() { // Select all on the table : nothing - $tbl1 = $this->tbl1 (); - $res = $tbl1->select()->execute (); - $tbl1->disconnect (); - $this->assertSame (array (), $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->select()->execute(); + $tbl1->disconnect(); + $this->assertSame(array (), $res); } - public function test_insert1 () + public function test_insert1() { // Insert without value : raise an exception - $this->setExpectedException ("Exception"); - $tbl1 = $this->tbl1 (); - $res = $tbl1->insert()->execute (); - $tbl1->disconnect (); + $this->setExpectedException("Exception"); + $tbl1 = $this->tbl1(); + $res = $tbl1->insert()->execute(); + $tbl1->disconnect(); } - public function test_insert2 () + public function test_insert2() { // Insert : missing not null field : exception - $this->setExpectedException ("Exception"); - $tbl1 = $this->tbl1 (); - $res = $tbl1->insert() - ->setValues(array ("group"=>"group1", "where"=>"where")) - ->execute (); - $tbl1->disconnect (); + $this->setExpectedException("Exception"); + $tbl1 = $this->tbl1(); + $res = $tbl1->insert() + ->setValues(array ("group" => "group1", "where" => "where")) + ->execute(); + $tbl1->disconnect(); } - public function test_insert3 () + public function test_insert3() { // Insert : first row inserted - $tbl1 = $this->tbl1 (); + $tbl1 = $this->tbl1(); // Normalize the value to be inserted too - $res = $tbl1->insert()->setValues(array ("group"=>" group1 ", - "where"=>"where", - "object"=>"object"))->execute (); - $tbl1->disconnect (); + $res = $tbl1->insert()->setValues(array ("group" => " group1 ", + "where" => "where", + "object" => "object"))->execute(); + $tbl1->disconnect(); // As the key is not an autoincrement, the lastInsertID can be 0 or 1 - $this->assertSame ($res, "group1"); + $this->assertSame($res, "group1"); } - public function test_select2 () + public function test_select2() { // Select all on the table : nothing - $tbl1 = $this->tbl1 (); - $res = $tbl1->select()->execute (); - $tbl1->disconnect (); - $this->assertSame (array (array ("group"=>"group1", "object"=>"object", - "where"=>"where", "with space"=>null)), - $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->select()->execute(); + $tbl1->disconnect(); + $this->assertSame( + array (array ("group" => "group1", "object" => "object", + "where" => "where", "with space" => null)), + $res + ); } - public function test_update1 () + public function test_update1() { // update the all the rows of the table (without WHERE) - $tbl1 = $this->tbl1 (); - $res = $tbl1->update()->setValues(array ("group"=>"group2", - "where"=>"where", - "object"=>"object"))->execute (); - $tbl1->disconnect (); - $this->assertSame (1, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->update()->setValues(array ("group" => "group2", + "where" => "where", + "object" => "object"))->execute(); + $tbl1->disconnect(); + $this->assertSame(1, $res); } - public function test_select3 () + public function test_select3() { // Select all on the table after update - $tbl1 = $this->tbl1 (); - $res = $tbl1->select()->execute (); - $tbl1->disconnect (); - $this->assertSame (array (array ("group"=>"group2", "object"=>"object", - "where"=>"where", "with space"=>null)), - $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->select()->execute(); + $tbl1->disconnect(); + $this->assertSame( + array (array ("group" => "group2", "object" => "object", + "where" => "where", "with space" => null)), + $res + ); } - public function test_update2 () + public function test_update2() { // update the all the rows of the table (with inexisting WHERE) - $tbl1 = $this->tbl1 (); - $res = $tbl1->update() - ->setValues(array ("group"=>"group2", "where"=>"where", - "object"=>"object")) - ->whereAdd ("group", "=", "group1") - ->execute (); - $tbl1->disconnect (); - $this->assertSame (0, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->update() + ->setValues(array ("group" => "group2", "where" => "where", + "object" => "object")) + ->whereAdd("group", "=", "group1") + ->execute(); + $tbl1->disconnect(); + $this->assertSame(0, $res); } - public function test_update3 () + public function test_update3() { // update the all the rows of the table (with existing WHERE) - $tbl1 = $this->tbl1 (); - $res = $tbl1->update() - ->setValues(array ("group"=>"group1", "where"=>"where", - "object"=>"object")) - ->whereAdd ("group", "=", "group2") - ->execute (); - $tbl1->disconnect (); - $this->assertSame (1, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->update() + ->setValues(array ("group" => "group1", "where" => "where", + "object" => "object")) + ->whereAdd("group", "=", "group2") + ->execute(); + $tbl1->disconnect(); + $this->assertSame(1, $res); } - public function test_update4 () + public function test_update4() { // update the all the rows of the table : NOT NULL value not provided // (already existing in the table) - $tbl1 = $this->tbl1 (); - $res = $tbl1->update() - ->setValues(array ("group"=>"group1")) - ->execute (); - $tbl1->disconnect (); - $this->assertSame (1, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->update() + ->setValues(array ("group" => "group1")) + ->execute(); + $tbl1->disconnect(); + $this->assertSame(1, $res); } - public function test_delete1 () + public function test_delete1() { // Delete : WHERE return nothing - $tbl1 = $this->tbl1 (); - $res = $tbl1->delete () - ->whereAdd ("group", "=", "group2") - ->execute (); - $tbl1->disconnect (); - $this->assertSame (0, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->delete() + ->whereAdd("group", "=", "group2") + ->execute(); + $tbl1->disconnect(); + $this->assertSame(0, $res); } - public function test_delete2 () + public function test_delete2() { // Delete all - $tbl1 = $this->tbl1 (); - $res = $tbl1->delete () - ->execute (); - $tbl1->disconnect (); - $this->assertSame (1, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->delete() + ->execute(); + $tbl1->disconnect(); + $this->assertSame(1, $res); } - public function test_select4 () + public function test_select4() { // Select all on the table : nothing - $tbl1 = $this->tbl1 (); - $res = $tbl1->select()->execute (); - $tbl1->disconnect (); - $this->assertSame (array (), $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->select()->execute(); + $tbl1->disconnect(); + $this->assertSame(array (), $res); } - public function test_insert5 () + public function test_insert5() { // Insert : first row inserted for TABLE 2 tests - $tbl1 = $this->tbl1 (); - $res = $tbl1->insert()->setValues(array ("group"=>"group1", - "where"=>"where", - "object"=>"object"))->execute (); - $tbl1->disconnect (); + $tbl1 = $this->tbl1(); + $res = $tbl1->insert()->setValues(array ("group" => "group1", + "where" => "where", + "object" => "object"))->execute(); + $tbl1->disconnect(); // As the key is not an autoincrement, the lastInsertID can be 0 or 1 - $this->assertSame ($res, "group1"); + $this->assertSame($res, "group1"); } /////////////////// /// TABLE 2 /// /////////////////// - public function test_insertAutoincrement1 () + public function test_insertAutoincrement1() { // Test autoincrement - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->insert()->setValues(array ("gecos"=>"name", - "password"=>"toto", - "group"=>"group1"))->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame ("1", $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->insert()->setValues(array ("gecos" => "name", + "password" => "toto", + "group" => "group1"))->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame("1", $res); } - public function test_insertAutoincrement2 () + public function test_insertAutoincrement2() { // Test autoincrement - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->insert()->setValues(array ("gecos"=>"firstname2", - "password"=>"toto2", - "group"=>"group1"))->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame ("2", $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->insert()->setValues(array ("gecos" => "firstname2", + "password" => "toto2", + "group" => "group1"))->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame("2", $res); } - public function test_insertAutoincrement3 () + public function test_insertAutoincrement3() { // Test autoincrement - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->insert()->setValues(array ("gecos"=>"firstname3", - "password"=>"toto3", - "group"=>"group1"))->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame ("3", $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->insert()->setValues(array ("gecos" => "firstname3", + "password" => "toto3", + "group" => "group1"))->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame("3", $res); } - public function test_delete3 () + public function test_delete3() { // Delete with WHERE clause - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->delete () - ->whereAdd ("gecos", "LIKE", "firstname%") - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (2, $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->delete() + ->whereAdd("gecos", "LIKE", "firstname%") + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(2, $res); } - public function test_select5 () + public function test_select5() { // Select all on the table : one entry "gecos"=>"name" - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->select()->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array (array ("uid"=>1, - "gecos"=>"name", - "password"=>"toto", - "group"=>"group1")), $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->select()->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array (array ("uid" => 1, + "gecos" => "name", + "password" => "toto", + "group" => "group1")), $res); } /// SCHEMA MANAGEMENT /// - public function test_getTableSchema1 () + public function test_getTableSchema1() { - $tbl3 = $this->tbl3 (); - $res = $tbl3->getTableSchema ("usersoo"); - $tbl3->disconnect (); - $this->assertSame ( - array ("table" => "usersoo", + $tbl3 = $this->tbl3(); + $res = $tbl3->getTableSchema("usersoo"); + $tbl3->disconnect(); + $this->assertSame( + array ("table" => "usersoo", "fields" => array ( "uid" => array ("integer", "not null", "autoincrement"), "gecos" => array ("varchar(255)", "not null"), @@ -400,75 +425,79 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase ), "foreignUsed" => array ( ), - ), $res); + ), + $res + ); } - public function test_getTableSchema2 () + public function test_getTableSchema2() { - $tbl3 = $this->tbl3 (); - $res = $tbl3->getTableSchema ("groupedoo"); - $tbl3->disconnect (); - $this->assertSame ( - array ( - "table" => "groupedoo", - "fields" => array ( + $tbl3 = $this->tbl3(); + $res = $tbl3->getTableSchema("groupedoo"); + $tbl3->disconnect(); + $this->assertSame( + array ( + "table" => "groupedoo", + "fields" => array ( "group" => array ("varchar(255)", "not null"), "object" => array ("varchar(255)", "not null"), "where" => array ("varchar(255)", "not null"), "with space" => array ("varchar(255)")), - "primary" => "group", - "unique" => array ("group"), - "foreign" => array (), - "foreignUsed" => array ( + "primary" => "group", + "unique" => array ("group"), + "foreign" => array (), + "foreignUsed" => array ( "group" => array ( array ("rightsoo", "group"), array ("usersoo", "group"), ), - ), - ), $res); + ), + ), + $res + ); } // JOINS - public function test_insertJoin1 () + public function test_insertJoin1() { - $tbl1 = $this->tbl1 (); - $tbl1->insert() - ->setValues(array ("group"=>"group2", - "object"=>"object", - "where"=>"where")) - ->execute (); - $tbl2 = $this->tbl2 (); - $tbl2->setForeignObj ($tbl1); - $res = $tbl2->insert() - ->setValues(array ("gecos"=>"name2", - "password"=>"pwd2", - "group"=>"group1")) - ->execute (); - $res = $tbl2->insert() - ->setValues(array ("gecos"=>"name3", - "password"=>"pwd3", - "group"=>"group1")) - ->execute (); - $res = $tbl2->insert() - ->setValues(array ("gecos"=>"name4", - "password"=>"pwd4", - "group"=>"group1")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); + $tbl1 = $this->tbl1(); + $tbl1->insert() + ->setValues(array ("group" => "group2", + "object" => "object", + "where" => "where")) + ->execute(); + $tbl2 = $this->tbl2(); + $tbl2->setForeignObj($tbl1); + $res = $tbl2->insert() + ->setValues(array ("gecos" => "name2", + "password" => "pwd2", + "group" => "group1")) + ->execute(); + $res = $tbl2->insert() + ->setValues(array ("gecos" => "name3", + "password" => "pwd3", + "group" => "group1")) + ->execute(); + $res = $tbl2->insert() + ->setValues(array ("gecos" => "name4", + "password" => "pwd4", + "group" => "group1")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); } - public function test_innerJoin1 () + public function test_innerJoin1() { // No filter - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $res = $tbl2->select () - ->joinInner ($tbl1, array ("group"=>"group")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $res = $tbl2->select() + ->joinInner($tbl1, array ("group" => "group")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( 'usersoo.uid' => 1, 'usersoo.gecos' => 'name', @@ -477,7 +506,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, ), array ( 'usersoo.uid' => 4, @@ -487,7 +516,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, ), array ( 'usersoo.uid' => 5, @@ -497,7 +526,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, ), array ( 'usersoo.uid' => 6, @@ -507,23 +536,23 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, ), - ), $res); + ), $res); } - public function test_innerJoin2 () + public function test_innerJoin2() { // No filter. Manage the empty displayAdd - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd (); - $tbl2 = $this->tbl2 (); - $res = $tbl2->select () - ->joinInner ($tbl1, array ("group"=>"group")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl1->displayAdd(); + $tbl2 = $this->tbl2(); + $res = $tbl2->select() + ->joinInner($tbl1, array ("group" => "group")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( 'uid' => 1, 'gecos' => 'name', @@ -548,64 +577,64 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'password' => 'pwd4', 'group' => 'group1', ), - ), $res); + ), $res); } - public function test_innerJoin3 () + public function test_innerJoin3() { // No filter. Manage the empty displayAdd - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->displayAdd (); - $res = $tbl2->select () - ->joinInner ($tbl1, array ("group"=>"group")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->displayAdd(); + $res = $tbl2->select() + ->joinInner($tbl1, array ("group" => "group")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( 'group' => 'group1', 'object' => 'object', 'where' => 'where', - 'with space' => NULL, + 'with space' => null, ), array ( 'group' => 'group1', 'object' => 'object', 'where' => 'where', - 'with space' => NULL, + 'with space' => null, ), array ( 'group' => 'group1', 'object' => 'object', 'where' => 'where', - 'with space' => NULL, + 'with space' => null, ), array ( 'group' => 'group1', 'object' => 'object', 'where' => 'where', - 'with space' => NULL, + 'with space' => null, ), - ), $res); + ), $res); } - public function test_leftJoin2 () + public function test_leftJoin2() { // No filter - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $res = $tbl1->select () - ->joinLeft ($tbl2, array ("group"=>"group")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $res = $tbl1->select() + ->joinLeft($tbl2, array ("group" => "group")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, 'usersoo.uid' => 1, 'usersoo.gecos' => 'name', 'usersoo.password' => 'toto', @@ -615,7 +644,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, 'usersoo.uid' => 4, 'usersoo.gecos' => 'name2', 'usersoo.password' => 'pwd2', @@ -625,7 +654,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, 'usersoo.uid' => 5, 'usersoo.gecos' => 'name3', 'usersoo.password' => 'pwd3', @@ -635,7 +664,7 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group1', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, + 'groupedoo.with space' => null, 'usersoo.uid' => 6, 'usersoo.gecos' => 'name4', 'usersoo.password' => 'pwd4', @@ -645,29 +674,29 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'groupedoo.group' => 'group2', 'groupedoo.object' => 'object', 'groupedoo.where' => 'where', - 'groupedoo.with space' => NULL, - 'usersoo.uid' => NULL, - 'usersoo.gecos' => NULL, - 'usersoo.password' => NULL, - 'usersoo.group' => NULL, + 'groupedoo.with space' => null, + 'usersoo.uid' => null, + 'usersoo.gecos' => null, + 'usersoo.password' => null, + 'usersoo.group' => null, ), - ), $res); + ), $res); } - public function test_leftJoin3 () + public function test_leftJoin3() { // Filter on the tbl1, do not display tbl2 - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->displayAdd (); - $res = $tbl1->select () - ->displayAdd ("group") - ->joinLeft ($tbl2, array ("group"=>"group")) - ->orderAdd ("group", "ASC") - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->displayAdd(); + $res = $tbl1->select() + ->displayAdd("group") + ->joinLeft($tbl2, array ("group" => "group")) + ->orderAdd("group", "ASC") + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( 'group' => 'group1', ), @@ -683,25 +712,25 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase array ( 'group' => 'group2', ), - ), $res); + ), $res); } - public function test_leftJoin4 () + public function test_leftJoin4() { // Filter on the tbl1, display one column in tbl2 - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->displayAdd ("group"); - $res = $tbl1->select () - ->displayAdd ("group") - ->joinLeft ($tbl2, array ("group"=>"group")) - ->orderAdd ("group", "DESC") - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->displayAdd("group"); + $res = $tbl1->select() + ->displayAdd("group") + ->joinLeft($tbl2, array ("group" => "group")) + ->orderAdd("group", "DESC") + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( - 'usersoo.group' => NULL, + 'usersoo.group' => null, 'groupedoo.group' => 'group2', ), array ( @@ -720,25 +749,25 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'usersoo.group' => 'group1', 'groupedoo.group' => 'group1', ), - ), $res); + ), $res); } - public function test_leftJoin5 () + public function test_leftJoin5() { // Filter on the tbl1 and add order in full mode - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl2->displayAdd ("group"); - $res = $tbl1->select () - ->displayAdd ("group") - ->joinLeft ($tbl2, array ("group"=>"group")) - ->orderAdd ("group", "DESC") - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl2->displayAdd("group"); + $res = $tbl1->select() + ->displayAdd("group") + ->joinLeft($tbl2, array ("group" => "group")) + ->orderAdd("group", "DESC") + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame(array ( array ( - 'usersoo.group' => NULL, + 'usersoo.group' => null, 'groupedoo.group' => 'group2', ), array ( @@ -757,49 +786,49 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'usersoo.group' => 'group1', 'groupedoo.group' => 'group1', ), - ), $res); + ), $res); } /// THREE TABLES /// - public function test_insert6 () + public function test_insert6() { - $tbl1 = $this->tbl1 (); - $tbl4 = $this->tbl4 (); - $tbl4->setForeignObj ($tbl1); - $res = $tbl4->insert () - ->setValues(array ("name"=>"RO", - "group"=>"group1")) - ->execute (); - $tbl4->disconnect (); + $tbl1 = $this->tbl1(); + $tbl4 = $this->tbl4(); + $tbl4->setForeignObj($tbl1); + $res = $tbl4->insert() + ->setValues(array ("name" => "RO", + "group" => "group1")) + ->execute(); + $tbl4->disconnect(); // As the key is not an autoincrement, the lastInsertID can be 0 or 1 - $this->assertGreaterThanOrEqual ($res, "0"); + $this->assertGreaterThanOrEqual($res, "0"); } - public function test_leftJoin6 () + public function test_leftJoin6() { // Two joins tables in left join - $tbl1 = $this->tbl1 (); // Do not display anything from groupedoo - $tbl1->displayAdd ("group") - ->orderAdd ("group", "DESC"); + $tbl1 = $this->tbl1(); // Do not display anything from groupedoo + $tbl1->displayAdd("group") + ->orderAdd("group", "DESC"); - $tbl2 = $this->tbl2 (); // Display the gecos and group from usersoo - $tbl2->displayAdd ("gecos") - ->orderAdd ("gecos", "ASC"); + $tbl2 = $this->tbl2(); // Display the gecos and group from usersoo + $tbl2->displayAdd("gecos") + ->orderAdd("gecos", "ASC"); - $tbl4 = $this->tbl4 (); // Display the name in rightsoo - $tbl4->displayAdd ("name"); - $tbl1->joinLeft ($tbl4, array ("group"=>"group")); - $res = $tbl1->select () - ->joinLeft ($tbl2, array ("group"=>"group")) - ->execute (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $tbl4->disconnect (); - $this->assertSame (array ( + $tbl4 = $this->tbl4(); // Display the name in rightsoo + $tbl4->displayAdd("name"); + $tbl1->joinLeft($tbl4, array ("group" => "group")); + $res = $tbl1->select() + ->joinLeft($tbl2, array ("group" => "group")) + ->execute(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $tbl4->disconnect(); + $this->assertSame(array ( array ( 'groupedoo.group' => 'group2', - 'usersoo.gecos' => NULL, - 'rightsoo.name' => NULL, + 'usersoo.gecos' => null, + 'rightsoo.name' => null, ), array ( 'groupedoo.group' => 'group1', @@ -821,624 +850,756 @@ class DblayerooTest{ENGINE} extends \PHPUnit_Framework_TestCase 'usersoo.gecos' => 'name4', 'rightsoo.name' => 'RO', ), - ), $res); + ), $res); } - public function test_sortOrder1 () + public function test_sortOrder1() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->getSortOrder (); - $tbl1->disconnect (); - $this->assertSame ("order1", $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->getSortOrder(); + $tbl1->disconnect(); + $this->assertSame("order1", $res); } - public function test_sortOrder2 () + public function test_sortOrder2() { - $tbl1 = $this->tbl1 (); - $tbl1->getSortOrder (); - $res = $tbl1->getSortOrder (); - $tbl1->disconnect (); - $this->assertSame ("order2", $res); + $tbl1 = $this->tbl1(); + $tbl1->getSortOrder(); + $res = $tbl1->getSortOrder(); + $tbl1->disconnect(); + $this->assertSame("order2", $res); } - public function test_sortOrder3 () + public function test_sortOrder3() { - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl1->getSortOrder (); - $tbl1->getSortOrder (); - $res = $tbl2->getSortOrder (); - $tbl1->disconnect (); - $tbl2->disconnect (); - $this->assertSame ("order3", $res); + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl1->getSortOrder(); + $tbl1->getSortOrder(); + $res = $tbl2->getSortOrder(); + $tbl1->disconnect(); + $tbl2->disconnect(); + $this->assertSame("order3", $res); } - public function test_displayAdd_NotFull1 () + public function test_displayAdd_NotFull1() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group"); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - $this->assertSame (array ("order1" => $tbl1->sep()."group".$tbl1->sep()), - $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group"); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + $this->assertSame( + array ("order1" => $tbl1->sep() . "group" . $tbl1->sep()), + $res + ); } - public function test_displayAdd_NotFull2 () + public function test_displayAdd_NotFull2() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("distinct group"); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - $this->assertSame (array ( - "order1" => "DISTINCT ".$tbl1->sep()."group".$tbl1->sep()), $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("distinct group"); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + $this->assertSame(array ( + "order1" => "DISTINCT " . $tbl1->sep() . "group" . $tbl1->sep()), $res); } - public function test_displayAdd_NotFull3 () + public function test_displayAdd_NotFull3() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat ( group ) "); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(".$tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by \"group\"". + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat ( group ) "); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(" . $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by \"group\"" . ")"), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(".$tbl1->sep()."group".$tbl1->sep().")"), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(" . $tbl1->sep() . "group" . $tbl1->sep() . ")"), $res); + } } - public function test_displayAdd_NotFull4 () + public function test_displayAdd_NotFull4() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat (distinct group ) "); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(DISTINCT ". - $tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by \"group\"". + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat (distinct group ) "); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(DISTINCT " . + $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by \"group\"" . ")"), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(DISTINCT ". - $tbl1->sep()."group".$tbl1->sep().")"), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(DISTINCT " . + $tbl1->sep() . "group" . $tbl1->sep() . ")"), $res); + } } - public function test_displayAdd_NotFull5 () + public function test_displayAdd_NotFull5() { // With alias - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat (distinct group ) ", "Group Alias"); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(DISTINCT ". - $tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by ". - $tbl1->sep()."group".$tbl1->sep(). - ") AS ". - $tbl1->sep()."Group Alias".$tbl1->sep()), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(DISTINCT ". - $tbl1->sep()."group".$tbl1->sep().") AS ". - $tbl1->sep()."Group Alias".$tbl1->sep()), $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat (distinct group ) ", "Group Alias"); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(DISTINCT " . + $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by " . + $tbl1->sep() . "group" . $tbl1->sep() . + ") AS " . + $tbl1->sep() . "Group Alias" . $tbl1->sep()), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(DISTINCT " . + $tbl1->sep() . "group" . $tbl1->sep() . ") AS " . + $tbl1->sep() . "Group Alias" . $tbl1->sep()), $res); + } } - public function test_displayAdd_Full1 () + public function test_displayAdd_Full1() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group"); - $res = $tbl1->displayGet (true); - $tbl1->disconnect (); - $this->assertSame (array ( - "order1" => $tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep()), - $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group"); + $res = $tbl1->displayGet(true); + $tbl1->disconnect(); + $this->assertSame( + array ( + "order1" => $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep()), + $res + ); } - public function test_displayAdd_Full2 () + public function test_displayAdd_Full2() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("distinct group"); - $res = $tbl1->displayGet (true); - $tbl1->disconnect (); - $this->assertSame (array ( - "order1" => "DISTINCT ".$tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep()), $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("distinct group"); + $res = $tbl1->displayGet(true); + $tbl1->disconnect(); + $this->assertSame(array ( + "order1" => "DISTINCT " . $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep()), $res); } - public function test_displayAdd_Full3 () + public function test_displayAdd_Full3() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat ( group ) "); - $res = $tbl1->displayGet (true); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(".$tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by \"group\"". + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat ( group ) "); + $res = $tbl1->displayGet(true); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(" . $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by \"group\"" . ")"), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(".$tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep().")"), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(" . $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . ")"), $res); + } } - public function test_displayAdd_Full4 () + public function test_displayAdd_Full4() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat (distinct group ) "); - $res = $tbl1->displayGet (true); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(DISTINCT ". - $tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by \"group\"". + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat (distinct group ) "); + $res = $tbl1->displayGet(true); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(DISTINCT " . + $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by \"group\"" . ")"), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(DISTINCT ". - $tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep().")"), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(DISTINCT " . + $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . ")"), $res); + } } - public function test_displayAdd_Full5 () + public function test_displayAdd_Full5() { // With alias - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat (distinct group ) ", "Group Alias"); - $res = $tbl1->displayGet (true); - $tbl1->disconnect (); - if ($this->engine === "pgsql") - $this->assertSame (array ( - "order1" => "string_agg(DISTINCT ". - $tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep(). - "::character varying, ',' order by \"group\"". - ") AS ". - $tbl1->sep()."Group Alias".$tbl1->sep()), $res); - else - $this->assertSame (array ( - "order1" => "GROUP_CONCAT(DISTINCT ". - $tbl1->sep()."groupedoo".$tbl1->sep().".". - $tbl1->sep()."group".$tbl1->sep().") AS ". - $tbl1->sep()."Group Alias".$tbl1->sep()), $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group_concat (distinct group ) ", "Group Alias"); + $res = $tbl1->displayGet(true); + $tbl1->disconnect(); + if ($this->engine === "pgsql") { + $this->assertSame(array ( + "order1" => "string_agg(DISTINCT " . + $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . + "::character varying, ',' order by \"group\"" . + ") AS " . + $tbl1->sep() . "Group Alias" . $tbl1->sep()), $res); + } else { + $this->assertSame(array ( + "order1" => "GROUP_CONCAT(DISTINCT " . + $tbl1->sep() . "groupedoo" . $tbl1->sep() . "." . + $tbl1->sep() . "group" . $tbl1->sep() . ") AS " . + $tbl1->sep() . "Group Alias" . $tbl1->sep()), $res); + } } - public function test_displayAdd_Multiple1 () + public function test_displayAdd_Multiple1() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group"); - $tbl1->displayAdd ("where"); - $res = $tbl1->displayGet (); - $tbl1->disconnect (); - $this->assertSame (array ("order1" => $tbl1->sep()."group".$tbl1->sep(), - "order2" => $tbl1->sep()."where".$tbl1->sep(),), - $res); + $tbl1 = $this->tbl1(); + $tbl1->displayAdd("group"); + $tbl1->displayAdd("where"); + $res = $tbl1->displayGet(); + $tbl1->disconnect(); + $this->assertSame( + array ("order1" => $tbl1->sep() . "group" . $tbl1->sep(), + "order2" => $tbl1->sep() . "where" . $tbl1->sep(),), + $res + ); } - public function test_update5 () + public function test_update5() { // Manage to update the non unique fields // the "where" column is not unique, so it allow to have twice the same // value - $tbl1 = $this->tbl1 (); - $res = $tbl1->update() - ->setValues(array ("where"=>"where2")) - ->execute (); - $tbl1->disconnect (); - $this->assertSame (2, $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->update() + ->setValues(array ("where" => "where2")) + ->execute(); + $tbl1->disconnect(); + $this->assertSame(2, $res); } - public function test_update6 () + public function test_update6() { // Manage to update the primary / unique fields // There is 2 lines in the DB, so the unique key "group" can not be updated // with the same value twice (the result can not be unique) - $tbl1 = $this->tbl1 (); - $this->setExpectedException ("Exception"); - $res = $tbl1->update() - ->setValues(array ("group"=>"group3")) - ->execute (); - $tbl1->disconnect (); + $tbl1 = $this->tbl1(); + $this->setExpectedException("Exception"); + $res = $tbl1->update() + ->setValues(array ("group" => "group3")) + ->execute(); + $tbl1->disconnect(); } - public function test_displayAdd_ComaFields1 () + public function test_displayAdd_ComaFields1() { - $tbl1 = $this->tbl1 (); - $tbl1->displayAdd ("group_concat (group ),group ", - "Group Alias,Group2"); - $res = $tbl1->select () - ->execute (); - $tbl1->disconnect (); - if ($this->engine !== "pgsql") - $this->assertSame (array ( - array ('Group Alias' => 'group1', + $tbl1 = $this->tbl1(); + $tbl1->displayAdd( + "group_concat (group ),group ", + "Group Alias,Group2" + ); + $res = $tbl1->select() + ->execute(); + $tbl1->disconnect(); + if ($this->engine !== "pgsql") { + $this->assertSame(array ( + array ('Group Alias' => 'group1', 'Group2' => 'group1',), - array ('Group Alias' => 'group2', + array ('Group Alias' => 'group2', 'Group2' => 'group2',), - ), $res); + ), $res); + } } - public function test_displayAdd_DISTINCT1 () + public function test_displayAdd_DISTINCT1() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->select () - ->displayAdd ("distinct where", "ALIAS") - ->execute (); - $tbl1->disconnect (); - $this->assertSame (array (0=>array ("ALIAS"=>"where2")), - $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->select() + ->displayAdd("distinct where", "ALIAS") + ->execute(); + $tbl1->disconnect(); + $this->assertSame( + array (0 => array ("ALIAS" => "where2")), + $res + ); } - public function test_orderAdd_alias1 () + public function test_orderAdd_alias1() { - $tbl2 = $this->tbl2 (); - $res = $tbl2->select () - ->displayAdd ("uid", "max") - ->orderAdd ("max","ASC") - ->execute (); - $tbl2->disconnect (); - $this->assertSame (array ( + $tbl2 = $this->tbl2(); + $res = $tbl2->select() + ->displayAdd("uid", "max") + ->orderAdd("max", "ASC") + ->execute(); + $tbl2->disconnect(); + $this->assertSame(array ( array ('max' => 1), array ('max' => 4), array ('max' => 5), array ('max' => 6), - ), $res); + ), $res); } - public function test_displayAdd_MAX_GROUPBY1 () + public function test_displayAdd_MAX_GROUPBY1() { - $tbl2 = $this->tbl2 (); - $res = $tbl2->select () - ->displayAdd ("MAX(uid)", "max") - ->displayAdd ("gecos") - ->orderAdd ("max","ASC") - ->execute (); - $tbl2->disconnect (); - $this->assertSame (array ( - array ('max' => 1, 'gecos' => 'name'), - array ('max' => 4, 'gecos' => 'name2'), - array ('max' => 5, 'gecos' => 'name3'), - array ('max' => 6, 'gecos' => 'name4')), - $res); + $tbl2 = $this->tbl2(); + $res = $tbl2->select() + ->displayAdd("MAX(uid)", "max") + ->displayAdd("gecos") + ->orderAdd("max", "ASC") + ->execute(); + $tbl2->disconnect(); + $this->assertSame( + array ( + array ('max' => 1, 'gecos' => 'name'), + array ('max' => 4, 'gecos' => 'name2'), + array ('max' => 5, 'gecos' => 'name3'), + array ('max' => 6, 'gecos' => 'name4')), + $res + ); } - public function test_displayAdd_MAX_GROUPBY2 () + public function test_displayAdd_MAX_GROUPBY2() { - $tbl2 = $this->tbl2 (); - $res = $tbl2->select () - ->displayAdd ("MAX(uid)") - ->execute (); - $tbl2->disconnect (); - $this->assertSame (array (array ('MAX(uid)' => 6)), $res); + $tbl2 = $this->tbl2(); + $res = $tbl2->select() + ->displayAdd("MAX(uid)") + ->execute(); + $tbl2->disconnect(); + $this->assertSame(array (array ('MAX(uid)' => 6)), $res); } - public function test_displayAdd_MAX_GROUPBY3 () + public function test_displayAdd_MAX_GROUPBY3() { - $tbl1 = $this->tbl1 (); - $tbl2 = $this->tbl2 (); - $tbl1->select () - ->displayAdd ("group"); - $res = $tbl2->select () - ->displayAdd ("MAX(uid)") - ->joinInner ($tbl1, array ("group"=>"group")) - ->execute (); - $tbl2->disconnect (); - $this->assertSame (array (array ( + $tbl1 = $this->tbl1(); + $tbl2 = $this->tbl2(); + $tbl1->select() + ->displayAdd("group"); + $res = $tbl2->select() + ->displayAdd("MAX(uid)") + ->joinInner($tbl1, array ("group" => "group")) + ->execute(); + $tbl2->disconnect(); + $this->assertSame(array (array ( 'groupedoo.group' => 'group1', 'MAX(usersoo.uid)' => 6, - )), $res); + )), $res); } - public function test_GROUPCONCATwithAlias1 () + public function test_GROUPCONCATwithAlias1() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->select () - ->displayAdd ("GROUP_CONCAT(group)", "groups") - ->execute (); - $this->assertSame (array (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->select() + ->displayAdd("GROUP_CONCAT(group)", "groups") + ->execute(); + $this->assertSame(array (array ( 'groups' => 'group1,group2' - )), $res); + )), $res); } - public function test_GROUPCONCATwithAlias2 () + public function test_GROUPCONCATwithAlias2() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->select () - ->displayAdd ("GROUP_CONCAT(group,',')", "groups") - ->execute (); - $this->assertSame (array (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->select() + ->displayAdd("GROUP_CONCAT(group,',')", "groups") + ->execute(); + $this->assertSame(array (array ( 'groups' => 'group1,group2' - )), $res); + )), $res); } - public function test_GROUPCONCATwithAlias3 () + public function test_GROUPCONCATwithAlias3() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->select () - ->displayAdd ("GROUP_CONCAT(group,' ')", "groups") - ->execute (); - $this->assertSame (array (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->select() + ->displayAdd("GROUP_CONCAT(group,' ')", "groups") + ->execute(); + $this->assertSame(array (array ( 'groups' => 'group1 group2' - )), $res); + )), $res); } - public function test_listTables_1 () + public function test_listTables_1() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->listTables (); - if ($this->engine === "sqlite") - $this->assertSame (array ( - 0 => 'groupedoo', - 1 => 'rightsoo', - 2 => 'usersoo', - ), $res); - else - $this->assertSame (array ( - 0 => 'grouped', - 1 => 'groupedoo', - 2 => 'multiple', - 3 => 'multiple2', - 4 => 'readOR', - 5 => 'rightsoo', - 6 => 'users', - 7 => 'users3', - 8 => 'usersoo', - ), $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->listTables(); + if ($this->engine === "sqlite") { + $this->assertSame(array ( + 0 => 'groupedoo', + 1 => 'rightsoo', + 2 => 'usersoo', + ), $res); + } else { + $this->assertSame(array ( + 0 => 'grouped', + 1 => 'groupedoo', + 2 => 'multiple', + 3 => 'multiple2', + 4 => 'readOR', + 5 => 'rightsoo', + 6 => 'users', + 7 => 'users3', + 8 => 'usersoo', + ), $res); + } } //// CHECK REAL TYPES TESTS //// - public function test_checkRealType_integerPositive_1 () + public function test_checkRealType_integerPositive_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_integerPositive", - "1", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_integerPositive", + "1", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_integerPositive_2 () + public function test_checkRealType_integerPositive_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_integerPositive", - "-1", ""); - $this->assertSame ("Invalid positive integer : ". + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_integerPositive", + "-1", + "" + ); + $this->assertSame("Invalid positive integer : " . "can not start by minus sign", $res); } - public function test_checkRealType_integerPositive_3 () + public function test_checkRealType_integerPositive_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_integerPositive", - "0777", ""); - $this->assertSame ("Invalid positive integer : ". + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_integerPositive", + "0777", + "" + ); + $this->assertSame("Invalid positive integer : " . "can not start by Zero", $res); } - public function test_checkRealType_integerPositive_4 () + public function test_checkRealType_integerPositive_4() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_integerPositive", - "07a7", ""); - $this->assertSame ("Invalid positive integer : ". + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_integerPositive", + "07a7", + "" + ); + $this->assertSame("Invalid positive integer : " . "invalid char", $res); } - public function test_checkRealType_allowedchars_1 () + public function test_checkRealType_allowedchars_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_allowedchars", - "1111", "allowedchars(123)"); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_allowedchars", + "1111", + "allowedchars(123)" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_allowedchars_2 () + public function test_checkRealType_allowedchars_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_allowedchars", - "-1", "allowedchars(123)"); - $this->assertSame ("Invalid char provided", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_allowedchars", + "-1", + "allowedchars(123)" + ); + $this->assertSame("Invalid char provided", $res); } - public function test_checkRealType_array_1 () + public function test_checkRealType_array_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_array", - "235", "array('123','235','256')"); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_array", + "235", + "array('123','235','256')" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_array_2 () + public function test_checkRealType_array_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_array", - "777", "array('123','235','256')"); - $this->assertSame ("Invalid value provided : not in allowed list", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_array", + "777", + "array('123','235','256')" + ); + $this->assertSame("Invalid value provided : not in allowed list", $res); } - public function test_checkRealType_regex_1 () + public function test_checkRealType_regex_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_regex", - "235", "regex(/^\\d+$/)"); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_regex", + "235", + "regex(/^\\d+$/)" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_regex_2 () + public function test_checkRealType_regex_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_regex", - "235", "regex(/^\\d{3}$/)"); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_regex", + "235", + "regex(/^\\d{3}$/)" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_regex_3 () + public function test_checkRealType_regex_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_regex", - "235", "regex(/^\\d{4}$/)"); - $this->assertSame ("Invalid value provided : do not match the regex", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_regex", + "235", + "regex(/^\\d{4}$/)" + ); + $this->assertSame("Invalid value provided : do not match the regex", $res); } - public function test_checkRealType_regex_4 () + public function test_checkRealType_regex_4() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_regex", - "abcdef", "regex(/^[a-z]+$/)"); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_regex", + "abcdef", + "regex(/^[a-z]+$/)" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_regex_5 () + public function test_checkRealType_regex_5() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_regex", - "Abcdef", "regex(/^[a-z]+$/)"); - $this->assertSame ("Invalid value provided : do not match the regex", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_regex", + "Abcdef", + "regex(/^[a-z]+$/)" + ); + $this->assertSame("Invalid value provided : do not match the regex", $res); } - public function test_checkRealType_mail_1 () + public function test_checkRealType_mail_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_mail", - "toto@example.com", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_mail", + "toto@example.com", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_mail_2 () + public function test_checkRealType_mail_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_mail", - "toto@", ""); - $this->assertSame ("Invalid mail provided", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_mail", + "toto@", + "" + ); + $this->assertSame("Invalid mail provided", $res); } - public function test_checkRealType_uuid_1 () + public function test_checkRealType_uuid_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_uuid", - "4e799e3f-f376-46e5-a5db-85200949987e", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_uuid", + "4e799e3f-f376-46e5-a5db-85200949987e", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_uuid_2 () + public function test_checkRealType_uuid_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_uuid", - "4E799E3F-F376-46E5-A5DB-85200949987E", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_uuid", + "4E799E3F-F376-46E5-A5DB-85200949987E", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_uuid_3 () + public function test_checkRealType_uuid_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_uuid", - "4E799E3F-F376-46E5+A5DB+85200949987E", ""); - $this->assertSame ("Invalid UUID provided : invalid char", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_uuid", + "4E799E3F-F376-46E5+A5DB+85200949987E", + "" + ); + $this->assertSame("Invalid UUID provided : invalid char", $res); } - public function test_checkRealType_uuid_4 () + public function test_checkRealType_uuid_4() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_uuid", - "4E799E3F5F376546E55A5DB585200949987E", ""); - $this->assertSame ("Invalid UUID provided : missing dash", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_uuid", + "4E799E3F5F376546E55A5DB585200949987E", + "" + ); + $this->assertSame("Invalid UUID provided : missing dash", $res); } - public function test_checkRealType_sqldate_1 () + public function test_checkRealType_sqldate_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldate", - "2018-10-24", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldate", + "2018-10-24", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_sqldate_2 () + public function test_checkRealType_sqldate_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldate", - "2018/10/24", ""); - $this->assertSame ("Invalid date provided : invalid chars", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldate", + "2018/10/24", + "" + ); + $this->assertSame("Invalid date provided : invalid chars", $res); } - public function test_checkRealType_sqldate_3 () + public function test_checkRealType_sqldate_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldate", - "2018-10-32", ""); - $this->assertSame ("Invalid date provided : can not parse the date", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldate", + "2018-10-32", + "" + ); + $this->assertSame("Invalid date provided : can not parse the date", $res); } - public function test_checkRealType_sqltime_1 () + public function test_checkRealType_sqltime_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqltime", - "12:34:56", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqltime", + "12:34:56", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_sqltime_2 () + public function test_checkRealType_sqltime_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqltime", - "12;22;22", ""); - $this->assertSame ("Invalid time provided : invalid chars", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqltime", + "12;22;22", + "" + ); + $this->assertSame("Invalid time provided : invalid chars", $res); } - public function test_checkRealType_sqltime_3 () + public function test_checkRealType_sqltime_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqltime", - "32:34:56", ""); - $this->assertSame ("Invalid time provided : can not parse the time", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqltime", + "32:34:56", + "" + ); + $this->assertSame("Invalid time provided : can not parse the time", $res); } - public function test_checkRealType_sqldatetime_1 () + public function test_checkRealType_sqldatetime_1() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldatetime", - "2018-10-24 22:23:24", ""); - $this->assertSame (null, $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldatetime", + "2018-10-24 22:23:24", + "" + ); + $this->assertSame(null, $res); } - public function test_checkRealType_sqldatetime_2 () + public function test_checkRealType_sqldatetime_2() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldatetime", - "2018/10/24", ""); - $this->assertSame ("Invalid date and time provided : invalid length", $res); + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldatetime", + "2018/10/24", + "" + ); + $this->assertSame("Invalid date and time provided : invalid length", $res); } - public function test_checkRealType_sqldatetime_3 () + public function test_checkRealType_sqldatetime_3() { - $tbl1 = $this->tbl1 (); - $res = $this->invokeMethod ($tbl1, "checkRealType_sqldatetime", - "2018-10-24 25:12:25", ""); - $this->assertSame ("Invalid date and time provided : ". + $tbl1 = $this->tbl1(); + $res = $this->invokeMethod( + $tbl1, + "checkRealType_sqldatetime", + "2018-10-24 25:12:25", + "" + ); + $this->assertSame("Invalid date and time provided : " . "can not parse the date", $res); } //// TEST REAL TYPES //// - public function test_checkRealTypes_1 () + public function test_checkRealTypes_1() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->checkRealTypes (array ("group" => "notempty")); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->checkRealTypes(array ("group" => "notempty")); + $this->assertSame(array ( "object" => "The field can not be empty", "where" => "The field can not be empty", ), $res); } - public function test_checkRealTypes_2 () + public function test_checkRealTypes_2() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->checkRealTypes (array ("group" => "not valid")); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->checkRealTypes(array ("group" => "not valid")); + $this->assertSame(array ( "group" => "Invalid value provided : do not match the regex", "object" => "The field can not be empty", "where" => "The field can not be empty", ), $res); } - public function test_checkRealTypes_3 () + public function test_checkRealTypes_3() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->checkRealTypes (array ("group" => "notempty"), true); - $this->assertSame (array (), $res); + $tbl1 = $this->tbl1(); + $res = $tbl1->checkRealTypes(array ("group" => "notempty"), true); + $this->assertSame(array (), $res); } - public function test_checkRealTypes_4 () + public function test_checkRealTypes_4() { - $tbl1 = $this->tbl1 (); - $res = $tbl1->checkRealTypes (array ("group" => "not valid"), true); - $this->assertSame (array ( + $tbl1 = $this->tbl1(); + $res = $tbl1->checkRealTypes(array ("group" => "not valid"), true); + $this->assertSame(array ( "group" => "Invalid value provided : do not match the regex", ), $res); } -} + } diff --git a/Tests/EncryptTest.php b/Tests/EncryptTest.php index 44be94f..7e3dccb 100644 --- a/Tests/EncryptTest.php +++ b/Tests/EncryptTest.php @@ -1,4 +1,5 @@ @@ -13,132 +14,159 @@ class EncryptTest extends \PHPUnit_Framework_TestCase { /** Check the length of the otken with cipher */ - public function testEncrypt1 () - { - $encrypt = new Encrypt (); - $res = $encrypt->encrypt ("TextToEncode", - "123456789012345678901234"); - $this->assertSame (strlen ($res), 24); - } + public function testEncrypt1() + { + $encrypt = new Encrypt(); + $res = $encrypt->encrypt( + "TextToEncode", + "123456789012345678901234" + ); + $this->assertSame(strlen($res), 24); + } /** Check if the encrypt/decrypt process return the same result */ - public function testEncrypt2 () - { - $encrypt = new Encrypt (); - $payload = "TextToEncode"; - $ckey = "123456789012345678901234"; - $token = $encrypt->encrypt ($payload, $ckey); - $res = $encrypt->decrypt ($token, $ckey); - $this->assertSame ($res, $payload); - } + public function testEncrypt2() + { + $encrypt = new Encrypt(); + $payload = "TextToEncode"; + $ckey = "123456789012345678901234"; + $token = $encrypt->encrypt($payload, $ckey); + $res = $encrypt->decrypt($token, $ckey); + $this->assertSame($res, $payload); + } /** Check if the encrypted part is well unreadable */ - public function testEncrypt3 () - { - $encrypt = new Encrypt (); - $payload = "TextToEncode"; - $token = $encrypt->encrypt ($payload, "123456789012345678901234"); - $res = strpos ($token, "Text"); - $this->assertSame ($res, false); - } + public function testEncrypt3() + { + $encrypt = new Encrypt(); + $payload = "TextToEncode"; + $token = $encrypt->encrypt($payload, "123456789012345678901234"); + $res = strpos($token, "Text"); + $this->assertSame($res, false); + } /** Encrypt : Invalid Cipher method */ - public function testInvalidCypher1 () - { - $this->expectException ("Exception", - "Invalid cipher provided to encrypt method : doesn't exists in OpenSSL", - 500); - $encrypt = new Encrypt (); - $payload = "TextToEncode"; - $token = $encrypt->encrypt ($payload, "123456789012345678901234", "TOTO"); - } + public function testInvalidCypher1() + { + $this->expectException( + "Exception", + "Invalid cipher provided to encrypt method : doesn't exists in OpenSSL", + 500 + ); + $encrypt = new Encrypt(); + $payload = "TextToEncode"; + $token = $encrypt->encrypt($payload, "123456789012345678901234", "TOTO"); + } /** Encrypt : Invalid Payload to encrypt */ - public function testInvalidPayload () - { - $this->expectException ("Exception", - "Invalid payload provided to encrypt method : Not a string", - 500); - $encrypt = new Encrypt (); - $payload = array ("Invalid"); - $token = $encrypt->encrypt ($payload, "123456789012345678901234"); - } + public function testInvalidPayload() + { + $this->expectException( + "Exception", + "Invalid payload provided to encrypt method : Not a string", + 500 + ); + $encrypt = new Encrypt(); + $payload = array ("Invalid"); + $token = $encrypt->encrypt($payload, "123456789012345678901234"); + } /** Encrypt : Invalid Cipher Key to encrypt */ - public function testInvalidCipherKey () - { - $this->expectException ("Exception", - "Invalid cipherKey provided to encrypt method : ". - "length different of 24 chars", 500); - $encrypt = new Encrypt (); - $payload = "Payload"; - $token = $encrypt->encrypt ($payload, "124"); - } + public function testInvalidCipherKey() + { + $this->expectException( + "Exception", + "Invalid cipherKey provided to encrypt method : " . + "length different of 24 chars", + 500 + ); + $encrypt = new Encrypt(); + $payload = "Payload"; + $token = $encrypt->encrypt($payload, "124"); + } /** Decrypt : invalid cipher text */ - public function testDecryptInvalidCipherKey () - { - $this->expectException ("Exception", - "Invalid cipherKey provided to decrypt method : ". - "length different of 24 chars", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt ("zfz", "124"); - } + public function testDecryptInvalidCipherKey() + { + $this->expectException( + "Exception", + "Invalid cipherKey provided to decrypt method : " . + "length different of 24 chars", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt("zfz", "124"); + } /** Decrypt : empty cipher string */ - public function testDecryptEmptyCipherString () - { - $this->expectException ("Exception", - "Invalid ciphertext provided to decrypt method : empty string", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt ("", "124"); - } + public function testDecryptEmptyCipherString() + { + $this->expectException( + "Exception", + "Invalid ciphertext provided to decrypt method : empty string", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt("", "124"); + } /** Decrypt : Not a string cypher */ - public function testDecryptNotStringCipherString () - { - $this->expectException ("Exception", - "Invalid ciphertext provided to decrypt method : not a string", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt (array (), "124"); - } + public function testDecryptNotStringCipherString() + { + $this->expectException( + "Exception", + "Invalid ciphertext provided to decrypt method : not a string", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt(array (), "124"); + } /** Decrypt : Not a string cypher key */ - public function testDecryptNotStringCipherKey () - { - $this->expectException ("Exception", - "Invalid cipherkey provided to decrypt method : not a string", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt ("1224", array ()); - } + public function testDecryptNotStringCipherKey() + { + $this->expectException( + "Exception", + "Invalid cipherkey provided to decrypt method : not a string", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt("1224", array ()); + } /** Decrypt : Not a cipher method string */ - public function testDecryptNotStringCipherMethod () - { - $this->expectException ("Exception", - "Invalid cipherMethod provided to decrypt method : not a string", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt ("1224", "1234", array ()); - } + public function testDecryptNotStringCipherMethod() + { + $this->expectException( + "Exception", + "Invalid cipherMethod provided to decrypt method : not a string", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt("1224", "1234", array ()); + } /** Decrypt : Not a known cipher method */ - public function testDecryptUnknownCipherMethod () - { - $this->expectException ("Exception", - "Invalid cipherMethod provided to decrypt method : ". - "doesn't exists in OpenSSL", 500); - $encrypt = new Encrypt (); - $token = $encrypt->decrypt ("1224", "1234", "unknown"); - } + public function testDecryptUnknownCipherMethod() + { + $this->expectException( + "Exception", + "Invalid cipherMethod provided to decrypt method : " . + "doesn't exists in OpenSSL", + 500 + ); + $encrypt = new Encrypt(); + $token = $encrypt->decrypt("1224", "1234", "unknown"); + } } diff --git a/Tests/FileTest.php b/Tests/FileTest.php index a6f1e3e..f18fea4 100644 --- a/Tests/FileTest.php +++ b/Tests/FileTest.php @@ -1,4 +1,5 @@ @@ -12,499 +13,517 @@ use Domframework\File; /** Test the domframework File part */ class FileTest extends \PHPUnit_Framework_TestCase { - public function testinit () - { - exec ("rm -rf /tmp/testDFFileDir"); - } + public function testinit() + { + exec("rm -rf /tmp/testDFFileDir"); + } - public function testRealPath01 () - { - $file = new File (); - $res = $file->realpath ("/tmp"); - $this->assertSame($res, "/tmp"); - } + public function testRealPath01() + { + $file = new File(); + $res = $file->realpath("/tmp"); + $this->assertSame($res, "/tmp"); + } - public function testRealPath02 () - { - $file = new File (); - $res = $file->realpath ("////tmp"); - $this->assertSame($res, "/tmp"); - } + public function testRealPath02() + { + $file = new File(); + $res = $file->realpath("////tmp"); + $this->assertSame($res, "/tmp"); + } - public function testRealPath03 () - { - $file = new File (); - $res = $file->realpath ("////tmp////"); - $this->assertSame($res, "/tmp"); - } + public function testRealPath03() + { + $file = new File(); + $res = $file->realpath("////tmp////"); + $this->assertSame($res, "/tmp"); + } - public function testRealPath04 () - { - $file = new File (); - $res = $file->realpath (".////tmp////"); - $this->assertSame($res, "./tmp"); - } + public function testRealPath04() + { + $file = new File(); + $res = $file->realpath(".////tmp////"); + $this->assertSame($res, "./tmp"); + } - public function testRealPath05 () - { - $file = new File (); - $res = $file->realpath ("../../../../../tmp/file"); - $this->assertSame($res, "/tmp/file"); - } + public function testRealPath05() + { + $file = new File(); + $res = $file->realpath("../../../../../tmp/file"); + $this->assertSame($res, "/tmp/file"); + } - public function testRealPath06 () - { - $file = new File (); - $res = $file->realpath ("../../../../../tmp/file/../../../.."); - $this->assertSame($res, "/"); - } + public function testRealPath06() + { + $file = new File(); + $res = $file->realpath("../../../../../tmp/file/../../../.."); + $this->assertSame($res, "/"); + } - public function testRealPath07 () - { - $file = new File (); - $res = $file->realpath (".././././../tmp/file/../././.."); - $this->assertSame($res, "/"); - } + public function testRealPath07() + { + $file = new File(); + $res = $file->realpath(".././././../tmp/file/../././.."); + $this->assertSame($res, "/"); + } - public function testRealPath11 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath ("/tmp2"); - $this->assertSame($res, "/tmp/tmp2"); - } + public function testRealPath11() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath("/tmp2"); + $this->assertSame($res, "/tmp/tmp2"); + } - public function testRealPath12 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath ("////tmp2"); - $this->assertSame($res, "/tmp/tmp2"); - } + public function testRealPath12() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath("////tmp2"); + $this->assertSame($res, "/tmp/tmp2"); + } - public function testRealPath13 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath ("////tmp2////"); - $this->assertSame($res, "/tmp/tmp2"); - } + public function testRealPath13() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath("////tmp2////"); + $this->assertSame($res, "/tmp/tmp2"); + } - public function testRealPath14 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath (".////tmp2////"); - $this->assertSame($res, "/tmp/tmp2"); - } + public function testRealPath14() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath(".////tmp2////"); + $this->assertSame($res, "/tmp/tmp2"); + } - public function testRealPath15 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath ("../../../../../tmp2/file"); - $this->assertSame($res, "/tmp/tmp2/file"); - } + public function testRealPath15() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath("../../../../../tmp2/file"); + $this->assertSame($res, "/tmp/tmp2/file"); + } - public function testRealPath16 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath ("../../../../../tmp2/file/../../../.."); - $this->assertSame($res, "/tmp"); - } + public function testRealPath16() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath("../../../../../tmp2/file/../../../.."); + $this->assertSame($res, "/tmp"); + } - public function testRealPath17 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->realpath (".././././../tmp2/file/../././.."); - $this->assertSame($res, "/tmp"); - } + public function testRealPath17() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->realpath(".././././../tmp2/file/../././.."); + $this->assertSame($res, "/tmp"); + } - public function testGetcwd1 () - { - $file = new File (); - $res = $file->getcwd (); - $this->assertSame($res, "."); - } + public function testGetcwd1() + { + $file = new File(); + $res = $file->getcwd(); + $this->assertSame($res, "."); + } - public function testGetcwd2 () - { - $file = new File (); - $file->chdir ("/tmp"); - $res = $file->getcwd (); - $this->assertSame($res, "/tmp"); - } + public function testGetcwd2() + { + $file = new File(); + $file->chdir("/tmp"); + $res = $file->getcwd(); + $this->assertSame($res, "/tmp"); + } - public function testGetcwd3 () - { - $this->setExpectedException ("Exception", "Path '/NON EXISTS' not found"); - $file = new File (); - $file->chdir ("/NON EXISTS"); - $res = $file->getcwd (); - } - public function testGetcwd4 () - { - $file = new File (); - $file->chdir ("/../../../tmp"); - $res = $file->getcwd (); - $this->assertSame($res, "/tmp"); - } + public function testGetcwd3() + { + $this->setExpectedException("Exception", "Path '/NON EXISTS' not found"); + $file = new File(); + $file->chdir("/NON EXISTS"); + $res = $file->getcwd(); + } + public function testGetcwd4() + { + $file = new File(); + $file->chdir("/../../../tmp"); + $res = $file->getcwd(); + $this->assertSame($res, "/tmp"); + } - public function testGetcwd5 () - { - $file = new File (); - $file->chdir ("../../../../../../tmp"); - $res = $file->getcwd (); - $this->assertSame($res, "/tmp"); - } + public function testGetcwd5() + { + $file = new File(); + $file->chdir("../../../../../../tmp"); + $res = $file->getcwd(); + $this->assertSame($res, "/tmp"); + } - public function testGetcwd6 () - { - $this->setExpectedException ("Exception", "Path './tmp' not found"); - $file = new File (); - $file->chdir ("./tmp"); - $res = $file->getcwd (); - } + public function testGetcwd6() + { + $this->setExpectedException("Exception", "Path './tmp' not found"); + $file = new File(); + $file->chdir("./tmp"); + $res = $file->getcwd(); + } - public function testGetcwd7 () - { - $this->setExpectedException ("Exception", - "Path '/tmp/NON EXISTS' not found"); - $file = new File (); - $file->chdir ("/tmp/NON EXISTS"); - $res = $file->getcwd (); - } + public function testGetcwd7() + { + $this->setExpectedException( + "Exception", + "Path '/tmp/NON EXISTS' not found" + ); + $file = new File(); + $file->chdir("/tmp/NON EXISTS"); + $res = $file->getcwd(); + } - public function testGetcwd8 () - { - $this->setExpectedException ("Exception", - "Parent Path '/NON EXISTS/' not found"); - $file = new File (); - $file->chdir ("/NON EXISTS/tmp"); - $res = $file->getcwd (); - } + public function testGetcwd8() + { + $this->setExpectedException( + "Exception", + "Parent Path '/NON EXISTS/' not found" + ); + $file = new File(); + $file->chdir("/NON EXISTS/tmp"); + $res = $file->getcwd(); + } - public function testchroot1 () - { - $this->setExpectedException ("Exception"); - $file = new File (); - $res = $file->chroot ("non exists"); - } + public function testchroot1() + { + $this->setExpectedException("Exception"); + $file = new File(); + $res = $file->chroot("non exists"); + } - public function testchroot2 () - { - $file = new File (); - $res = $file->chroot ("/tmp"); - $this->assertSame($res, true); - } + public function testchroot2() + { + $file = new File(); + $res = $file->chroot("/tmp"); + $this->assertSame($res, true); + } // Without chroot - public function testMkdir1 () - { - $file = new File (); - $res = $file->mkdir ("/tmp/testmkdir1-".time()); - $this->assertSame($res, true); - } + public function testMkdir1() + { + $file = new File(); + $res = $file->mkdir("/tmp/testmkdir1-" . time()); + $this->assertSame($res, true); + } // With chroot in tmp - public function testMkdir2 () - { - $file = new File (); - $res = $file->chroot ("/tmp"); - $res = $file->mkdir ("/testmkdir2-".time()); - $this->assertSame($res, true); - } + public function testMkdir2() + { + $file = new File(); + $res = $file->chroot("/tmp"); + $res = $file->mkdir("/testmkdir2-" . time()); + $this->assertSame($res, true); + } // Without chroot and relative - public function testMkdir3 () - { - $file = new File (); - $res = $file->mkdir ("/tmp/testmkdir3-".time()); - $this->assertSame($res, true); - } + public function testMkdir3() + { + $file = new File(); + $res = $file->mkdir("/tmp/testmkdir3-" . time()); + $this->assertSame($res, true); + } // With chroot in tmp and in relative - public function testMkdir4 () - { - $file = new File (); - $res = $file->chroot ("/tmp"); - $res = $file->mkdir ("testmkdir4-".time()); - $this->assertSame($res, true); - } + public function testMkdir4() + { + $file = new File(); + $res = $file->chroot("/tmp"); + $res = $file->mkdir("testmkdir4-" . time()); + $this->assertSame($res, true); + } // With chroot in tmp - public function testChdir1 () - { - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->chdir ("/testDFFileDir"); - $res = $file->getcwd (); - $this->assertSame($res, "/testDFFileDir"); - } + public function testChdir1() + { + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->chdir("/testDFFileDir"); + $res = $file->getcwd(); + $this->assertSame($res, "/testDFFileDir"); + } // With chroot in tmp - public function testChdir2 () - { - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->chroot ("/"); - $file->chdir ("/testDFFileDir"); - $res = $file->getcwd (); - $this->assertSame($res, "/testDFFileDir"); - } + public function testChdir2() + { + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->chroot("/"); + $file->chdir("/testDFFileDir"); + $res = $file->getcwd(); + $this->assertSame($res, "/testDFFileDir"); + } // With chroot in tmp - public function testChdir3 () - { - $this->setExpectedException ("Exception", - "Path '/tmp/testDFFileDir/NON EXISTS' not found"); - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->chroot ("/testDFFileDir"); - $file->chdir ("/NON EXISTS"); - } + public function testChdir3() + { + $this->setExpectedException( + "Exception", + "Path '/tmp/testDFFileDir/NON EXISTS' not found" + ); + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->chroot("/testDFFileDir"); + $file->chdir("/NON EXISTS"); + } // With chroot in tmp - public function testChdir4 () - { - $this->setExpectedException ("Exception", - "Parent Path '/tmp/tmp/' not found"); - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->chroot (".."); - $file->chdir ("/tmp/testDFFileDir"); - } + public function testChdir4() + { + $this->setExpectedException( + "Exception", + "Parent Path '/tmp/tmp/' not found" + ); + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->chroot(".."); + $file->chdir("/tmp/testDFFileDir"); + } - public function testFile_get_contents1 () - { - $this->setExpectedException ("Exception", - "File '/tmp/testDFFileDir' is not a file"); - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $res = $file->file_get_contents ("/testDFFileDir"); - } + public function testFile_get_contents1() + { + $this->setExpectedException( + "Exception", + "File '/tmp/testDFFileDir' is not a file" + ); + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $res = $file->file_get_contents("/testDFFileDir"); + } - public function testFile_get_contents2 () - { - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->touch ("/testDFFileDir/toto"); - $res = $file->file_get_contents ("/testDFFileDir/toto"); - $this->assertSame($res, ""); - } + public function testFile_get_contents2() + { + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->touch("/testDFFileDir/toto"); + $res = $file->file_get_contents("/testDFFileDir/toto"); + $this->assertSame($res, ""); + } - public function testFile_put_contents1 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->file_put_contents ("/testDFFileDir/toto", "content"); - $res = $file->file_get_contents ("/testDFFileDir/toto"); - $this->assertSame($res, "content"); - } + public function testFile_put_contents1() + { + $file = new File(); + $file->chroot("/tmp"); + $file->file_put_contents("/testDFFileDir/toto", "content"); + $res = $file->file_get_contents("/testDFFileDir/toto"); + $this->assertSame($res, "content"); + } - public function testFile_put_contents2 () - { - $this->setExpectedException ("Exception", - "File '/tmp/testDFFileDir' is not a file"); - $file = new File (); - $file->file_put_contents ("/tmp/testDFFileDir", "content"); - } + public function testFile_put_contents2() + { + $this->setExpectedException( + "Exception", + "File '/tmp/testDFFileDir' is not a file" + ); + $file = new File(); + $file->file_put_contents("/tmp/testDFFileDir", "content"); + } - public function testFile_put_contents3 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->file_put_contents ("/testDFFileDir/toto", "content"); - $this->assertSame($res, 7); - } + public function testFile_put_contents3() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->file_put_contents("/testDFFileDir/toto", "content"); + $this->assertSame($res, 7); + } - public function testscandir1 () - { - $file = new File (); - $res = $file->scandir ("/tmp/testDFFileDir"); - $this->assertSame ($res, array ("toto")); - } + public function testscandir1() + { + $file = new File(); + $res = $file->scandir("/tmp/testDFFileDir"); + $this->assertSame($res, array ("toto")); + } - public function testscandir2 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->scandir ("/testDFFileDir"); - $this->assertSame ($res, array ("toto")); - } + public function testscandir2() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->scandir("/testDFFileDir"); + $this->assertSame($res, array ("toto")); + } - public function testscandir3 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->scandir ("/testDFFileDir/"); - $this->assertSame ($res, array ("toto")); - } + public function testscandir3() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->scandir("/testDFFileDir/"); + $this->assertSame($res, array ("toto")); + } - public function testrmdir1 () - { - // Directory not empty and NOT recursive : return false - $file = new File (); - $res = $file->rmdir ("/tmp/testDFFileDir"); - $this->assertSame ($res, false); - } + public function testrmdir1() + { + // Directory not empty and NOT recursive : return false + $file = new File(); + $res = $file->rmdir("/tmp/testDFFileDir"); + $this->assertSame($res, false); + } - public function testrmdir2 () - { - // Directory not empty and NOT recursive : return false - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->rmdir ("/testDFFileDir"); - $this->assertSame ($res, false); - } + public function testrmdir2() + { + // Directory not empty and NOT recursive : return false + $file = new File(); + $file->chroot("/tmp"); + $res = $file->rmdir("/testDFFileDir"); + $this->assertSame($res, false); + } - public function testrmdir3 () - { - // Directory not empty and recursive : return true - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->rmdir ("/testDFFileDir", true); - $this->assertSame ($res, true); - } + public function testrmdir3() + { + // Directory not empty and recursive : return true + $file = new File(); + $file->chroot("/tmp"); + $res = $file->rmdir("/testDFFileDir", true); + $this->assertSame($res, true); + } - public function testUnlink1 () - { - if (file_exists ("/tmp/testDFFileDir")) - rmdir ("/tmp/testDFFileDir"); - $file = new File (); - $file->chroot ("/tmp"); - $file->mkdir ("/testDFFileDir"); - $file->touch ("/testDFFileDir/toto"); - $res = $file->unlink ("/testDFFileDir/toto"); - $this->assertSame ($res, true); - } + public function testUnlink1() + { + if (file_exists("/tmp/testDFFileDir")) { + rmdir("/tmp/testDFFileDir"); + } + $file = new File(); + $file->chroot("/tmp"); + $file->mkdir("/testDFFileDir"); + $file->touch("/testDFFileDir/toto"); + $res = $file->unlink("/testDFFileDir/toto"); + $this->assertSame($res, true); + } - public function testIsDir1 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->is_dir ("//testDFFileDir"); - $this->assertSame ($res, true); - } + public function testIsDir1() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->is_dir("//testDFFileDir"); + $this->assertSame($res, true); + } - public function testIsDir2 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->touch ("/testDFFileDir/toto"); - $res = $file->is_dir ("//testDFFileDir/toto"); - $this->assertSame ($res, false); - } + public function testIsDir2() + { + $file = new File(); + $file->chroot("/tmp"); + $file->touch("/testDFFileDir/toto"); + $res = $file->is_dir("//testDFFileDir/toto"); + $this->assertSame($res, false); + } - public function testIsFile1 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->touch ("/testDFFileDir/toto"); - $res = $file->is_file ("/testDFFileDir/toto"); - $this->assertSame ($res, true); - } + public function testIsFile1() + { + $file = new File(); + $file->chroot("/tmp"); + $file->touch("/testDFFileDir/toto"); + $res = $file->is_file("/testDFFileDir/toto"); + $this->assertSame($res, true); + } - public function testIsFile2 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->touch ("/testDFFileDir/toto"); - $res = $file->is_file ("//testDFFileDir"); - $this->assertSame ($res, false); - } + public function testIsFile2() + { + $file = new File(); + $file->chroot("/tmp"); + $file->touch("/testDFFileDir/toto"); + $res = $file->is_file("//testDFFileDir"); + $this->assertSame($res, false); + } - public function testMkdir5 () - { - $file = new File (); - $file->chroot ("/tmp"); - // The parent doesn't exists and not recursive mode : exception - $this->expectException (); - $res = $file->mkdir ("/testDFFileDir/tptp/titi/poo"); - } + public function testMkdir5() + { + $file = new File(); + $file->chroot("/tmp"); + // The parent doesn't exists and not recursive mode : exception + $this->expectException(); + $res = $file->mkdir("/testDFFileDir/tptp/titi/poo"); + } - public function testMkdir6 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->mkdir ("/testDFFileDir/tptp/titi/poo", 0777, true); - $this->assertSame ($res, true); - } + public function testMkdir6() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->mkdir("/testDFFileDir/tptp/titi/poo", 0777, true); + $this->assertSame($res, true); + } - public function test_glob_1 () - { - $file = new File (); - $file->chroot ("/tmp"); - $res = $file->glob ("/testDFFileDir/*"); - $this->assertSame ($res, array ("/testDFFileDir/toto", + public function test_glob_1() + { + $file = new File(); + $file->chroot("/tmp"); + $res = $file->glob("/testDFFileDir/*"); + $this->assertSame($res, array ("/testDFFileDir/toto", "/testDFFileDir/tptp")); - } + } - public function test_glob_2 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->chdir ("/testDFFileDir"); - $res = $file->glob ("*"); - $this->assertSame ($res, array ("toto", + public function test_glob_2() + { + $file = new File(); + $file->chroot("/tmp"); + $file->chdir("/testDFFileDir"); + $res = $file->glob("*"); + $this->assertSame($res, array ("toto", "tptp")); - } + } - public function test_glob_3 () - { - $file = new File (); - $file->chroot ("/tmp"); - $file->chdir ("/testDFFileDir"); - $res = $file->glob ("/testDFFileDir/*"); - $this->assertSame ($res, array ("/testDFFileDir/toto", + public function test_glob_3() + { + $file = new File(); + $file->chroot("/tmp"); + $file->chdir("/testDFFileDir"); + $res = $file->glob("/testDFFileDir/*"); + $this->assertSame($res, array ("/testDFFileDir/toto", "/testDFFileDir/tptp")); - } + } - public function test_glob_4 () - { - $file = new File (); - $res = $file->glob ("/tmp/testDFFileDir/*"); - $this->assertSame ($res, array ("/tmp/testDFFileDir/toto", + public function test_glob_4() + { + $file = new File(); + $res = $file->glob("/tmp/testDFFileDir/*"); + $this->assertSame($res, array ("/tmp/testDFFileDir/toto", "/tmp/testDFFileDir/tptp")); - } + } - public function test_glob_5 () - { - $file = new File (); - $file->chdir ("/tmp/testDFFileDir"); - $res = $file->glob ("*"); - $this->assertSame ($res, array ("toto", + public function test_glob_5() + { + $file = new File(); + $file->chdir("/tmp/testDFFileDir"); + $res = $file->glob("*"); + $this->assertSame($res, array ("toto", "tptp")); - } + } - public function test_glob_6 () - { - $file = new File (); - $file->chdir ("/tmp/testDFFileDir"); - $res = $file->glob ("/tmp/testDFFileDir/*"); - $this->assertSame ($res, array ("/tmp/testDFFileDir/toto", + public function test_glob_6() + { + $file = new File(); + $file->chdir("/tmp/testDFFileDir"); + $res = $file->glob("/tmp/testDFFileDir/*"); + $this->assertSame($res, array ("/tmp/testDFFileDir/toto", "/tmp/testDFFileDir/tptp")); - } - + } } diff --git a/Tests/FtsTest.php b/Tests/FtsTest.php index 86e151c..a98a7dc 100644 --- a/Tests/FtsTest.php +++ b/Tests/FtsTest.php @@ -1,4 +1,5 @@ @@ -12,170 +13,170 @@ use Domframework\Fts; /** Test the FTS */ class FtsTest extends \PHPUnit_Framework_TestCase { - public function test_tokenizerSearch0 () - { - // Empty - $fts = new Fts (); - $fts->search (""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array (), - "minuses"=>array ())); - } + public function testTokenizerSearch0() + { + // Empty + $fts = new Fts(); + $fts->search(""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array (), + "minuses" => array ())); + } - public function test_tokenizerSearch1 () - { - // Too small - $fts = new Fts (); - $fts->search ("X"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array (), - "minuses"=>array ())); - } + public function testTokenizerSearch1() + { + // Too small + $fts = new Fts(); + $fts->search("X"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array (), + "minuses" => array ())); + } - public function test_tokenizerSearch2 () - { - // One word - $fts = new Fts (); - $fts->search ("XYZ"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ"), - "minuses"=>array (""))); - } + public function testTokenizerSearch2() + { + // One word + $fts = new Fts(); + $fts->search("XYZ"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ"), + "minuses" => array (""))); + } - public function test_tokenizerSearch3 () - { - // Two word - $fts = new Fts (); - $fts->search ("XYZ 123"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ", "123"), - "minuses"=>array ("", ""))); - } + public function testTokenizerSearch3() + { + // Two word + $fts = new Fts(); + $fts->search("XYZ 123"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ", "123"), + "minuses" => array ("", ""))); + } - public function test_tokenizerSearch4 () - { - // Three word - $fts = new Fts (); - $fts->search ("XYZ 123 ABC"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ", "123", "ABC"), - "minuses"=>array ("", "", ""))); - } + public function testTokenizerSearch4() + { + // Three word + $fts = new Fts(); + $fts->search("XYZ 123 ABC"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ", "123", "ABC"), + "minuses" => array ("", "", ""))); + } - public function test_tokenizerSearch5 () - { - // Three word - $fts = new Fts (); - $fts->search ("XYZ 123 ABC KLM"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ", "123", + public function testTokenizerSearch5() + { + // Three word + $fts = new Fts(); + $fts->search("XYZ 123 ABC KLM"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ", "123", "ABC", "KLM"), - "minuses"=>array ("", "", "", ""))); - } + "minuses" => array ("", "", "", ""))); + } - public function test_tokenizerSearch6 () - { - // Three word - $fts = new Fts (); - $fts->search ("Louis-XYZ 123 -AéBCé KLM"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("Louis-XYZ", "123", + public function testTokenizerSearch6() + { + // Three word + $fts = new Fts(); + $fts->search("Louis-XYZ 123 -AéBCé KLM"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("Louis-XYZ", "123", "AéBCé", "KLM"), - "minuses"=>array ("", "", "-", ""))); - } + "minuses" => array ("", "", "-", ""))); + } - public function test_tokenizerSentence0 () - { - // Empty sentence - $fts = new Fts (); - $fts->search ("\"\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array (), - "minuses"=>array ())); - } + public function testTokenizerSentence0() + { + // Empty sentence + $fts = new Fts(); + $fts->search("\"\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array (), + "minuses" => array ())); + } - public function test_tokenizerSentence1 () - { - // One sentence only - $fts = new Fts (); - $fts->search ("\"XYZ 123\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ 123"), - "minuses"=>array (""))); - } + public function testTokenizerSentence1() + { + // One sentence only + $fts = new Fts(); + $fts->search("\"XYZ 123\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ 123"), + "minuses" => array (""))); + } - public function test_tokenizerSentence2 () - { - // Two sentence - $fts = new Fts (); - $fts->search ("\"XYZ 123\" \"ABC KLM\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ 123", "ABC KLM"), - "minuses"=>array ("", ""))); - } + public function testTokenizerSentence2() + { + // Two sentence + $fts = new Fts(); + $fts->search("\"XYZ 123\" \"ABC KLM\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ 123", "ABC KLM"), + "minuses" => array ("", ""))); + } - public function test_tokenizerSentence3 () - { - // Three sentence - $fts = new Fts (); - $fts->search ("\"XYZ 123\" -\"ABC KLM\" \"RPO YUI\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ 123", "ABC KLM", + public function testTokenizerSentence3() + { + // Three sentence + $fts = new Fts(); + $fts->search("\"XYZ 123\" -\"ABC KLM\" \"RPO YUI\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ 123", "ABC KLM", "RPO YUI"), - "minuses"=>array ("", "-", ""))); - } + "minuses" => array ("", "-", ""))); + } - public function test_tokenizerMixed1 () - { - // One word and one sentence, starting by word - $fts = new Fts (); - $fts->search ("XYZ \"ABC KLM\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("XYZ", "ABC KLM"), - "minuses"=>array ("", ""))); - } + public function testTokenizerMixed1() + { + // One word and one sentence, starting by word + $fts = new Fts(); + $fts->search("XYZ \"ABC KLM\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("XYZ", "ABC KLM"), + "minuses" => array ("", ""))); + } - public function test_tokenizerMixed2 () - { - // One word and one sentence, starting by sentence - $fts = new Fts (); - $fts->search ("\"ABC KLM\" XYZ"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ"), - "minuses"=>array ("", ""))); - } + public function testTokenizerMixed2() + { + // One word and one sentence, starting by sentence + $fts = new Fts(); + $fts->search("\"ABC KLM\" XYZ"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("ABC KLM", "XYZ"), + "minuses" => array ("", ""))); + } - public function test_tokenizerMixed3 () - { - // One word and two sentences, starting by sentence - $fts = new Fts (); - $fts->search ("\"ABC KLM\" XYZ \"RPO YUI\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ", + public function testTokenizerMixed3() + { + // One word and two sentences, starting by sentence + $fts = new Fts(); + $fts->search("\"ABC KLM\" XYZ \"RPO YUI\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("ABC KLM", "XYZ", "RPO YUI"), - "minuses"=>array ("", "", ""))); - } + "minuses" => array ("", "", ""))); + } - public function test_tokenizerMixed4 () - { - // Two words and two sentences, starting by sentence - $fts = new Fts (); - $fts->search ("\"ABC KLM\" XYZ \"RPO YUI\" 123"); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ", + public function testTokenizerMixed4() + { + // Two words and two sentences, starting by sentence + $fts = new Fts(); + $fts->search("\"ABC KLM\" XYZ \"RPO YUI\" 123"); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("ABC KLM", "XYZ", "RPO YUI", "123"), - "minuses"=>array ("", "", "", ""))); - } + "minuses" => array ("", "", "", ""))); + } - public function test_tokenizerMixed5 () - { - // Two words and two sentences, starting by a word - $fts = new Fts (); - $fts->search ("123 \"ABC KLM\" XYZ \"RPO YUI\""); - $res = $fts->getTokensMin (); - $this->assertSame ($res, array ("tokens"=>array ("123", "ABC KLM", + public function testTokenizerMixed5() + { + // Two words and two sentences, starting by a word + $fts = new Fts(); + $fts->search("123 \"ABC KLM\" XYZ \"RPO YUI\""); + $res = $fts->getTokensMin(); + $this->assertSame($res, array ("tokens" => array ("123", "ABC KLM", "XYZ", "RPO YUI"), - "minuses"=>array ("", "", "", ""))); - } + "minuses" => array ("", "", "", ""))); + } } diff --git a/Tests/GetoptsTest.php b/Tests/GetoptsTest.php index 586ebc2..20f40b5 100644 --- a/Tests/GetoptsTest.php +++ b/Tests/GetoptsTest.php @@ -1,4 +1,5 @@ @@ -12,173 +13,173 @@ use Domframework\Getopts; /** Test the GetOpts */ class GetoptsTest extends \PHPUnit_Framework_TestCase { - public function test_empty1 () - { - // Empty - $getopts = new Getopts (); - $res = $getopts->help (); - $this->assertSame ($res, "No option defined\n"); - } + public function test_empty1() + { + // Empty + $getopts = new Getopts(); + $res = $getopts->help(); + $this->assertSame($res, "No option defined\n"); + } - public function test_simu1 () - { - $getopts = new Getopts (); - $res = $getopts->simulate ("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); - $this->assertSame (is_object ($res), true); - } + public function test_simu1() + { + $getopts = new Getopts(); + $res = $getopts->simulate("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); + $this->assertSame(is_object($res), true); + } - public function test_add1 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); - $res = $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $this->assertSame (is_object ($res), true); - } + public function test_add1() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); + $res = $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $this->assertSame(is_object($res), true); + } - public function test_add2 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $res = $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $this->assertSame (is_object ($res), true); - } + public function test_add2() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $res = $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $this->assertSame(is_object($res), true); + } - public function test_scan1 () - { - $this->expectException ("Exception", "Provided tokens are not known: -f,-o,-o,-o"); - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->scan (); - } + public function test_scan1() + { + $this->expectException("Exception", "Provided tokens are not known: -f,-o,-o,-o"); + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d -f ii -o 1\ 2 -o \"2 2\" -o 3 -- -bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->scan(); + } - public function test_getShort1 () - { - // One unique value (-h -> true/false) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Help"); - $this->assertSame ($res, true); - } + public function test_getShort1() + { + // One unique value (-h -> true/false) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Help"); + $this->assertSame($res, true); + } - public function test_getShort2 () - { - // Multiple values, two set (-d -d) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array (true,true)); - } + public function test_getShort2() + { + // Multiple values, two set (-d -d) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array (true,true)); + } - public function test_getShort3 () - { - // Multiple values, one set (-d) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array (true)); - } + public function test_getShort3() + { + // Multiple values, one set (-d) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array (true)); + } - public function test_getShort4 () - { - // Multiple values, None set (-d) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array ()); - } + public function test_getShort4() + { + // Multiple values, None set (-d) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array ()); + } - public function test_getLong1 () - { - // One unique value (--help -> true/false) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate --help -d -d "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Help"); - $this->assertSame ($res, true); - } + public function test_getLong1() + { + // One unique value (--help -> true/false) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate --help -d -d "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Help"); + $this->assertSame($res, true); + } - public function test_getLong2 () - { - // Multiple values, two set (-debug --debug) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h --debug --debug "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array (true,true)); - } + public function test_getLong2() + { + // Multiple values, two set (-debug --debug) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h --debug --debug "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array (true,true)); + } - public function test_getLong3 () - { - // Multiple values, one set (-d) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate --help -d "); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array (true)); - } + public function test_getLong3() + { + // Multiple values, one set (-d) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate --help -d "); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array (true)); + } - public function test_getLong4 () - { - // Multiple values, None set (-d) - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->get ("Debug"); - $this->assertSame ($res, array ()); - } + public function test_getLong4() + { + // Multiple values, None set (-d) + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->get("Debug"); + $this->assertSame($res, array ()); + } - public function test_restOfLine1 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d -- -bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->restOfLine (); - $this->assertSame ($res, array ("-bla", "final")); - } + public function test_restOfLine1() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d -- -bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->restOfLine(); + $this->assertSame($res, array ("-bla", "final")); + } - public function test_restOfLine2 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->restOfLine (); - $this->assertSame ($res, array ("bla", "final")); - } + public function test_restOfLine2() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->restOfLine(); + $this->assertSame($res, array ("bla", "final")); + } - public function test_restOfLine3 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -- -bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->restOfLine (); - $this->assertSame ($res, array ("-bla", "final")); - } + public function test_restOfLine3() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -- -bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->restOfLine(); + $this->assertSame($res, array ("-bla", "final")); + } - public function test_programName1 () - { - $getopts = new Getopts (); - $getopts->simulate ("sim\ ulate -h -d -d -- -bla final"); - $getopts->add ("Help", "?h", array ("help","help2"), "Help of the software"); - $getopts->add ("Debug", "d", "debug", "Debug", "DebugLevel", 2); - $res = $getopts->programName (); - $this->assertSame ($res, "sim ulate"); - } + public function test_programName1() + { + $getopts = new Getopts(); + $getopts->simulate("sim\ ulate -h -d -d -- -bla final"); + $getopts->add("Help", "?h", array ("help","help2"), "Help of the software"); + $getopts->add("Debug", "d", "debug", "Debug", "DebugLevel", 2); + $res = $getopts->programName(); + $this->assertSame($res, "sim ulate"); + } } diff --git a/Tests/HttpTest.php b/Tests/HttpTest.php index a87de6f..e68d377 100644 --- a/Tests/HttpTest.php +++ b/Tests/HttpTest.php @@ -1,4 +1,5 @@ @@ -14,47 +15,55 @@ class HttpTest extends \PHPUnit_Framework_TestCase { /** bestChoice : exact existing entry */ - public function testBestChoice1 () - { - $http = new Http (); - $res = $http->bestChoice ( - "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - array ("application/xml"), "text/html"); - $this->assertSame ($res, "application/xml"); - } + public function testBestChoice1() + { + $http = new Http(); + $res = $http->bestChoice( + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + array ("application/xml"), + "text/html" + ); + $this->assertSame($res, "application/xml"); + } /** bestChoice : Generic catch. * Use default value */ - public function testBestChoice2 () - { - $http = new Http (); - $res = $http->bestChoice ( - "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - array ("text/plain"), "text/html"); - $this->assertSame ($res, "text/html"); - } + public function testBestChoice2() + { + $http = new Http(); + $res = $http->bestChoice( + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + array ("text/plain"), + "text/html" + ); + $this->assertSame($res, "text/html"); + } /** bestChoice : no solution : use the default value */ - public function testBestChoice3 () - { - $http = new Http (); - $res = $http->bestChoice ( - "text/html,application/xhtml+xml,application/xml;q=0.9", - array ("text/plain"), "text/html"); - $this->assertSame ($res, "text/html"); - } + public function testBestChoice3() + { + $http = new Http(); + $res = $http->bestChoice( + "text/html,application/xhtml+xml,application/xml;q=0.9", + array ("text/plain"), + "text/html" + ); + $this->assertSame($res, "text/html"); + } /** bestChoice : invalid entry (end with comma). Continue without error and * skip the bad choices */ - public function testBestChoice4 () - { - $http = new Http (); - $res = $http->bestChoice ( - "text/html,application/xhtml+xml,application/xml;q=0.9,", - array ("text/plain"), "text/html"); - $this->assertSame ($res, "text/html"); - } + public function testBestChoice4() + { + $http = new Http(); + $res = $http->bestChoice( + "text/html,application/xhtml+xml,application/xml;q=0.9,", + array ("text/plain"), + "text/html" + ); + $this->assertSame($res, "text/html"); + } } diff --git a/Tests/InifileTest.php b/Tests/InifileTest.php index 4e57e3a..ad70865 100644 --- a/Tests/InifileTest.php +++ b/Tests/InifileTest.php @@ -1,4 +1,5 @@ @@ -12,213 +13,242 @@ use Domframework\Inifile; /** Test the Inifile.php file */ class InifileTest extends \PHPUnit_Framework_TestCase { - public function testsetString001 () - { - $this->setExpectedException ("Exception"); - $inifile = new Inifile (); - $res = $inifile->setString (1, TRUE); - } + public function testsetString001() + { + $this->setExpectedException("Exception"); + $inifile = new Inifile(); + $res = $inifile->setString(1, true); + } - public function testsetString002 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array (), TRUE); - $this->assertSame("", $res); - } + public function testsetString002() + { + $inifile = new Inifile(); + $res = $inifile->setString(array (), true); + $this->assertSame("", $res); + } //// TEST OF THE SECTION PART //// - public function testsetString103 () - { - $this->setExpectedException ("Exception"); - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"), TRUE); - } + public function testsetString103() + { + $this->setExpectedException("Exception"); + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1"), true); + } - public function testsetString104 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array ()), TRUE); - $this->assertSame("[section1]\n\n", $res); - } + public function testsetString104() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array ()), true); + $this->assertSame("[section1]\n\n", $res); + } - public function testsetString105 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0)), TRUE); - $this->assertSame("[section1]\n0 = \"0\"\n\n", $res); - } + public function testsetString105() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0)), true); + $this->assertSame("[section1]\n0 = \"0\"\n\n", $res); + } - public function testsetString106 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>1)), TRUE); - $this->assertSame("[section1]\n0 = \"1\"\n\n", $res); - } + public function testsetString106() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0 => 1)), true); + $this->assertSame("[section1]\n0 = \"1\"\n\n", $res); + } - public function testsetString107 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null)), TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n\n", $res); - } + public function testsetString107() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0 => null)), true); + $this->assertSame("[section1]\n0 = \"null\"\n\n", $res); + } - public function testsetString108 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, 1=>1)), - TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n\n", $res); - } + public function testsetString108() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, 1 => 1)), + true + ); + $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n\n", $res); + } - public function testsetString109 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str")), - TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n\n", - $res); - } + public function testsetString109() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str")), + true + ); + $this->assertSame( + "[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n\n", + $res + ); + } - public function testsetString110 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str", - 3=>array (1,2,3))), - TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n". + public function testsetString110() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str", + 3 => array (1,2,3))), + true + ); + $this->assertSame( + "[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n" . "3[0] = \"1\"\n3[1] = \"2\"\n3[2] = \"3\"\n\n", - $res); - } + $res + ); + } - public function testsetString111 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str", - 3=>array ())), - TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n\n", - $res); - } + public function testsetString111() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str", + 3 => array ())), + true + ); + $this->assertSame( + "[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n\n", + $res + ); + } - public function testsetString112 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str", - "chain"=>array ("key"=>1,2))), - TRUE); - $this->assertSame("[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n". + public function testsetString112() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str", + "chain" => array ("key" => 1,2))), + true + ); + $this->assertSame( + "[section1]\n0 = \"null\"\n1 = \"1\"\n2 = \"str\"\n" . "chain[key] = \"1\"\nchain[0] = \"2\"\n\n", - $res); - } + $res + ); + } //// TEST OF THE NOT SECTION PART //// - public function testsetString203 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"), FALSE); - $this->assertSame("0 = \"section1\"\n\n", $res); - } + public function testsetString203() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1"), false); + $this->assertSame("0 = \"section1\"\n\n", $res); + } - public function testsetString204 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array ()), FALSE); - $this->assertSame("\n", $res); - } + public function testsetString204() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array ()), false); + $this->assertSame("\n", $res); + } - public function testsetString205 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0)), FALSE); - $this->assertSame("section1[0] = \"0\"\n\n", $res); - } + public function testsetString205() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0)), false); + $this->assertSame("section1[0] = \"0\"\n\n", $res); + } - public function testsetString206 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>1)), FALSE); - $this->assertSame("section1[0] = \"1\"\n\n", $res); - } + public function testsetString206() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0 => 1)), false); + $this->assertSame("section1[0] = \"1\"\n\n", $res); + } - public function testsetString207 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null)), FALSE); - $this->assertSame("section1[0] = \"null\"\n\n", $res); - } + public function testsetString207() + { + $inifile = new Inifile(); + $res = $inifile->setString(array ("section1" => array (0 => null)), false); + $this->assertSame("section1[0] = \"null\"\n\n", $res); + } - public function testsetString208 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, 1=>1)), - FALSE); - $this->assertSame("section1[0] = \"null\"\nsection1[1] = \"1\"\n\n", - $res); - } + public function testsetString208() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, 1 => 1)), + false + ); + $this->assertSame( + "section1[0] = \"null\"\nsection1[1] = \"1\"\n\n", + $res + ); + } - public function testsetString209 () - { - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str")), - FALSE); - $this->assertSame("section1[0] = \"null\"\nsection1[1] = \"1\"\n". + public function testsetString209() + { + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str")), + false + ); + $this->assertSame( + "section1[0] = \"null\"\nsection1[1] = \"1\"\n" . "section1[2] = \"str\"\n\n", - $res); - } + $res + ); + } - public function testsetString210 () - { - $this->setExpectedException ("Exception"); - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str", - 3=>array (1,2,3))), - FALSE); - } + public function testsetString210() + { + $this->setExpectedException("Exception"); + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str", + 3 => array (1,2,3))), + false + ); + } - public function testsetString211 () - { - $this->setExpectedException ("Exception"); - $inifile = new Inifile (); - $res = $inifile->setString (array ("section1"=>array (0=>null, - 1=>1, 2=>"str", - 3=>array ())), - FALSE); - } + public function testsetString211() + { + $this->setExpectedException("Exception"); + $inifile = new Inifile(); + $res = $inifile->setString( + array ("section1" => array (0 => null, + 1 => 1, 2 => "str", + 3 => array ())), + false + ); + } //// LOOP TEST : CREATE AN INI STRING AND PARSE IT //// - public function testLoop406 () - { - $inifile = new Inifile (); - $loop = $inifile->setString (array ("section1"=>array (0=>1)), FALSE); -var_dump ($loop); - $res = $inifile->getString ($loop, FALSE); -var_dump ($res); - $this->assertSame(array ("section1"=>array (0=>1)), $res); - } + public function testLoop406() + { + $inifile = new Inifile(); + $loop = $inifile->setString(array ("section1" => array (0 => 1)), false); + var_dump($loop); + $res = $inifile->getString($loop, false); + var_dump($res); + $this->assertSame(array ("section1" => array (0 => 1)), $res); + } - public function testLoop407 () - { - $inifile = new Inifile (); - $loop = $inifile->setString (array ("section1"=>array (0=>null)), FALSE); - $res = $inifile->getString ($loop, FALSE); - $this->assertSame(array ("section1"=>array (0=>null)), $res); - } - - public function testLoop408 () - { - $inifile = new Inifile (); - $loop = $inifile->setString (array ("section1"=>array (0=>"toto")), FALSE); -var_dump ($loop); - $res = $inifile->getString ($loop, FALSE); -var_dump ($res); - $this->assertSame(array ("section1"=>array (0=>"toto")), $res); - } + public function testLoop407() + { + $inifile = new Inifile(); + $loop = $inifile->setString(array ("section1" => array (0 => null)), false); + $res = $inifile->getString($loop, false); + $this->assertSame(array ("section1" => array (0 => null)), $res); + } + public function testLoop408() + { + $inifile = new Inifile(); + $loop = $inifile->setString(array ("section1" => array (0 => "toto")), false); + var_dump($loop); + $res = $inifile->getString($loop, false); + var_dump($res); + $this->assertSame(array ("section1" => array (0 => "toto")), $res); + } } diff --git a/Tests/IpaddressesTest.php b/Tests/IpaddressesTest.php index 2f70b22..1602f57 100644 --- a/Tests/IpaddressesTest.php +++ b/Tests/IpaddressesTest.php @@ -1,4 +1,5 @@ @@ -12,561 +13,561 @@ use Domframework\Ipaddresses; /** Test the Ipaddresses.php file */ class IpaddressesTest extends \PHPUnit_Framework_TestCase { - public function test_validIPAddress1 () - { - $i = new Ipaddresses (); - $res = $i->validIPAddress ("::"); - $this->assertSame (true, $res); - } - public function test_validIPAddress2 () - { - $i = new Ipaddresses (); - $res = $i->validIPAddress ("1::"); - $this->assertSame (true, $res); - } - public function test_validIPAddress3 () - { - $i = new Ipaddresses (); - $res = $i->validIPAddress ("::1"); - $this->assertSame (true, $res); - } - public function test_validIPAddress4 () - { - $i = new Ipaddresses (); - $res = $i->validIPAddress ("2001::1"); - $this->assertSame (true, $res); - } - public function test_validIPAddress5 () - { - $i = new Ipaddresses (); - $res = $i->validIPAddress ("1.2.3.4"); - $this->assertSame (true, $res); - } - public function test_validIPAddress6 () - { - $this->setExpectedException ("Exception"); - $i = new Ipaddresses (); - $res = $i->validIPAddress (""); - } - public function test_validIPAddress7 () - { - $this->setExpectedException ("Exception"); - $i = new Ipaddresses (); - $res = $i->validIPAddress (array ()); - } + public function test_validIPAddress1() + { + $i = new Ipaddresses(); + $res = $i->validIPAddress("::"); + $this->assertSame(true, $res); + } + public function test_validIPAddress2() + { + $i = new Ipaddresses(); + $res = $i->validIPAddress("1::"); + $this->assertSame(true, $res); + } + public function test_validIPAddress3() + { + $i = new Ipaddresses(); + $res = $i->validIPAddress("::1"); + $this->assertSame(true, $res); + } + public function test_validIPAddress4() + { + $i = new Ipaddresses(); + $res = $i->validIPAddress("2001::1"); + $this->assertSame(true, $res); + } + public function test_validIPAddress5() + { + $i = new Ipaddresses(); + $res = $i->validIPAddress("1.2.3.4"); + $this->assertSame(true, $res); + } + public function test_validIPAddress6() + { + $this->setExpectedException("Exception"); + $i = new Ipaddresses(); + $res = $i->validIPAddress(""); + } + public function test_validIPAddress7() + { + $this->setExpectedException("Exception"); + $i = new Ipaddresses(); + $res = $i->validIPAddress(array ()); + } - public function test_validIPv4Address1 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4Address ("::"); - $this->assertSame (false, $res); - } - public function test_validIPv4Address2 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4Address ("1.2.3.4"); - $this->assertSame (true, $res); - } + public function test_validIPv4Address1() + { + $i = new Ipaddresses(); + $res = $i->validIPv4Address("::"); + $this->assertSame(false, $res); + } + public function test_validIPv4Address2() + { + $i = new Ipaddresses(); + $res = $i->validIPv4Address("1.2.3.4"); + $this->assertSame(true, $res); + } - public function test_validIPv6Address1 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("1.2.3.4"); - $this->assertSame (false, $res); - } - public function test_validIPv6Address2 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("::"); - $this->assertSame (true, $res); - } - public function test_validIPv6Address3 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("1::"); - $this->assertSame (true, $res); - } - public function test_validIPv6Address4 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("::1"); - $this->assertSame (true, $res); - } - public function test_validIPv6Address5 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("1::1"); - $this->assertSame (true, $res); - } - public function test_validIPv6Address6 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6Address ("1:1:1"); - $this->assertSame (false, $res); - } + public function test_validIPv6Address1() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("1.2.3.4"); + $this->assertSame(false, $res); + } + public function test_validIPv6Address2() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("::"); + $this->assertSame(true, $res); + } + public function test_validIPv6Address3() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("1::"); + $this->assertSame(true, $res); + } + public function test_validIPv6Address4() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("::1"); + $this->assertSame(true, $res); + } + public function test_validIPv6Address5() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("1::1"); + $this->assertSame(true, $res); + } + public function test_validIPv6Address6() + { + $i = new Ipaddresses(); + $res = $i->validIPv6Address("1:1:1"); + $this->assertSame(false, $res); + } - public function test_validCIDR1 () - { - $i = new Ipaddresses (); - $res = $i->validCIDR (-1); - $this->assertSame (false, $res); - } - public function test_validCIDR2 () - { - $i = new Ipaddresses (); - $res = $i->validCIDR (129); - $this->assertSame (false, $res); - } - public function test_validCIDR3 () - { - $i = new Ipaddresses (); - $res = $i->validCIDR (128); - $this->assertSame (true, $res); - } - public function test_validCIDR4 () - { - $i = new Ipaddresses (); - $res = $i->validCIDR (0); - $this->assertSame (true, $res); - } + public function test_validCIDR1() + { + $i = new Ipaddresses(); + $res = $i->validCIDR(-1); + $this->assertSame(false, $res); + } + public function test_validCIDR2() + { + $i = new Ipaddresses(); + $res = $i->validCIDR(129); + $this->assertSame(false, $res); + } + public function test_validCIDR3() + { + $i = new Ipaddresses(); + $res = $i->validCIDR(128); + $this->assertSame(true, $res); + } + public function test_validCIDR4() + { + $i = new Ipaddresses(); + $res = $i->validCIDR(0); + $this->assertSame(true, $res); + } - public function test_validIPv4CIDR1 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4CIDR (-1); - $this->assertSame (false, $res); - } - public function test_validIPv4CIDR2 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4CIDR (33); - $this->assertSame (false, $res); - } - public function test_validIPv4CIDR3 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4CIDR (32); - $this->assertSame (true, $res); - } - public function test_validIPv4CIDR4 () - { - $i = new Ipaddresses (); - $res = $i->validIPv4CIDR (0); - $this->assertSame (true, $res); - } + public function test_validIPv4CIDR1() + { + $i = new Ipaddresses(); + $res = $i->validIPv4CIDR(-1); + $this->assertSame(false, $res); + } + public function test_validIPv4CIDR2() + { + $i = new Ipaddresses(); + $res = $i->validIPv4CIDR(33); + $this->assertSame(false, $res); + } + public function test_validIPv4CIDR3() + { + $i = new Ipaddresses(); + $res = $i->validIPv4CIDR(32); + $this->assertSame(true, $res); + } + public function test_validIPv4CIDR4() + { + $i = new Ipaddresses(); + $res = $i->validIPv4CIDR(0); + $this->assertSame(true, $res); + } - public function test_validIPv6CIDR1 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6CIDR (-1); - $this->assertSame (false, $res); - } - public function test_validIPv6CIDR2 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6CIDR (129); - $this->assertSame (false, $res); - } - public function test_validIPv6CIDR3 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6CIDR (128); - $this->assertSame (true, $res); - } - public function test_validIPv6CIDR4 () - { - $i = new Ipaddresses (); - $res = $i->validIPv6CIDR (0); - $this->assertSame (true, $res); - } + public function test_validIPv6CIDR1() + { + $i = new Ipaddresses(); + $res = $i->validIPv6CIDR(-1); + $this->assertSame(false, $res); + } + public function test_validIPv6CIDR2() + { + $i = new Ipaddresses(); + $res = $i->validIPv6CIDR(129); + $this->assertSame(false, $res); + } + public function test_validIPv6CIDR3() + { + $i = new Ipaddresses(); + $res = $i->validIPv6CIDR(128); + $this->assertSame(true, $res); + } + public function test_validIPv6CIDR4() + { + $i = new Ipaddresses(); + $res = $i->validIPv6CIDR(0); + $this->assertSame(true, $res); + } - public function test_compressIP1 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("::"); - $this->assertSame ("::", $res); - } - public function test_compressIP2 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("::1"); - $this->assertSame ("::1", $res); - } - public function test_compressIP3 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("2::1"); - $this->assertSame ("2::1", $res); - } - public function test_compressIP4 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("2::"); - $this->assertSame ("2::", $res); - } - public function test_compressIP5 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("2:1:0:3::0:1"); - $this->assertSame ("2:1:0:3::1", $res); - } - public function test_compressIP6 () - { - $i = new Ipaddresses (); - $res = $i->compressIP ("2:1:0:3:0000::1"); - $this->assertSame ("2:1:0:3::1", $res); - } + public function test_compressIP1() + { + $i = new Ipaddresses(); + $res = $i->compressIP("::"); + $this->assertSame("::", $res); + } + public function test_compressIP2() + { + $i = new Ipaddresses(); + $res = $i->compressIP("::1"); + $this->assertSame("::1", $res); + } + public function test_compressIP3() + { + $i = new Ipaddresses(); + $res = $i->compressIP("2::1"); + $this->assertSame("2::1", $res); + } + public function test_compressIP4() + { + $i = new Ipaddresses(); + $res = $i->compressIP("2::"); + $this->assertSame("2::", $res); + } + public function test_compressIP5() + { + $i = new Ipaddresses(); + $res = $i->compressIP("2:1:0:3::0:1"); + $this->assertSame("2:1:0:3::1", $res); + } + public function test_compressIP6() + { + $i = new Ipaddresses(); + $res = $i->compressIP("2:1:0:3:0000::1"); + $this->assertSame("2:1:0:3::1", $res); + } - public function test_uncompressIPv6a () - { - $i = new Ipaddresses (); - $res = $i->uncompressIPv6 ("1::1"); - $this->assertSame ("1:0:0:0:0:0:0:1", $res); - } - public function test_uncompressIPv6b () - { - $i = new Ipaddresses (); - $res = $i->uncompressIPv6 ("1::"); - $this->assertSame ("1:0:0:0:0:0:0:0", $res); - } - public function test_uncompressIPv6c () - { - $i = new Ipaddresses (); - $res = $i->uncompressIPv6 ("::"); - $this->assertSame ("0:0:0:0:0:0:0:0", $res); - } - public function test_uncompressIPv6d () - { - $i = new Ipaddresses (); - $res = $i->uncompressIPv6 ("1.2.3.4"); - $this->assertSame ("1.2.3.4", $res); - } + public function test_uncompressIPv6a() + { + $i = new Ipaddresses(); + $res = $i->uncompressIPv6("1::1"); + $this->assertSame("1:0:0:0:0:0:0:1", $res); + } + public function test_uncompressIPv6b() + { + $i = new Ipaddresses(); + $res = $i->uncompressIPv6("1::"); + $this->assertSame("1:0:0:0:0:0:0:0", $res); + } + public function test_uncompressIPv6c() + { + $i = new Ipaddresses(); + $res = $i->uncompressIPv6("::"); + $this->assertSame("0:0:0:0:0:0:0:0", $res); + } + public function test_uncompressIPv6d() + { + $i = new Ipaddresses(); + $res = $i->uncompressIPv6("1.2.3.4"); + $this->assertSame("1.2.3.4", $res); + } - public function test_groupIPv6a () - { - $this->setExpectedException ("Exception"); - $i = new Ipaddresses (); - $res = $i->groupIPv6 ("1.2.3.4"); - } - public function test_groupIPv6b () - { - $i = new Ipaddresses (); - $res = $i->groupIPv6 ("0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.". + public function test_groupIPv6a() + { + $this->setExpectedException("Exception"); + $i = new Ipaddresses(); + $res = $i->groupIPv6("1.2.3.4"); + } + public function test_groupIPv6b() + { + $i = new Ipaddresses(); + $res = $i->groupIPv6("0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f." . "0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f"); - $this->assertSame ("0123:4567:89ab:cdef:0123:4567:89ab:cdef", $res); - } + $this->assertSame("0123:4567:89ab:cdef:0123:4567:89ab:cdef", $res); + } - public function test_completeAddressWithZero1 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("::"); - $this->assertSame ("0000:0000:0000:0000:0000:0000:0000:0000", $res); - } - public function test_completeAddressWithZero2 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("::1"); - $this->assertSame ("0000:0000:0000:0000:0000:0000:0000:0001", $res); - } - public function test_completeAddressWithZero3 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("1::"); - $this->assertSame ("0001:0000:0000:0000:0000:0000:0000:0000", $res); - } - public function test_completeAddressWithZero4 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("1::1"); - $this->assertSame ("0001:0000:0000:0000:0000:0000:0000:0001", $res); - } - public function test_completeAddressWithZero5 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("1:222::1"); - $this->assertSame ("0001:0222:0000:0000:0000:0000:0000:0001", $res); - } - public function test_completeAddressWithZero6 () - { - $i = new Ipaddresses (); - $res = $i->completeAddressWithZero ("1.2.3.4"); - $this->assertSame ("1.2.3.4", $res); - } + public function test_completeAddressWithZero1() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("::"); + $this->assertSame("0000:0000:0000:0000:0000:0000:0000:0000", $res); + } + public function test_completeAddressWithZero2() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("::1"); + $this->assertSame("0000:0000:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero3() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("1::"); + $this->assertSame("0001:0000:0000:0000:0000:0000:0000:0000", $res); + } + public function test_completeAddressWithZero4() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("1::1"); + $this->assertSame("0001:0000:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero5() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("1:222::1"); + $this->assertSame("0001:0222:0000:0000:0000:0000:0000:0001", $res); + } + public function test_completeAddressWithZero6() + { + $i = new Ipaddresses(); + $res = $i->completeAddressWithZero("1.2.3.4"); + $this->assertSame("1.2.3.4", $res); + } // TODO : cidrToBin // TODO : str_base_convert - public function test_reverseIPAddress1 () - { - $i = new Ipaddresses (); - $res = $i->reverseIPAddress ("1.2.3.4"); - $this->assertSame ("4.3.2.1", $res); - } - public function test_reverseIPAddress2 () - { - $i = new Ipaddresses (); - $res = $i->reverseIPAddress ("::"); - $this->assertSame ("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); - } - public function test_reverseIPAddress3 () - { - $i = new Ipaddresses (); - $res = $i->reverseIPAddress ("::1"); - $this->assertSame ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); - } - public function test_reverseIPAddress4 () - { - $i = new Ipaddresses (); - $res = $i->reverseIPAddress ("2::1"); - $this->assertSame ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); - } - public function test_reverseIPAddress5 () - { - $i = new Ipaddresses (); - $res = $i->reverseIPAddress ("2::abcd:1"); - $this->assertSame ("1.0.0.0.d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); - } + public function test_reverseIPAddress1() + { + $i = new Ipaddresses(); + $res = $i->reverseIPAddress("1.2.3.4"); + $this->assertSame("4.3.2.1", $res); + } + public function test_reverseIPAddress2() + { + $i = new Ipaddresses(); + $res = $i->reverseIPAddress("::"); + $this->assertSame("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); + } + public function test_reverseIPAddress3() + { + $i = new Ipaddresses(); + $res = $i->reverseIPAddress("::1"); + $this->assertSame("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", $res); + } + public function test_reverseIPAddress4() + { + $i = new Ipaddresses(); + $res = $i->reverseIPAddress("2::1"); + $this->assertSame("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); + } + public function test_reverseIPAddress5() + { + $i = new Ipaddresses(); + $res = $i->reverseIPAddress("2::abcd:1"); + $this->assertSame("1.0.0.0.d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0", $res); + } - public function test_netmask2cidr1 () - { - $this->setExpectedException ("Exception"); - $i = new Ipaddresses (); - $res = $i->netmask2cidr (0); - } - public function test_netmask2cidr2 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.255.255.0"); - $this->assertSame (24, $res); - } - public function test_netmask2cidr3 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.255.255.255"); - $this->assertSame (32, $res); - } - public function test_netmask2cidr4 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.255.255.255"); - $this->assertSame (32, $res); - } - public function test_netmask2cidr5 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.0.0.0"); - $this->assertSame (8, $res); - } - public function test_netmask2cidr6 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("127.0.0.0"); - $this->assertSame (false, $res); - } - public function test_netmask2cidr7 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("63.0.0.0"); - $this->assertSame (false, $res); - } - public function test_netmask2cidr8 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("155.0.0.0"); - $this->assertSame (false, $res); - } - public function test_netmask2cidr9 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("0.0.0.255"); - $this->assertSame (false, $res); - } + public function test_netmask2cidr1() + { + $this->setExpectedException("Exception"); + $i = new Ipaddresses(); + $res = $i->netmask2cidr(0); + } + public function test_netmask2cidr2() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.255.255.0"); + $this->assertSame(24, $res); + } + public function test_netmask2cidr3() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.255.255.255"); + $this->assertSame(32, $res); + } + public function test_netmask2cidr4() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.255.255.255"); + $this->assertSame(32, $res); + } + public function test_netmask2cidr5() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.0.0.0"); + $this->assertSame(8, $res); + } + public function test_netmask2cidr6() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("127.0.0.0"); + $this->assertSame(false, $res); + } + public function test_netmask2cidr7() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("63.0.0.0"); + $this->assertSame(false, $res); + } + public function test_netmask2cidr8() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("155.0.0.0"); + $this->assertSame(false, $res); + } + public function test_netmask2cidr9() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("0.0.0.255"); + $this->assertSame(false, $res); + } - public function test_netmask2cidrWildcard_1 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.255.255.0", false); - $this->assertSame (false, $res); - } + public function test_netmask2cidrWildcard_1() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.255.255.0", false); + $this->assertSame(false, $res); + } - public function test_netmask2cidrWildcard_2 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("0.0.0.0", false); - $this->assertSame (32, $res); - } - public function test_netmask2cidrWildcard_3 () - { - $i = new Ipaddresses (); - $res = $i->netmask2cidr ("255.255.255.255", false); - $this->assertSame (0, $res); - } + public function test_netmask2cidrWildcard_2() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("0.0.0.0", false); + $this->assertSame(32, $res); + } + public function test_netmask2cidrWildcard_3() + { + $i = new Ipaddresses(); + $res = $i->netmask2cidr("255.255.255.255", false); + $this->assertSame(0, $res); + } - public function test_cidr2netmask_1 () - { - $i = new Ipaddresses (); - $res = $i->cidr2netmask (0, true); - $this->assertSame ("0.0.0.0", $res); - } + public function test_cidr2netmask_1() + { + $i = new Ipaddresses(); + $res = $i->cidr2netmask(0, true); + $this->assertSame("0.0.0.0", $res); + } - public function test_cidr2netmask_2 () - { - $i = new Ipaddresses (); - $res = $i->cidr2netmask (24, true); - $this->assertSame ("255.255.255.0", $res); - } + public function test_cidr2netmask_2() + { + $i = new Ipaddresses(); + $res = $i->cidr2netmask(24, true); + $this->assertSame("255.255.255.0", $res); + } - public function test_cidr2netmask_3 () - { - $i = new Ipaddresses (); - $res = $i->cidr2netmask (25, true); - $this->assertSame ("255.255.255.128", $res); - } + public function test_cidr2netmask_3() + { + $i = new Ipaddresses(); + $res = $i->cidr2netmask(25, true); + $this->assertSame("255.255.255.128", $res); + } - public function test_cidr2netmask_4 () - { - $i = new Ipaddresses (); - $res = $i->cidr2netmask (32, true); - $this->assertSame ("255.255.255.255", $res); - } - public function test_cidr2netmask_5 () - { - $i = new Ipaddresses (); - $res = $i->cidr2netmask (1, true); - $this->assertSame ("128.0.0.0", $res); - } + public function test_cidr2netmask_4() + { + $i = new Ipaddresses(); + $res = $i->cidr2netmask(32, true); + $this->assertSame("255.255.255.255", $res); + } + public function test_cidr2netmask_5() + { + $i = new Ipaddresses(); + $res = $i->cidr2netmask(1, true); + $this->assertSame("128.0.0.0", $res); + } - public function test_ipInNetwork1 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("127.0.0.1", "127.1.0.0", 8); - $this->assertSame (true, $res); - } - public function test_ipInNetwork2 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("192.168.1.1", "127.1.0.0", 8); - $this->assertSame (false, $res); - } - public function test_ipInNetwork3 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("2001:660:530d:201::1", "2001:660:530d:201::", 64); - $this->assertSame (true, $res); - } - public function test_ipInNetwork4 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("2001:660:530d:203::1", "2001:660:530d:201::", 64); - $this->assertSame (false, $res); - } - public function test_ipInNetwork5 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("2001:660:530d:203::1", "2001::", 0); - $this->assertSame (true, $res); - } - public function test_ipInNetwork6 () - { - $i = new Ipaddresses (); - $res = $i->ipInNetwork ("192.168.1.1", "127.0.0.0", 0); - $this->assertSame (true, $res); - } + public function test_ipInNetwork1() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("127.0.0.1", "127.1.0.0", 8); + $this->assertSame(true, $res); + } + public function test_ipInNetwork2() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("192.168.1.1", "127.1.0.0", 8); + $this->assertSame(false, $res); + } + public function test_ipInNetwork3() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("2001:660:530d:201::1", "2001:660:530d:201::", 64); + $this->assertSame(true, $res); + } + public function test_ipInNetwork4() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("2001:660:530d:203::1", "2001:660:530d:201::", 64); + $this->assertSame(false, $res); + } + public function test_ipInNetwork5() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("2001:660:530d:203::1", "2001::", 0); + $this->assertSame(true, $res); + } + public function test_ipInNetwork6() + { + $i = new Ipaddresses(); + $res = $i->ipInNetwork("192.168.1.1", "127.0.0.0", 0); + $this->assertSame(true, $res); + } - public function test_networkFirstIP1 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("192.168.1.21", 24); - $this->assertSame ($res, "192.168.1.0"); - } - public function test_networkFirstIP2 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("192.168.1.21", 0); - $this->assertSame ($res, "0.0.0.0"); - } - public function test_networkFirstIP3 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("192.168.1.21", 32); - $this->assertSame ($res, "192.168.1.21"); - } - public function test_networkFirstIP4 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("192.168.1.21", 31); - $this->assertSame ($res, "192.168.1.20"); - } - public function test_networkFirstIP5 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("2001:660:530d:201::125", 64); - $this->assertSame ($res, "2001:660:530d:201::"); - } - public function test_networkFirstIP6 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("2001:660:530d:201::125", 0); - $this->assertSame ($res, "::"); - } - public function test_networkFirstIP7 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("2001:660:530d:201::125", 128); - $this->assertSame ($res, "2001:660:530d:201::125"); - } - public function test_networkFirstIP8 () - { - $i = new Ipaddresses (); - $res = $i->networkFirstIP ("2001:660:530d:201::125", 127); - $this->assertSame ($res, "2001:660:530d:201::124"); - } - public function test_networkLastIP1 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("192.168.1.21", 24); - $this->assertSame ($res, "192.168.1.255"); - } - public function test_networkLastIP2 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("192.168.1.21", 0); - $this->assertSame ($res, "255.255.255.255"); - } - public function test_networkLastIP3 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("192.168.1.21", 32); - $this->assertSame ($res, "192.168.1.21"); - } - public function test_networkLastIP4 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("192.168.1.21", 31); - $this->assertSame ($res, "192.168.1.21"); - } - public function test_networkLastIP5 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("2001:660:530d:201::125", 64); - $this->assertSame ($res, "2001:660:530d:201:ffff:ffff:ffff:ffff"); - } - public function test_networkLastIP6 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("2001:660:530d:201::125", 0); - $this->assertSame ($res, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - } - public function test_networkLastIP7 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("2001:660:530d:201::125", 128); - $this->assertSame ($res, "2001:660:530d:201::125"); - } - public function test_networkLastIP8 () - { - $i = new Ipaddresses (); - $res = $i->networkLastIP ("2001:660:530d:201::125", 127); - $this->assertSame ($res, "2001:660:530d:201::125"); - } + public function test_networkFirstIP1() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("192.168.1.21", 24); + $this->assertSame($res, "192.168.1.0"); + } + public function test_networkFirstIP2() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("192.168.1.21", 0); + $this->assertSame($res, "0.0.0.0"); + } + public function test_networkFirstIP3() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("192.168.1.21", 32); + $this->assertSame($res, "192.168.1.21"); + } + public function test_networkFirstIP4() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("192.168.1.21", 31); + $this->assertSame($res, "192.168.1.20"); + } + public function test_networkFirstIP5() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("2001:660:530d:201::125", 64); + $this->assertSame($res, "2001:660:530d:201::"); + } + public function test_networkFirstIP6() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("2001:660:530d:201::125", 0); + $this->assertSame($res, "::"); + } + public function test_networkFirstIP7() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("2001:660:530d:201::125", 128); + $this->assertSame($res, "2001:660:530d:201::125"); + } + public function test_networkFirstIP8() + { + $i = new Ipaddresses(); + $res = $i->networkFirstIP("2001:660:530d:201::125", 127); + $this->assertSame($res, "2001:660:530d:201::124"); + } + public function test_networkLastIP1() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("192.168.1.21", 24); + $this->assertSame($res, "192.168.1.255"); + } + public function test_networkLastIP2() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("192.168.1.21", 0); + $this->assertSame($res, "255.255.255.255"); + } + public function test_networkLastIP3() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("192.168.1.21", 32); + $this->assertSame($res, "192.168.1.21"); + } + public function test_networkLastIP4() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("192.168.1.21", 31); + $this->assertSame($res, "192.168.1.21"); + } + public function test_networkLastIP5() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("2001:660:530d:201::125", 64); + $this->assertSame($res, "2001:660:530d:201:ffff:ffff:ffff:ffff"); + } + public function test_networkLastIP6() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("2001:660:530d:201::125", 0); + $this->assertSame($res, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + } + public function test_networkLastIP7() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("2001:660:530d:201::125", 128); + $this->assertSame($res, "2001:660:530d:201::125"); + } + public function test_networkLastIP8() + { + $i = new Ipaddresses(); + $res = $i->networkLastIP("2001:660:530d:201::125", 127); + $this->assertSame($res, "2001:660:530d:201::125"); + } } diff --git a/Tests/JwtTest.php b/Tests/JwtTest.php index 4d177d3..f8f08b7 100644 --- a/Tests/JwtTest.php +++ b/Tests/JwtTest.php @@ -1,4 +1,5 @@ @@ -12,170 +13,206 @@ use Domframework\Jwt; /** Test the Jwt.php file */ class JwtTest extends \PHPUnit_Framework_TestCase { - public function test_createKey_1 () - { - $jwt = new Jwt (); - $res = $jwt->createKey (); - $this->assertSame (40, strlen ($res)); - } + public function test_createKey_1() + { + $jwt = new Jwt(); + $res = $jwt->createKey(); + $this->assertSame(40, strlen($res)); + } - public function test_sign_1 () - { - $jwt = new Jwt (); - $res = $this->invokeMethod ($jwt, "sign", "TEXT TO SIGN", "KEY TO USE", - "HS384"); - $this->assertSame ( - "cQB+yNVvIER+Nw53MZfU/PGPAJlkKUnjMikmXAwVB9tcaINQH5a88LCDi0PmI5mZ", - base64_encode ($res)); - } + public function test_sign_1() + { + $jwt = new Jwt(); + $res = $this->invokeMethod( + $jwt, + "sign", + "TEXT TO SIGN", + "KEY TO USE", + "HS384" + ); + $this->assertSame( + "cQB+yNVvIER+Nw53MZfU/PGPAJlkKUnjMikmXAwVB9tcaINQH5a88LCDi0PmI5mZ", + base64_encode($res) + ); + } - public function test_sign_2 () - { - $jwt = new Jwt (); - $res = $this->invokeMethod ($jwt, "sign", "text to sign", "KEY TO USE", - "HS384"); - $this->assertSame ( - "FLSkslsUGIpkP3xsJx5ephnCtH7K4jZSNxRxxCn3m7fsPK/MMfEIVr+h3heap80x", - base64_encode ($res)); - } + public function test_sign_2() + { + $jwt = new Jwt(); + $res = $this->invokeMethod( + $jwt, + "sign", + "text to sign", + "KEY TO USE", + "HS384" + ); + $this->assertSame( + "FLSkslsUGIpkP3xsJx5ephnCtH7K4jZSNxRxxCn3m7fsPK/MMfEIVr+h3heap80x", + base64_encode($res) + ); + } - public function test_sign_3 () - { - $jwt = new Jwt (); - $res = $this->invokeMethod ($jwt, "sign", "text to sign", "key to use", - "HS384"); - $this->assertSame ( - "lBLlXb5Xo3z9zoEuO0obZdhqGNUKr8DaEsL991TpSPWIdB2067ckR+AJ1FW6in2B", - base64_encode ($res)); - } + public function test_sign_3() + { + $jwt = new Jwt(); + $res = $this->invokeMethod( + $jwt, + "sign", + "text to sign", + "key to use", + "HS384" + ); + $this->assertSame( + "lBLlXb5Xo3z9zoEuO0obZdhqGNUKr8DaEsL991TpSPWIdB2067ckR+AJ1FW6in2B", + base64_encode($res) + ); + } - public function test_encode_1 () - { - $jwt = new Jwt (); - $res = $jwt->encode (array ("payload" => "value"), "key to use", "HS384"); - $this->assertSame ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", $res); - } + public function test_encode_1() + { + $jwt = new Jwt(); + $res = $jwt->encode(array ("payload" => "value"), "key to use", "HS384"); + $this->assertSame( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + $res + ); + } - public function test_decode_1 () - { - $jwt = new Jwt (); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", - "key to use"); - $this->assertSame ((object)array ("payload" => "value"), $res); - } + public function test_decode_1() + { + $jwt = new Jwt(); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + "key to use" + ); + $this->assertSame((object)array ("payload" => "value"), $res); + } - public function test_decode_2 () - { - $GLOBALS["hash_equals"] = false; - $jwt = new Jwt (); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", - "key to use"); - $this->assertSame ((object)array ("payload" => "value"), $res); - } + public function test_decode_2() + { + $GLOBALS["hash_equals"] = false; + $jwt = new Jwt(); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + "key to use" + ); + $this->assertSame((object)array ("payload" => "value"), $res); + } - public function test_decode_3 () - { - $jwt = new Jwt (); - $this->expectException ("Exception", "JWT with Empty algorithm"); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUXXXXXJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", - "key to use"); - } + public function test_decode_3() + { + $jwt = new Jwt(); + $this->expectException("Exception", "JWT with Empty algorithm"); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUXXXXXJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + "key to use" + ); + } - public function test_decode_4 () - { - $jwt = new Jwt (); - $this->expectException ("Exception", "JWT Payload not readable"); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoiXXXXXXXXfQ.". - "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", - "key to use"); - } + public function test_decode_4() + { + $jwt = new Jwt(); + $this->expectException("Exception", "JWT Payload not readable"); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoiXXXXXXXXfQ." . + "0ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + "key to use" + ); + } - public function test_decode_5 () - { - $jwt = new Jwt (); - $this->expectException ("Exception", - "JWT Signature verification failed"); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "1ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", - "key to use"); - } + public function test_decode_5() + { + $jwt = new Jwt(); + $this->expectException( + "Exception", + "JWT Signature verification failed" + ); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "1ByHaODQQjYEvmgU2u5LI034RRMc7CKJQ752ys19Fqj7QiTJO7-trerYKCxCyuge", + "key to use" + ); + } - public function test_decode_6 () - { - $jwt = new Jwt (); - $this->expectException ("Exception", - "JWT Signature not readable"); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ.". - "0", - "key to use"); - } + public function test_decode_6() + { + $jwt = new Jwt(); + $this->expectException( + "Exception", + "JWT Signature not readable" + ); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ." . + "0", + "key to use" + ); + } - public function test_decode_7 () - { - $jwt = new Jwt (); - $this->expectException ("Exception", - "Malformed JWT Token"); - $res = $jwt->decode ( - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.". - "eyJwYXlsb2FkIjoidmFsdWUifQ", - "key to use"); - } + public function test_decode_7() + { + $jwt = new Jwt(); + $this->expectException( + "Exception", + "Malformed JWT Token" + ); + $res = $jwt->decode( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9." . + "eyJwYXlsb2FkIjoidmFsdWUifQ", + "key to use" + ); + } /////////////////////////////// // ENCRYPT THE PAYLOAD // /////////////////////////////// /** Check the length of the otken with cipher */ - public function testEncrypt1 () - { - $jwt = new Jwt (); - $key = $jwt->createKey (); - $res = $jwt->encode ( - ["email" => "toto@example.com", "password" => "ToTo"], - $key, "HS256", "123456789012345678901234"); - $this->assertSame (strlen ($res), 156); - } + public function testEncrypt1() + { + $jwt = new Jwt(); + $key = $jwt->createKey(); + $res = $jwt->encode( + ["email" => "toto@example.com", "password" => "ToTo"], + $key, + "HS256", + "123456789012345678901234" + ); + $this->assertSame(strlen($res), 156); + } /** Check if the encrypt/decrypt process return the same result */ - public function testEncrypyt2 () - { - $jwt = new Jwt (); - $key = $jwt->createKey (); - $payload = (object)["email" => "toto@example.com", "password" => "ToTo"]; - $token = $jwt->encode ($payload, $key, "HS256", "123456789012345678901234"); - $res = $jwt->decode ($token, $key, null, "123456789012345678901234"); - $this->assertSame ($res, $payload); - } + public function testEncrypyt2() + { + $jwt = new Jwt(); + $key = $jwt->createKey(); + $payload = (object)["email" => "toto@example.com", "password" => "ToTo"]; + $token = $jwt->encode($payload, $key, "HS256", "123456789012345678901234"); + $res = $jwt->decode($token, $key, null, "123456789012345678901234"); + $this->assertSame($res, $payload); + } /** Check if the encrypted part is well unreadable */ - public function testEncrypt3 () - { - $jwt = new Jwt (); - $key = $jwt->createKey (); - $payload = (object)["email" => "toto@example.com", "password" => "ToTo"]; - $token = $jwt->encode ($payload, $key, "HS256", "123456789012345678901234"); - list ($header, $payload, $signature) = explode (".", $token); - $res = strpos (base64_decode ($payload), "email"); - $this->assertSame ($res, false); - } + public function testEncrypt3() + { + $jwt = new Jwt(); + $key = $jwt->createKey(); + $payload = (object)["email" => "toto@example.com", "password" => "ToTo"]; + $token = $jwt->encode($payload, $key, "HS256", "123456789012345678901234"); + list ($header, $payload, $signature) = explode(".", $token); + $res = strpos(base64_decode($payload), "email"); + $this->assertSame($res, false); + } } diff --git a/Tests/MacaddressesTest.php b/Tests/MacaddressesTest.php index e825db3..e561311 100644 --- a/Tests/MacaddressesTest.php +++ b/Tests/MacaddressesTest.php @@ -1,4 +1,5 @@ @@ -12,100 +13,100 @@ use Domframework\Macaddresses; /** Test the Macaddresses.php file */ class MacaddressesTest extends \PHPUnit_Framework_TestCase { - public function test_isMACAddress_1 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress (""); - $this->assertSame (false, $res); - } + public function test_isMACAddress_1() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress(""); + $this->assertSame(false, $res); + } - public function test_isMACAddress_2 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("INVALID"); - $this->assertSame (false, $res); - } + public function test_isMACAddress_2() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("INVALID"); + $this->assertSame(false, $res); + } - public function test_isMACAddress_3 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("de:ad:be:af:aa:bb"); - $this->assertSame (true, $res); - } + public function test_isMACAddress_3() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("de:ad:be:af:aa:bb"); + $this->assertSame(true, $res); + } - public function test_isMACAddress_4 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("de-ad-be-af-aa-bb"); - $this->assertSame (true, $res); - } + public function test_isMACAddress_4() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("de-ad-be-af-aa-bb"); + $this->assertSame(true, $res); + } - public function test_isMACAddress_5 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("0005.313B.9080"); - $this->assertSame (true, $res); - } + public function test_isMACAddress_5() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("0005.313B.9080"); + $this->assertSame(true, $res); + } - public function test_isMACAddress_6 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("0005313B9080"); - $this->assertSame (true, $res); - } + public function test_isMACAddress_6() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("0005313B9080"); + $this->assertSame(true, $res); + } - public function test_isMACAddress_7 () - { - $macaddresses = new Macaddresses (); - $res = $macaddresses->isMACAddress ("a0005313B9080a"); - $this->assertSame (false, $res); - } + public function test_isMACAddress_7() + { + $macaddresses = new Macaddresses(); + $res = $macaddresses->isMACAddress("a0005313B9080a"); + $this->assertSame(false, $res); + } - public function test_addSeparator_1 () - { - $res = Macaddresses::addSeparator ("0005313B9080"); - $this->assertSame ("00:05:31:3B:90:80", $res); - } + public function test_addSeparator_1() + { + $res = Macaddresses::addSeparator("0005313B9080"); + $this->assertSame("00:05:31:3B:90:80", $res); + } - public function test_addSeparator_2 () - { - $res = Macaddresses::addSeparator ("0005313B9080", "-"); - $this->assertSame ("00-05-31-3B-90-80", $res); - } + public function test_addSeparator_2() + { + $res = Macaddresses::addSeparator("0005313B9080", "-"); + $this->assertSame("00-05-31-3B-90-80", $res); + } - public function test_addSeparator_3 () - { - $res = Macaddresses::addSeparator ("0005313B9080", ".", 4); - $this->assertSame ("0005.313B.9080", $res); - } + public function test_addSeparator_3() + { + $res = Macaddresses::addSeparator("0005313B9080", ".", 4); + $this->assertSame("0005.313B.9080", $res); + } - public function test_addSeparator_4 () - { - $this->expectException (); - $res = Macaddresses::addSeparator ("INVALID", ".", 4); - } + public function test_addSeparator_4() + { + $this->expectException(); + $res = Macaddresses::addSeparator("INVALID", ".", 4); + } - public function test_removeSeparator_1 () - { - $res = Macaddresses::removeSeparator("de:ad:be:af:aa:bb"); - $this->assertSame ("deadbeafaabb", $res); - } + public function test_removeSeparator_1() + { + $res = Macaddresses::removeSeparator("de:ad:be:af:aa:bb"); + $this->assertSame("deadbeafaabb", $res); + } - public function test_removeSeparator_2 () - { - $res = Macaddresses::removeSeparator("de-ad-be-af-aa-bb"); - $this->assertSame ("deadbeafaabb", $res); - } + public function test_removeSeparator_2() + { + $res = Macaddresses::removeSeparator("de-ad-be-af-aa-bb"); + $this->assertSame("deadbeafaabb", $res); + } - public function test_removeSeparator_3 () - { - $res = Macaddresses::removeSeparator("dead.beaf.aabb"); - $this->assertSame ("deadbeafaabb", $res); - } + public function test_removeSeparator_3() + { + $res = Macaddresses::removeSeparator("dead.beaf.aabb"); + $this->assertSame("deadbeafaabb", $res); + } - public function test_removeSeparator_4 () - { - $res = Macaddresses::removeSeparator("deadbeafaabb"); - $this->assertSame ("deadbeafaabb", $res); - } + public function test_removeSeparator_4() + { + $res = Macaddresses::removeSeparator("deadbeafaabb"); + $this->assertSame("deadbeafaabb", $res); + } } diff --git a/Tests/MailTest.php b/Tests/MailTest.php index 026149a..423e955 100644 --- a/Tests/MailTest.php +++ b/Tests/MailTest.php @@ -1,4 +1,5 @@ @@ -12,141 +13,141 @@ use Domframework\Mail; /** Test the Mail.php file */ class MailTest extends \PHPUnit_Framework_TestCase { - public function test_setBodyText1 () - { - $mail = new Mail (); - $mail->setBodyText ("TEST"); - $res = $mail->getMail (); - $this->assertRegExp ("#TEST\n$#", $res); - } + public function testSetBodyText1() + { + $mail = new Mail(); + $mail->setBodyText("TEST"); + $res = $mail->getMail(); + $this->assertRegExp("#TEST\n$#", $res); + } - public function test_setBodyHTML1 () - { - $mail = new Mail (); - $mail->setBodyHTML ("TEST"); - $res = $mail->getMail (); - $this->assertRegExp ("#^\r\nTEST\n$#m", $res); - } + public function testSetBodyHTML1() + { + $mail = new Mail(); + $mail->setBodyHTML("TEST"); + $res = $mail->getMail(); + $this->assertRegExp("#^\r\nTEST\n$#m", $res); + } - public function test_setGetBodyText1 () - { - $mail = new Mail (); - $mail->setBodyText ("TEST"); - $res = $mail->getBodyText (); - $this->assertSame ("TEST\n", $res); - } + public function testSetGetBodyText1() + { + $mail = new Mail(); + $mail->setBodyText("TEST"); + $res = $mail->getBodyText(); + $this->assertSame("TEST\n", $res); + } - public function test_setGetBodyHtml1 () - { - $mail = new Mail (); - $mail->setBodyHtml ("TEST"); - $res = $mail->getBodyHtml (); - $this->assertSame ("TEST\n", $res); - } + public function testSetGetBodyHtml1() + { + $mail = new Mail(); + $mail->setBodyHtml("TEST"); + $res = $mail->getBodyHtml(); + $this->assertSame("TEST\n", $res); + } - public function test_setFrom1 () - { - $mail = new Mail (); - $mail->setFrom ("test@example.com", "Test Exa1mple Com"); - $res = $mail->getFrom (); - $this->assertSame ("Test Exa1mple Com \r\n", $res); - } + public function testSetFrom1() + { + $mail = new Mail(); + $mail->setFrom("test@example.com", "Test Exa1mple Com"); + $res = $mail->getFrom(); + $this->assertSame("Test Exa1mple Com \r\n", $res); + } - public function test_addTo1 () - { - $mail = new Mail (); - $mail->addTo ("test@example.com", "Test Exa1mple Com"); - $res = $mail->getTo (); - $this->assertSame ("Test Exa1mple Com \r\n", $res); - } + public function testAddTo1() + { + $mail = new Mail(); + $mail->addTo("test@example.com", "Test Exa1mple Com"); + $res = $mail->getTo(); + $this->assertSame("Test Exa1mple Com \r\n", $res); + } - public function test_addTo2 () - { - $mail = new Mail (); - $mail->addTo ("test@example.com", "Test Exa1mple Com"); - $res = $mail->getMail (); - $this->assertRegexp ("#^To: Test Exa1mple Com \r$#m", $res); - } + public function testAddTo2() + { + $mail = new Mail(); + $mail->addTo("test@example.com", "Test Exa1mple Com"); + $res = $mail->getMail(); + $this->assertRegexp("#^To: Test Exa1mple Com \r$#m", $res); + } - public function test_setDateTimestamp1 () - { - $mail = new Mail (); - $time = time (); - $mail->setDateTimestamp ($time); - $res = $mail->getDateTimestamp (); - $this->assertSame ($res, $time); - } + public function testSetDateTimestamp1() + { + $mail = new Mail(); + $time = time(); + $mail->setDateTimestamp($time); + $res = $mail->getDateTimestamp(); + $this->assertSame($res, $time); + } - public function test_setDateTimestamp2 () - { - $mail = new Mail (); - $time = time (); - $mail->setDateTimestamp ($time); - $res = $mail->getMail (); - $this->assertRegexp ("#^Date: ".preg_quote (date ("r", $time))."\r$#m", $res); - } + public function testSetDateTimestamp2() + { + $mail = new Mail(); + $time = time(); + $mail->setDateTimestamp($time); + $res = $mail->getMail(); + $this->assertRegexp("#^Date: " . preg_quote(date("r", $time)) . "\r$#m", $res); + } - public function test_convertPeopleToArray1 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray ("toto toto "); - $this->assertSame ($res, array (array ("name"=>"toto toto", - "mail"=>"toto@toto.com"))); - } + public function testConvertPeopleToArray1() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray("toto toto "); + $this->assertSame($res, array (array ("name" => "toto toto", + "mail" => "toto@toto.com"))); + } - public function test_convertPeopleToArray2 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray (""); - $this->assertSame ($res, array (array ("name"=>"", - "mail"=>"toto@toto.com"))); - } + public function testConvertPeopleToArray2() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray(""); + $this->assertSame($res, array (array ("name" => "", + "mail" => "toto@toto.com"))); + } - public function test_convertPeopleToArray3 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray ("toto@toto.com,titi@titi.com"); - $this->assertSame ($res, array (array ("name" => "", + public function testConvertPeopleToArray3() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray("toto@toto.com,titi@titi.com"); + $this->assertSame($res, array (array ("name" => "", "mail" => "toto@toto.com"), array ("name" => "", "mail" => "titi@titi.com"))); - } + } - public function test_convertPeopleToArray4 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray ("toto@toto.com"); - $this->assertSame ($res, array (array ("name"=>"", - "mail"=>"toto@toto.com"))); - } + public function testConvertPeopleToArray4() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray("toto@toto.com"); + $this->assertSame($res, array (array ("name" => "", + "mail" => "toto@toto.com"))); + } - public function test_convertPeopleToArray5 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray (" , "); - $this->assertSame ($res, array (array ("name" => "", + public function testConvertPeopleToArray5() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray(" , "); + $this->assertSame($res, array (array ("name" => "", "mail" => "toto@toto.com"), array ("name" => "", "mail" => "titi@titi.com"))); - } + } - public function test_convertPeopleToArray6 () - { - $mail = new Mail (); - $res = $mail->convertPeopleToArray ("ToTo , "); - $this->assertSame ($res, array (array ("name" => "ToTo", + public function testConvertPeopleToArray6() + { + $mail = new Mail(); + $res = $mail->convertPeopleToArray("ToTo , "); + $this->assertSame($res, array (array ("name" => "ToTo", "mail" => "toto@toto.com"), array ("name" => "", "mail" => "titi@titi.com"))); - } + } /** Read all the headers and return them as JSON object */ - public function testHeadersToJSON1 () - { - $mail = new Mail (); - $mail->readMail ( // {{{ -"Return-Path: + public function testHeadersToJSON1() + { + $mail = new Mail(); + $mail->readMail( // {{{ + "Return-Path: Delivered-To: dominique@fournier38.fr Received: from mail-postfix-mx.fournier38.fr ([192.168.1.103]) by mail-dovecot.fournier38.fr with LMTP @@ -187,46 +188,47 @@ https://openclassrooms.com/fr/courses/4470541-analysez-vos-donnees-textuelles/48 http://www.nltk.org/nltk_data/ http://www.cs.cmu.edu/~ralf/langid.html -"); -// }}} - $this->assertSame ($mail->getHeaders (), array ( - ["Return-Path" => "\n"], - ["Delivered-To" => "dominique@fournier38.fr\n"], - ["Received" => "from mail-postfix-mx.fournier38.fr ([192.168.1.103]) +" + ); + // }}} + $this->assertSame($mail->getHeaders(), array ( + ["Return-Path" => "\n"], + ["Delivered-To" => "dominique@fournier38.fr\n"], + ["Received" => "from mail-postfix-mx.fournier38.fr ([192.168.1.103]) by mail-dovecot.fournier38.fr with LMTP id z706BqQt7V15IAAAA28uxw (envelope-from ) for ; Sun, 08 Dec 2019 18:06:44 +0100\n"], - ["Received" => "from mailgw-out1.grenoble.cnrs.fr (mailgw-out1.grenoble.cnrs.fr [147.173.1.68]) + ["Received" => "from mailgw-out1.grenoble.cnrs.fr (mailgw-out1.grenoble.cnrs.fr [147.173.1.68]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail-postfix-mx.fournier38.fr (Postfix) with ESMTPS id 8A2DF820733 for ; Sun, 8 Dec 2019 18:06:43 +0100 (CET)\n"], - ["DMARC-Filter" => "OpenDMARC Filter v1.3.2 mail-postfix-mx.fournier38.fr 8A2DF820733\n"], - ["Delivered-To" => "dominique.fournier@grenoble.cnrs.fr\n"], - ["Received" => "from [192.168.1.154] (82-64-55-197.subs.proxad.net [82.64.55.197]) + ["DMARC-Filter" => "OpenDMARC Filter v1.3.2 mail-postfix-mx.fournier38.fr 8A2DF820733\n"], + ["Delivered-To" => "dominique.fournier@grenoble.cnrs.fr\n"], + ["Received" => "from [192.168.1.154] (82-64-55-197.subs.proxad.net [82.64.55.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mailgw-out1.grenoble.cnrs.fr (Postfix) with ESMTPSA id 458EDBFCE4 for ; Sun, 8 Dec 2019 18:08:06 +0100 (CET)\n"], - ["From" => "Dominique Fournier \n"], - ["Subject" => "Analyse de texte\n"], - ["To" => "Dominique Fournier / Fournier38 \n"], - ["Message-ID" => "<81d7982f-7fee-96b4-078f-a6365234356f@grenoble.cnrs.fr>\n"], - ["Date" => "Sun, 8 Dec 2019 18:08:06 +0100\n"], - ["User-Agent" => "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 + ["From" => "Dominique Fournier \n"], + ["Subject" => "Analyse de texte\n"], + ["To" => "Dominique Fournier / Fournier38 \n"], + ["Message-ID" => "<81d7982f-7fee-96b4-078f-a6365234356f@grenoble.cnrs.fr>\n"], + ["Date" => "Sun, 8 Dec 2019 18:08:06 +0100\n"], + ["User-Agent" => "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2\n"], - ["MIME-Version" => "1.0\n"], - ["Content-Type" => "text/plain; charset=utf-8; format=flowed\n"], - ["Content-Language" => "en-US\n"], - ["Content-Transfer-Encoding" => "7bit\n"], - ["Authentication-Results" => "mail-postfix-mx.fournier38.fr; + ["MIME-Version" => "1.0\n"], + ["Content-Type" => "text/plain; charset=utf-8; format=flowed\n"], + ["Content-Language" => "en-US\n"], + ["Content-Transfer-Encoding" => "7bit\n"], + ["Authentication-Results" => "mail-postfix-mx.fournier38.fr; dkim=none; dmarc=none; spf=pass (mail-postfix-mx.fournier38.fr: domain of dominique.fournier@grenoble.cnrs.fr designates 147.173.1.68 as permitted sender) smtp.mailfrom=dominique.fournier@grenoble.cnrs.fr\n"], - ["X-Spamd-Bar" => "--------------------------------------------------------------------------------------------------\n"], + ["X-Spamd-Bar" => "--------------------------------------------------------------------------------------------------\n"], - )); - } + )); + } } diff --git a/Tests/MarkdownTest.php b/Tests/MarkdownTest.php index 98a382b..249224a 100644 --- a/Tests/MarkdownTest.php +++ b/Tests/MarkdownTest.php @@ -1,4 +1,5 @@ @@ -13,207 +14,207 @@ use Domframework\Markdown; class MarkdownTest extends \PHPUnit_Framework_TestCase { // TitleSeText - public function testTitleSeText1 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("test\n====\n"), TRUE); - } + public function testTitleSeText1() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("test\n====\n"), true); + } - public function testTitleSeText2 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("test\n----\n"), TRUE); - } + public function testTitleSeText2() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("test\n----\n"), true); + } // Titles Sharp - public function testTitleSharp1 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("# test #")); - } + public function testTitleSharp1() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("# test #")); + } - public function testTitleSharp2 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("## test ##")); - } + public function testTitleSharp2() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("## test ##")); + } - public function testTitleSharp3 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("### test ###")); - } + public function testTitleSharp3() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("### test ###")); + } - public function testTitleSharp4 () - { - $this->expectOutputString("

test

"); - $md = new Markdown (); - printf ($md->html ("#### test ####")); - } + public function testTitleSharp4() + { + $this->expectOutputString("

test

"); + $md = new Markdown(); + printf($md->html("#### test ####")); + } - public function testTitleSharp5 () - { - $this->expectOutputString("
test
"); - $md = new Markdown (); - printf ($md->html ("##### test #####")); - } + public function testTitleSharp5() + { + $this->expectOutputString("
test
"); + $md = new Markdown(); + printf($md->html("##### test #####")); + } - public function testTitleSharp6 () - { - $this->expectOutputString("
test
"); - $md = new Markdown (); - printf ($md->html ("###### test #######")); - } + public function testTitleSharp6() + { + $this->expectOutputString("
test
"); + $md = new Markdown(); + printf($md->html("###### test #######")); + } // Separator - public function testSeparator1 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("---\n"), TRUE); - } + public function testSeparator1() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("---\n"), true); + } - public function testSeparator2 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("___\n"), TRUE); - } + public function testSeparator2() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("___\n"), true); + } - public function testSeparator3 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("***\n"), TRUE); - } + public function testSeparator3() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("***\n"), true); + } - public function testSeparator4 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("- - -\n"), TRUE); - } + public function testSeparator4() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("- - -\n"), true); + } - public function testSeparator5 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("_ _ _\n"), TRUE); - } + public function testSeparator5() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("_ _ _\n"), true); + } - public function testSeparator6 () - { - $this->expectOutputString("
"); - $md = new Markdown (); - printf ($md->html ("* * *\n"), TRUE); - } + public function testSeparator6() + { + $this->expectOutputString("
"); + $md = new Markdown(); + printf($md->html("* * *\n"), true); + } // Simple Text - public function testSimpleText () - { - $this->expectOutputString("

text

"); - $md = new Markdown (); - printf ($md->html ("text"), TRUE); - } + public function testSimpleText() + { + $this->expectOutputString("

text

"); + $md = new Markdown(); + printf($md->html("text"), true); + } // Emphasis - public function testEmphasisStrong1 () - { - $this->expectOutputString("

text

"); - $md = new Markdown (); - printf ($md->html ("__text__")); - } + public function testEmphasisStrong1() + { + $this->expectOutputString("

text

"); + $md = new Markdown(); + printf($md->html("__text__")); + } - public function testEmphasisStrong2 () - { - $this->expectOutputString("

text

"); - $md = new Markdown (); - printf ($md->html ("**text**")); - } + public function testEmphasisStrong2() + { + $this->expectOutputString("

text

"); + $md = new Markdown(); + printf($md->html("**text**")); + } - public function testEmphasisEM1 () - { - $this->expectOutputString("

text

"); - $md = new Markdown (); - printf ($md->html ("_text_")); - } + public function testEmphasisEM1() + { + $this->expectOutputString("

text

"); + $md = new Markdown(); + printf($md->html("_text_")); + } - public function testEmphasisEM2 () - { - $this->expectOutputString("

file1.php or file2.php

"); - $md = new Markdown (); - printf ($md->html ("_file1.php_ or _file2.php_")); - } + public function testEmphasisEM2() + { + $this->expectOutputString("

file1.php or file2.php

"); + $md = new Markdown(); + printf($md->html("_file1.php_ or _file2.php_")); + } - public function testEmphasisEM3 () - { - $this->expectOutputString("

text

"); - $md = new Markdown (); - printf ($md->html ("*text*")); - } + public function testEmphasisEM3() + { + $this->expectOutputString("

text

"); + $md = new Markdown(); + printf($md->html("*text*")); + } - public function testEmphasisEM4 () - { - $this->expectOutputString("

text or text2

"); - $md = new Markdown (); - printf ($md->html ("*text* or *text2*")); - } + public function testEmphasisEM4() + { + $this->expectOutputString("

text or text2

"); + $md = new Markdown(); + printf($md->html("*text* or *text2*")); + } // Unnumbered lists - public function testUnnumbered1 () - { - $this->expectOutputString("
    + public function testUnnumbered1() + { + $this->expectOutputString("
    • Case1
    • Case2
    • Case3
    "); - $md = new Markdown (); - printf ($md->html ("* Case1\n* Case2\n* Case3"), TRUE); - } + $md = new Markdown(); + printf($md->html("* Case1\n* Case2\n* Case3"), true); + } - public function testUnnumbered2 () - { - $this->expectOutputString("
      + public function testUnnumbered2() + { + $this->expectOutputString("
      • Case1
      • Case2
      • Case3
      "); - $md = new Markdown (); - printf ($md->html ("- Case1\n- Case2\n- Case3"), TRUE); - } + $md = new Markdown(); + printf($md->html("- Case1\n- Case2\n- Case3"), true); + } - public function testUnnumbered3 () - { - $this->expectOutputString("
        + public function testUnnumbered3() + { + $this->expectOutputString("
        • Case1
        • Case2
        • Case3
        "); - $md = new Markdown (); - printf ($md->html ("+ Case1\n+ Case2\n+ Case3"), TRUE); - } + $md = new Markdown(); + printf($md->html("+ Case1\n+ Case2\n+ Case3"), true); + } - public function testUnnumberredMultiline1 () - { - $this->expectOutputString("
          + public function testUnnumberredMultiline1() + { + $this->expectOutputString("
          • line1 end
          • line2 end
          "); - $md = new Markdown (); - printf ($md->html ("* line1 + $md = new Markdown(); + printf($md->html("* line1 end * line2 end")); - } + } - public function testUnnumberedListMultiple1 () - { - $this->expectOutputString("
            + public function testUnnumberedListMultiple1() + { + $this->expectOutputString("
            • line1
            • line2
                @@ -223,161 +224,165 @@ end"));
              • line3
              "); - $md = new Markdown (); - printf ($md->html ("* line1 + $md = new Markdown(); + printf($md->html("* line1 * line2 * NEW lineA * NEW lineB * line3")); - } + } // Numbered lists - public function testNumbered1 () - { - $this->expectOutputString("
                + public function testNumbered1() + { + $this->expectOutputString("
                1. Case1
                2. Case2
                3. Case3
                "); - $md = new Markdown (); - printf ($md->html ("1. Case1\n2. Case2\n3. Case3"), TRUE); - } + $md = new Markdown(); + printf($md->html("1. Case1\n2. Case2\n3. Case3"), true); + } // Code - public function testCode1 () - { - $this->expectOutputString("
                test
                +    public function testCode1()
                +    {
                +        $this->expectOutputString("
                test
                     indent
                 base
                "); - $md = new Markdown (); - printf ($md->html (" test + $md = new Markdown(); + printf($md->html(" test indent base")); - } + } // Inline code - public function testInlineCode1 () - { - $this->expectOutputString("

                code

                "); - $md = new Markdown (); - printf ($md->html ("`code`")); - } + public function testInlineCode1() + { + $this->expectOutputString("

                code

                "); + $md = new Markdown(); + printf($md->html("`code`")); + } // Links - public function testLinkHTTP1 () - { - $this->expectOutputString( - "

                http://example.com

                "); - $md = new Markdown (); - printf ($md->html ("")); - } + public function testLinkHTTP1() + { + $this->expectOutputString( + "

                http://example.com

                " + ); + $md = new Markdown(); + printf($md->html("")); + } - public function testLinkHTTP2 () - { - $this->expectOutputString( - "

                https://example.com

                "); - $md = new Markdown (); - printf ($md->html ("")); - } + public function testLinkHTTP2() + { + $this->expectOutputString( + "

                https://example.com

                " + ); + $md = new Markdown(); + printf($md->html("")); + } - public function testLinkHTTP3 () - { - $this->expectOutputString( - "

                test@example.com

                "); - $md = new Markdown (); - printf ($md->html ("")); - } + public function testLinkHTTP3() + { + $this->expectOutputString( + "

                test@example.com

                " + ); + $md = new Markdown(); + printf($md->html("")); + } - public function testLinkHTTP4 () - { - $this->expectOutputString( - "

                test_with_underscore@example.com

                "); - $md = new Markdown (); - printf ($md->html ("")); - } + public function testLinkHTTP4() + { + $this->expectOutputString( + "

                test_with_underscore@example.com

                " + ); + $md = new Markdown(); + printf($md->html("")); + } // Chaining - public function testChain1 () - { - $this->expectOutputString("

                t1

                t2

                "); - $md = new Markdown (); - printf ($md->html ("# t1\n## t2")); - } + public function testChain1() + { + $this->expectOutputString("

                t1

                t2

                "); + $md = new Markdown(); + printf($md->html("# t1\n## t2")); + } - public function testChainCode1 () - { - $this->expectOutputString("
                
                +    public function testChainCode1()
                +    {
                +        $this->expectOutputString("
                
                 * OK
                "); - $md = new Markdown (); - printf ($md->html (" \n * OK")); - } + $md = new Markdown(); + printf($md->html(" \n * OK")); + } - public function testChainCode2 () - { - $this->expectOutputString("
                
                +    public function testChainCode2()
                +    {
                +        $this->expectOutputString("
                
                 * * * * * www-data OK
                "); - $md = new Markdown (); - printf ($md->html (" \n * * * * * www-data OK")); - } + $md = new Markdown(); + printf($md->html(" \n * * * * * www-data OK")); + } - public function testChainCode3 () - { - $this->expectOutputString("

                To write

                + public function testChainCode3() + { + $this->expectOutputString("

                To write

                * * * * * www-data OK
                "); - $md = new Markdown (); - printf ($md->html ("To write + $md = new Markdown(); + printf($md->html("To write * * * * * www-data OK")); - } + } - public function testUnnumberredAndText1 () - { - $this->expectOutputString("

                Hi

                + public function testUnnumberredAndText1() + { + $this->expectOutputString("

                Hi

                • line1
                • line2 end
                "); - $md = new Markdown (); - printf ($md->html ("Hi + $md = new Markdown(); + printf($md->html("Hi * line1 * line2 end")); - } + } - public function testCarriageReturn1 () - { - $this->expectOutputString("

                line1 line2

                "); - $md = new Markdown (); - printf ($md->html ("line1\nline2\n")); - } + public function testCarriageReturn1() + { + $this->expectOutputString("

                line1 line2

                "); + $md = new Markdown(); + printf($md->html("line1\nline2\n")); + } - public function testCarriageReturn2 () - { - $this->expectOutputString("

                line1
                line2

                "); - $md = new Markdown (); - printf ($md->html ("line1 \nline2\n")); - } + public function testCarriageReturn2() + { + $this->expectOutputString("

                line1
                line2

                "); + $md = new Markdown(); + printf($md->html("line1 \nline2\n")); + } - public function testCarriageReturn3 () - { - $this->expectOutputString("

                line1 line2 line3.

                "); - $md = new Markdown (); - printf ($md->html ("line1 + public function testCarriageReturn3() + { + $this->expectOutputString("

                line1 line2 line3.

                "); + $md = new Markdown(); + printf($md->html("line1 line2 line3.")); - } + } - public function testHTMLSpecialChars1 () - { - $this->expectOutputString("

                toto&titi

                "); - $md = new Markdown (); - printf ($md->html ("toto&titi")); - } + public function testHTMLSpecialChars1() + { + $this->expectOutputString("

                toto&titi

                "); + $md = new Markdown(); + printf($md->html("toto&titi")); + } - public function testHTMLSpecialChars2 () - { - $this->expectOutputString("

                totoétiti

                "); - $md = new Markdown (); - printf ($md->html ("totoétiti")); - } + public function testHTMLSpecialChars2() + { + $this->expectOutputString("

                totoétiti

                "); + $md = new Markdown(); + printf($md->html("totoétiti")); + } } diff --git a/Tests/OutputdlTest.php b/Tests/OutputdlTest.php index a4b9440..4b240f4 100644 --- a/Tests/OutputdlTest.php +++ b/Tests/OutputdlTest.php @@ -1,4 +1,5 @@ @@ -12,97 +13,102 @@ use Domframework\Outputdl; /** Test the Outputdl.php file */ class OutputdlTest extends \PHPUnit_Framework_TestCase { - public function test_outputdl_init () - { - exec ("rm -f /tmp/testDFWoutputDL*"); - file_put_contents ("/tmp/testDFWoutputDL", - str_repeat ( - "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", - 1000) - ); - symlink ("/etc/passwd", "/tmp/testDFWoutputDL2"); - symlink ("/tmp/testDFWoutputDL", "/tmp/testDFWoutputDL3"); - } + public function test_outputdl_init() + { + exec("rm -f /tmp/testDFWoutputDL*"); + file_put_contents( + "/tmp/testDFWoutputDL", + str_repeat( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", + 1000 + ) + ); + symlink("/etc/passwd", "/tmp/testDFWoutputDL2"); + symlink("/tmp/testDFWoutputDL", "/tmp/testDFWoutputDL3"); + } - public function test_outputdl_1 () - { - // Check the full download content - $outputdl = new Outputdl (); - $this->expectOutputString (str_repeat ( - "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", - 1000)); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_1() + { + // Check the full download content + $outputdl = new Outputdl(); + $this->expectOutputString(str_repeat( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", + 1000 + )); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_Announce_1 () - { - // Check the announce of Resume mode Enabled - $outputdl = new Outputdl (); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - $res = $outputdl->headers (); - $this->assertSame (in_array ("Accept-Ranges: bytes", $res), true); - } + public function test_outputdl_Announce_1() + { + // Check the announce of Resume mode Enabled + $outputdl = new Outputdl(); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + $res = $outputdl->headers(); + $this->assertSame(in_array("Accept-Ranges: bytes", $res), true); + } - public function test_outputdl_Announce_2 () - { - // Check the announce of Resume mode Disabled - $outputdl = new Outputdl (); - $outputdl->resumeAllow (false); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - $res = $outputdl->headers (); - $this->assertSame (in_array ("Accept-Ranges: none", $res), true); - } + public function test_outputdl_Announce_2() + { + // Check the announce of Resume mode Disabled + $outputdl = new Outputdl(); + $outputdl->resumeAllow(false); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + $res = $outputdl->headers(); + $this->assertSame(in_array("Accept-Ranges: none", $res), true); + } - public function test_outputdl_Partial_1 () - { - // Check the content get with provided range - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=3-9"; - $this->expectOutputString ("4567890"); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - unset ($_SERVER["HTTP_RANGE"]); - } + public function test_outputdl_Partial_1() + { + // Check the content get with provided range + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=3-9"; + $this->expectOutputString("4567890"); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + unset($_SERVER["HTTP_RANGE"]); + } - public function test_outputdl_Partial_2 () - { - // Check the content get with provided range - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=3-"; - $this->expectOutputString (substr (str_repeat ( - "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", - 1000), 3)); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - unset ($_SERVER["HTTP_RANGE"]); - } + public function test_outputdl_Partial_2() + { + // Check the content get with provided range + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=3-"; + $this->expectOutputString(substr(str_repeat( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", + 1000 + ), 3)); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + unset($_SERVER["HTTP_RANGE"]); + } - public function test_outputdl_Partial_3 () - { - // Check the content get with provided range - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=0-"; - $this->expectOutputString (str_repeat ( - "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", - 1000)); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - unset ($_SERVER["HTTP_RANGE"]); - } + public function test_outputdl_Partial_3() + { + // Check the content get with provided range + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=0-"; + $this->expectOutputString(str_repeat( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", + 1000 + )); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + unset($_SERVER["HTTP_RANGE"]); + } - public function test_outputdl_Partial_4 () - { - // Check the content get with provided range - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=-5"; - $this->expectOutputString ("wxyz\n"); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - unset ($_SERVER["HTTP_RANGE"]); - } + public function test_outputdl_Partial_4() + { + // Check the content get with provided range + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=-5"; + $this->expectOutputString("wxyz\n"); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + unset($_SERVER["HTTP_RANGE"]); + } - public function test_outputdl_Partial_5 () - { - // Check the content get with provided range - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=0-3,6-9"; - $this->expectOutputString ("--Qm91bmRhcnk=\r + public function test_outputdl_Partial_5() + { + // Check the content get with provided range + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=0-3,6-9"; + $this->expectOutputString("--Qm91bmRhcnk=\r Content-Range: bytes 0-3/63000\r Content-Type: application/octet-stream\r \r @@ -114,92 +120,102 @@ Content-Type: application/octet-stream\r 7890\r --Qm91bmRhcnk=--\r "); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - unset ($_SERVER["HTTP_RANGE"]); - } + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + unset($_SERVER["HTTP_RANGE"]); + } - public function test_outputdl_PartialWrong_1 () - { - // Check the invalid provided range - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=99999-"; - $this->expectException ("Exception", "Invalid range provided", 416); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_PartialWrong_1() + { + // Check the invalid provided range + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=99999-"; + $this->expectException("Exception", "Invalid range provided", 416); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_PartialWrong_2 () - { - // Check the invalid provided range - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=9-3"; - $this->expectException ("Exception", "Invalid range provided", 416); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_PartialWrong_2() + { + // Check the invalid provided range + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=9-3"; + $this->expectException("Exception", "Invalid range provided", 416); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_PartialWrong_3 () - { - // Check the invalid provided range - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=9-999999"; - $this->expectException ("Exception", "Invalid range provided", 416); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_PartialWrong_3() + { + // Check the invalid provided range + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=9-999999"; + $this->expectException("Exception", "Invalid range provided", 416); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_PartialWrong_4 () - { - // Check the invalid provided range - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $_SERVER["HTTP_RANGE"] = "bytes=-"; - $this->expectException ("Exception", "Invalid range provided", 416); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_PartialWrong_4() + { + // Check the invalid provided range + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $_SERVER["HTTP_RANGE"] = "bytes=-"; + $this->expectException("Exception", "Invalid range provided", 416); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_invalidBase_1 () - { - // Check the base comparison : OK - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $outputdl->base ("/tmp"); - $this->expectOutputString (str_repeat ( - "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", - 1000)); - $outputdl->downloadFile ("/tmp/testDFWoutputDL"); - } + public function test_outputdl_invalidBase_1() + { + // Check the base comparison : OK + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $outputdl->base("/tmp"); + $this->expectOutputString(str_repeat( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n", + 1000 + )); + $outputdl->downloadFile("/tmp/testDFWoutputDL"); + } - public function test_outputdl_invalidBase_2 () - { - // Check the base comparison : BAD - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $outputdl->base ("/tmp"); - $this->expectException ("Exception", - "Invalid file to download : out of base", 406); - $outputdl->downloadFile ("../../../../../..//etc/passwd"); - } + public function test_outputdl_invalidBase_2() + { + // Check the base comparison : BAD + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $outputdl->base("/tmp"); + $this->expectException( + "Exception", + "Invalid file to download : out of base", + 406 + ); + $outputdl->downloadFile("../../../../../..//etc/passwd"); + } - public function test_outputdl_invalidFile_1 () - { - // Check the base comparison : BAD Symlink - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $outputdl->base ("/tmp"); - $this->expectException ("Exception", - "Invalid file to download : not a file", 406); - $outputdl->downloadFile ("/tmp/testDFWoutputDL3"); - } + public function test_outputdl_invalidFile_1() + { + // Check the base comparison : BAD Symlink + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $outputdl->base("/tmp"); + $this->expectException( + "Exception", + "Invalid file to download : not a file", + 406 + ); + $outputdl->downloadFile("/tmp/testDFWoutputDL3"); + } - public function test_outputdl_invalidFile_2 () - { - // Check the base comparison : Non existing - unset ($_SERVER["HTTP_RANGE"]); - $outputdl = new Outputdl (); - $outputdl->base ("/tmp"); - $this->expectException ("Exception", - "Invalid file to download : file doesn't exists", 404); - $outputdl->downloadFile ("/tmp/testDFWoutputNON"); - } + public function test_outputdl_invalidFile_2() + { + // Check the base comparison : Non existing + unset($_SERVER["HTTP_RANGE"]); + $outputdl = new Outputdl(); + $outputdl->base("/tmp"); + $this->expectException( + "Exception", + "Invalid file to download : file doesn't exists", + 404 + ); + $outputdl->downloadFile("/tmp/testDFWoutputNON"); + } } diff --git a/Tests/OutputhtmlTest.php b/Tests/OutputhtmlTest.php index 178003e..2c45a62 100644 --- a/Tests/OutputhtmlTest.php +++ b/Tests/OutputhtmlTest.php @@ -1,4 +1,5 @@ @@ -13,52 +14,59 @@ use Domframework\Outputhtml; class OutputhtmlTest extends \PHPUnit_Framework_TestCase { /** Entry null */ - public function testlayout1 () - { - $this->expectOutputRegex ("#\s+#"); - $output = new Outputhtml (); - $res = $output->out (""); - } + public function testlayout1() + { + $this->expectOutputRegex("#\s+#"); + $output = new Outputhtml(); + $res = $output->out(""); + } - public function testlayout2 () - { - $this->expectOutputRegex("#data#"); - $output = new Outputhtml (); - $res = $output->out ("data"); - } + public function testlayout2() + { + $this->expectOutputRegex("#data#"); + $output = new Outputhtml(); + $res = $output->out("data"); + } - public function testlayout3 () - { - $this->expectOutputRegex("#data#"); - $output = new Outputhtml (); - $res = $output->out ("data", "title"); - } + public function testlayout3() + { + $this->expectOutputRegex("#data#"); + $output = new Outputhtml(); + $res = $output->out("data", "title"); + } - public function testlayout4 () - { - $this->expectOutputString(" + public function testlayout4() + { + $this->expectOutputString(" Text -"." "." +" . " " . " \n"); - $output = new Outputhtml (); - $output->out ("data", "title", FALSE, FALSE, "Tests/layout.html" ); - } + $output = new Outputhtml(); + $output->out("data", "title", false, false, "Tests/layout.html"); + } - public function testlayout5 () - { - $this->expectOutputString(" + public function testlayout5() + { + $this->expectOutputString(" Text VARIABLE \n"); - $output = new Outputhtml (); - $variable = array ("var"=>"VARIABLE"); - $output->out ("data", "title", FALSE, FALSE, "Tests/layout.html", - null, $variable); - } + $output = new Outputhtml(); + $variable = array ("var" => "VARIABLE"); + $output->out( + "data", + "title", + false, + false, + "Tests/layout.html", + null, + $variable + ); + } } diff --git a/Tests/OutputjsonTest.php b/Tests/OutputjsonTest.php index a04e07a..e41167b 100644 --- a/Tests/OutputjsonTest.php +++ b/Tests/OutputjsonTest.php @@ -1,4 +1,5 @@ @@ -13,26 +14,26 @@ use Domframework\Outputjson; class OutputjsonTest extends \PHPUnit_Framework_TestCase { /** Entry null */ - public function testoutputjson1 () - { - $this->expectOutputString("\"\""); - $output = new Outputjson (); - $output->out (""); - } + public function testoutputjson1() + { + $this->expectOutputString("\"\""); + $output = new Outputjson(); + $output->out(""); + } /** Entry string */ - public function testoutputjson2 () - { - $this->expectOutputString("\"string\""); - $output = new Outputjson (); - $output->out ("string"); - } + public function testoutputjson2() + { + $this->expectOutputString("\"string\""); + $output = new Outputjson(); + $output->out("string"); + } /** Entry array */ - public function testoutputjson3 () - { - $this->expectOutputString("[1,2,3]"); - $output = new Outputjson (); - $output->out (array (1,2,3)); - } + public function testoutputjson3() + { + $this->expectOutputString("[1,2,3]"); + $output = new Outputjson(); + $output->out(array (1,2,3)); + } } diff --git a/Tests/PasswordTest.php b/Tests/PasswordTest.php index aa401c3..bc30245 100644 --- a/Tests/PasswordTest.php +++ b/Tests/PasswordTest.php @@ -1,4 +1,5 @@ @@ -13,224 +14,237 @@ use Domframework\Password; */ class PasswordTest extends \PHPUnit_Framework_TestCase { - public function test_cryptPasswd_1 () - { - $res = Password::cryptPasswd ("AAA"); - $this->assertSame ($res[0] == "$" && strlen ($res) > 8, true); - } + public function test_cryptPasswd_1() + { + $res = Password::cryptPasswd("AAA"); + $this->assertSame($res[0] == "$" && strlen($res) > 8, true); + } - public function test_cryptPasswd_2 () - { - // Test the randomization of the salt : must be different each time - $res1 = Password::cryptPasswd ("AAA"); - echo "RES1=$res1\n"; - $res2 = Password::cryptPasswd ("AAA"); - echo "RES2=$res2\n"; - $res3 = Password::cryptPasswd ("AAA"); - echo "RES3=$res3\n"; - $this->assertSame (count (array_unique (array ($res1, $res2, $res3))), 3); - // Three passwords : each must have a different result - } + public function test_cryptPasswd_2() + { + // Test the randomization of the salt : must be different each time + $res1 = Password::cryptPasswd("AAA"); + echo "RES1=$res1\n"; + $res2 = Password::cryptPasswd("AAA"); + echo "RES2=$res2\n"; + $res3 = Password::cryptPasswd("AAA"); + echo "RES3=$res3\n"; + $this->assertSame(count(array_unique(array ($res1, $res2, $res3))), 3); + // Three passwords : each must have a different result + } - public function test_cryptPasswd_3 () - { - $this->expectException (); - $res = Password::cryptPasswd (false); - } + public function test_cryptPasswd_3() + { + $this->expectException(); + $res = Password::cryptPasswd(false); + } - public function test_cryptPassword_MYSQL () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "MYSQL"); - $this->assertSame ($res, "*5AF9D0EA5F6406FB0EDD0507F81C1D5CEBE8AC9C"); - } + public function test_cryptPassword_MYSQL() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "MYSQL"); + $this->assertSame($res, "*5AF9D0EA5F6406FB0EDD0507F81C1D5CEBE8AC9C"); + } - public function test_cryptPassword_CRYPT_STD_DES () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_STD_DES"); - $this->assertSame (strlen ($res), 13); - } + public function test_cryptPassword_CRYPT_STD_DES() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_STD_DES"); + $this->assertSame(strlen($res), 13); + } - public function test_cryptPassword_CRYPT_EXT_DES () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_EXT_DES"); - $this->assertSame (strlen ($res), 13); - } + public function test_cryptPassword_CRYPT_EXT_DES() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_EXT_DES"); + $this->assertSame(strlen($res), 13); + } - public function test_cryptPassword_CRYPT_MD5 () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_MD5"); - $this->assertSame (substr ($res, 0, 3) === "$1$" && strlen ($res) === 34, - true); - } + public function test_cryptPassword_CRYPT_MD5() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_MD5"); + $this->assertSame( + substr($res, 0, 3) === "$1$" && strlen($res) === 34, + true + ); + } - public function test_cryptPassword_CRYPT_BLOWFISH () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_BLOWFISH"); - $this->assertSame (substr ($res, 0, 4) === "$2y$" && strlen ($res) === 24, - true); - } + public function test_cryptPassword_CRYPT_BLOWFISH() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_BLOWFISH"); + $this->assertSame( + substr($res, 0, 4) === "$2y$" && strlen($res) === 24, + true + ); + } - public function test_cryptPassword_CRYPT_SHA256 () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_SHA256"); - $this->assertSame ( - substr ($res, 0, 10) === "$5\$rounds=" && strlen ($res) === 75, - true); - } + public function test_cryptPassword_CRYPT_SHA256() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_SHA256"); + $this->assertSame( + substr($res, 0, 10) === "$5\$rounds=" && strlen($res) === 75, + true + ); + } - public function test_cryptPassword_CRYPT_SHA512 () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "CRYPT_SHA512"); - $this->assertSame ( - substr ($res, 0, 10) === "$6\$rounds=" && strlen ($res) === 118, - true); - } + public function test_cryptPassword_CRYPT_SHA512() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "CRYPT_SHA512"); + $this->assertSame( + substr($res, 0, 10) === "$6\$rounds=" && strlen($res) === 118, + true + ); + } - public function test_cryptPassword_PASSWORD_BCRYPT () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "PASSWORD_BCRYPT"); - $this->assertSame ( - substr ($res, 0, 7) === "$2y\$10\$" && strlen ($res) === 60, - true); - } + public function test_cryptPassword_PASSWORD_BCRYPT() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "PASSWORD_BCRYPT"); + $this->assertSame( + substr($res, 0, 7) === "$2y\$10\$" && strlen($res) === 60, + true + ); + } - public function test_cryptPassword_PASSWORD_ARGON2I () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "PASSWORD_ARGON2I"); - $this->assertSame ( - substr ($res, 0, 11) === "\$argon2i\$v=" && strlen ($res) === 96, - true); - } + public function test_cryptPassword_PASSWORD_ARGON2I() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "PASSWORD_ARGON2I"); + $this->assertSame( + substr($res, 0, 11) === "\$argon2i\$v=" && strlen($res) === 96, + true + ); + } - public function test_cryptPassword_PASSWORD_ARGON2ID () - { - $password = new password (); - $res = $password->cryptPassword ("AAA", "PASSWORD_ARGON2ID"); - $this->assertSame ( - substr ($res, 0, 12) === "\$argon2id\$v=" && strlen ($res) === 97, - true); - } + public function test_cryptPassword_PASSWORD_ARGON2ID() + { + $password = new password(); + $res = $password->cryptPassword("AAA", "PASSWORD_ARGON2ID"); + $this->assertSame( + substr($res, 0, 12) === "\$argon2id\$v=" && strlen($res) === 97, + true + ); + } - public function test_cryptPassword_UNKNOWN () - { - $this->expectException (); - $password = new password (); - $res = $password->cryptPassword ("AAA", "UNKNOWN"); - } + public function test_cryptPassword_UNKNOWN() + { + $this->expectException(); + $password = new password(); + $res = $password->cryptPassword("AAA", "UNKNOWN"); + } - public function test_checkPassword_1 () - { - $res = Password::checkPassword ("AAA", "AAA"); - $this->assertSame ($res, false); - } + public function test_checkPassword_1() + { + $res = Password::checkPassword("AAA", "AAA"); + $this->assertSame($res, false); + } - public function test_checkPassword_2 () - { - $crypt = Password::cryptPasswd ("AAA"); - $res = Password::checkPassword ("AAA", $crypt); - $this->assertSame ($res, true); - } + public function test_checkPassword_2() + { + $crypt = Password::cryptPasswd("AAA"); + $res = Password::checkPassword("AAA", $crypt); + $this->assertSame($res, true); + } - public function test_checkPassword_3 () - { - $res = Password::checkPassword ("AAA", Password::cryptPasswd ("BBB")); - $this->assertSame ($res, false); - } + public function test_checkPassword_3() + { + $res = Password::checkPassword("AAA", Password::cryptPasswd("BBB")); + $this->assertSame($res, false); + } - public function test_checkPassword_4 () - { - $res = Password::checkPassword ("AAA", - '$2y$11$Y.E98jbjgDpV61eK..9MT.klzTeg7ulO4WH/B5yA8cAGMIh.zoNXq'); - $this->assertSame ($res, true); - } + public function test_checkPassword_4() + { + $res = Password::checkPassword( + "AAA", + '$2y$11$Y.E98jbjgDpV61eK..9MT.klzTeg7ulO4WH/B5yA8cAGMIh.zoNXq' + ); + $this->assertSame($res, true); + } - public function test_checkPassword_invalid1 () - { - $this->expectException (); - $res = Password::checkPassword (false, - '$2y$11$Y.E98jbjgDpV61eK..9MT.klzTeg7ulO4WH/B5yA8cAGMIh.zoNXq'); - } + public function test_checkPassword_invalid1() + { + $this->expectException(); + $res = Password::checkPassword( + false, + '$2y$11$Y.E98jbjgDpV61eK..9MT.klzTeg7ulO4WH/B5yA8cAGMIh.zoNXq' + ); + } - public function test_checkPassword_invalid2 () - { - $this->expectException (); - $res = Password::checkPassword ("AAA", false); - } + public function test_checkPassword_invalid2() + { + $this->expectException(); + $res = Password::checkPassword("AAA", false); + } - public function test_generateASCII_defaultsize () - { - $res = Password::generateASCII (); - $this->assertSame (strlen ($res), 12); - } + public function test_generateASCII_defaultsize() + { + $res = Password::generateASCII(); + $this->assertSame(strlen($res), 12); + } - public function test_generateASCII_toobig () - { - $this->expectException (); - $res = Password::generateASCII (112); - } + public function test_generateASCII_toobig() + { + $this->expectException(); + $res = Password::generateASCII(112); + } - public function test_generateASCII_toosmall () - { - $this->expectException (); - $res = Password::generateASCII (0); - } + public function test_generateASCII_toosmall() + { + $this->expectException(); + $res = Password::generateASCII(0); + } - public function test_generateAlphanum_defaultsize () - { - $res = Password::generateAlphanum (); - $this->assertSame (strlen ($res), 12); - } + public function test_generateAlphanum_defaultsize() + { + $res = Password::generateAlphanum(); + $this->assertSame(strlen($res), 12); + } - public function test_generateAlphanum_toobig () - { - $this->expectException (); - $res = Password::generateAlphanum (112); - } + public function test_generateAlphanum_toobig() + { + $this->expectException(); + $res = Password::generateAlphanum(112); + } - public function test_generateAlphanum_toosmall () - { - $this->expectException (); - $res = Password::generateAlphanum (0); - } + public function test_generateAlphanum_toosmall() + { + $this->expectException(); + $res = Password::generateAlphanum(0); + } - public function test_generateAlphabetical_defaultsize () - { - $res = Password::generateAlphabetical (); - $this->assertSame (strlen ($res), 12); - } + public function test_generateAlphabetical_defaultsize() + { + $res = Password::generateAlphabetical(); + $this->assertSame(strlen($res), 12); + } - public function test_generateAlphabetical_toobig () - { - $this->expectException (); - $res = Password::generateAlphabetical (112); - } + public function test_generateAlphabetical_toobig() + { + $this->expectException(); + $res = Password::generateAlphabetical(112); + } - public function test_generateAlphabetical_toosmall () - { - $this->expectException (); - $res = Password::generateAlphabetical (0); - } + public function test_generateAlphabetical_toosmall() + { + $this->expectException(); + $res = Password::generateAlphabetical(0); + } - public function test_listMethods_1 () - { - $password = new password (); - $res = $password->listMethods(); - $this->assertSame (count ($res) > 7, true); - } + public function test_listMethods_1() + { + $password = new password(); + $res = $password->listMethods(); + $this->assertSame(count($res) > 7, true); + } - public function test_salt_1 () - { - $password = new password (); - $res = $password->salt(); - $this->assertSame (strlen ($res) > 20, true); - } + public function test_salt_1() + { + $password = new password(); + $res = $password->salt(); + $this->assertSame(strlen($res) > 20, true); + } } diff --git a/Tests/QueueTest.php b/Tests/QueueTest.php index 05b097b..d4915e2 100644 --- a/Tests/QueueTest.php +++ b/Tests/QueueTest.php @@ -1,4 +1,5 @@ @@ -12,8 +13,8 @@ use Domframework\Queue; /** Test the Queue.php file */ class QueueTest extends \PHPUnit_Framework_TestCase { - public function test () - { - $queue = new Queue (); - } + public function test() + { + $queue = new Queue(); + } } diff --git a/Tests/QueuefileTest.php b/Tests/QueuefileTest.php index d6a9fb4..8aa6d0c 100644 --- a/Tests/QueuefileTest.php +++ b/Tests/QueuefileTest.php @@ -1,4 +1,5 @@ @@ -12,131 +13,131 @@ use Domframework\Queuefile; /** Test the Queuefile.php file */ class QueuefileTest extends \PHPUnit_Framework_TestCase { - public function test_clean () - { - if (file_exists ("/tmp/queuefileTest/queuefileTest.json")) - unlink ("/tmp/queuefileTest/queuefileTest.json"); - } + public function test_clean() + { + if (file_exists("/tmp/queuefileTest/queuefileTest.json")) { + unlink("/tmp/queuefileTest/queuefileTest.json"); + } + } - public function test_add1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->add ("test1"); - $this->assertSame (true, is_object ($res)); - } + public function test_add1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->add("test1"); + $this->assertSame(true, is_object($res)); + } - public function test_count1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->count (); - $this->assertSame (1, $res); - } + public function test_count1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->count(); + $this->assertSame(1, $res); + } - public function test_add2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->add ("test2"); - $this->assertSame (true, is_object ($res)); - } + public function test_add2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->add("test2"); + $this->assertSame(true, is_object($res)); + } - public function test_count2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->count (); - $this->assertSame (2, $res); - } + public function test_count2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->count(); + $this->assertSame(2, $res); + } - public function test_getFirst1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getFirst (); - $this->assertSame ("test1", $res); - } + public function test_getFirst1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getFirst(); + $this->assertSame("test1", $res); + } - public function test_getLast1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getLast (); - $this->assertSame ("test2", $res); - } + public function test_getLast1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getLast(); + $this->assertSame("test2", $res); + } - public function test_getRange1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getRange (1, 1); - $this->assertSame (["test2"], $res); - } + public function test_getRange1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getRange(1, 1); + $this->assertSame(["test2"], $res); + } - public function test_getRange2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getRange (0, 2); - $this->assertSame (["test1", "test2"], $res); - } + public function test_getRange2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getRange(0, 2); + $this->assertSame(["test1", "test2"], $res); + } - public function test_getRange3 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $this->expectException (); - $res = $queuefile->getRange (0, 3); - } + public function test_getRange3() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $this->expectException(); + $res = $queuefile->getRange(0, 3); + } - public function test_getAll1 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getAll (); - $this->assertSame (["test1", "test2"], $res); - } + public function test_getAll1() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getAll(); + $this->assertSame(["test1", "test2"], $res); + } // AFTER THIS TEST THE FILE WILL BE EMPTY - public function test_getAll2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->clear (); - $this->assertSame (true, is_object ($res)); - } + public function test_getAll2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->clear(); + $this->assertSame(true, is_object($res)); + } - public function test_count3 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->count (); - $this->assertSame (0, $res); - } + public function test_count3() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->count(); + $this->assertSame(0, $res); + } - public function test_getAll3 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getAll (); - $this->assertSame ([], $res); - } + public function test_getAll3() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getAll(); + $this->assertSame([], $res); + } - public function test_getFirst2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getFirst (); - $this->assertSame (null, $res); - } - - public function test_getLast2 () - { - $queuefile = new Queuefile (); - $queuefile->connect ("file:///tmp/queuefileTest/queuefileTest.json"); - $res = $queuefile->getLast (); - $this->assertSame (null, $res); - } + public function test_getFirst2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getFirst(); + $this->assertSame(null, $res); + } + public function test_getLast2() + { + $queuefile = new Queuefile(); + $queuefile->connect("file:///tmp/queuefileTest/queuefileTest.json"); + $res = $queuefile->getLast(); + $this->assertSame(null, $res); + } } diff --git a/Tests/RatelimitTest.php b/Tests/RatelimitTest.php index e44e62b..49e58db 100644 --- a/Tests/RatelimitTest.php +++ b/Tests/RatelimitTest.php @@ -1,4 +1,5 @@ @@ -12,8 +13,8 @@ use Domframework\Ratelimit; /** Test the Ratelimit.php file */ class RatelimitTest extends \PHPUnit_Framework_TestCase { - public function test_ratelimit0 () - { - $ratelimit = new Ratelimit (); - } + public function test_ratelimit0() + { + $ratelimit = new Ratelimit(); + } } diff --git a/Tests/RatelimitfileTest.php b/Tests/RatelimitfileTest.php index 0293e54..66961da 100644 --- a/Tests/RatelimitfileTest.php +++ b/Tests/RatelimitfileTest.php @@ -1,4 +1,5 @@ @@ -12,65 +13,65 @@ use Domframework\Ratelimitfile; /** Test the Ratelimitfile.php file */ class RatelimitfileTest extends \PHPUnit_Framework_TestCase { - public function test_ratelimitfile0 () - { - exec ("rm -rf /tmp/testDFWratelimit"); - } + public function testRatelimitfile0() + { + exec("rm -rf /tmp/testDFWratelimit"); + } - public function test_ratelimitfile1 () - { - // Create one non ratelimited entry - $ratelimitfile = new Ratelimitfile (); - $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; - $res = $ratelimitfile->set ("TOTO"); - $this->assertSame (true, $res); - } + public function testRatelimitfile1() + { + // Create one non ratelimited entry + $ratelimitfile = new Ratelimitfile(); + $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; + $res = $ratelimitfile->set("TOTO"); + $this->assertSame(true, $res); + } - public function test_ratelimitfile2 () - { - // Too much entries - $ratelimitfile = new Ratelimitfile (); - $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $ratelimitfile->set ("TOTO"); - $res = $ratelimitfile->set ("TOTO"); - $this->assertSame (false, $res); - } + public function testRatelimitfile2() + { + // Too much entries + $ratelimitfile = new Ratelimitfile(); + $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $ratelimitfile->set("TOTO"); + $res = $ratelimitfile->set("TOTO"); + $this->assertSame(false, $res); + } - public function test_ratelimitfile3 () - { - // Del the ratelimited entry - $ratelimitfile = new Ratelimitfile (); - $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; - $res = $ratelimitfile->del ("TOTO"); - $this->assertSame (true, $res); - } + public function testRatelimitfile3() + { + // Del the ratelimited entry + $ratelimitfile = new Ratelimitfile(); + $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; + $res = $ratelimitfile->del("TOTO"); + $this->assertSame(true, $res); + } - public function test_ratelimitfile4 () - { - // Create one non ratelimited entry - $ratelimitfile = new Ratelimitfile (); - $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; - $res = $ratelimitfile->set ("TOTO"); - $this->assertSame (true, $res); - } + public function testRatelimitfile4() + { + // Create one non ratelimited entry + $ratelimitfile = new Ratelimitfile(); + $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; + $res = $ratelimitfile->set("TOTO"); + $this->assertSame(true, $res); + } - public function test_ratelimitfile5 () - { - // Clean expired entries - sleep (2); - $ratelimitfile = new Ratelimitfile (); - $ratelimitfile->unittime = 1; - $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; - $ratelimitfile->clean (); - $res = count (glob ("/tmp/testDFWratelimit/*")); - $this->assertSame (0, $res); - } + public function testRatelimitfile5() + { + // Clean expired entries + sleep(2); + $ratelimitfile = new Ratelimitfile(); + $ratelimitfile->unittime = 1; + $ratelimitfile->storageDir = "/tmp/testDFWratelimit"; + $ratelimitfile->clean(); + $res = count(glob("/tmp/testDFWratelimit/*")); + $this->assertSame(0, $res); + } } diff --git a/Tests/RestTest.php b/Tests/RestTest.php index 2032e9d..b729020 100644 --- a/Tests/RestTest.php +++ b/Tests/RestTest.php @@ -1,4 +1,5 @@ @@ -14,52 +15,52 @@ class RestTest extends \PHPUnit_Framework_TestCase { /** No param, JSON by default */ - public function testChooseType1 () - { - $rest = new Rest (); - $res = $rest->chooseType (); - $this->assertSame ($res, "json"); - } + public function testChooseType1() + { + $rest = new Rest(); + $res = $rest->chooseType(); + $this->assertSame($res, "json"); + } /** If limited allowedTypes, return the first one as default */ - public function testChooseType2 () - { - $rest = new Rest (); - $rest->allowedtypes = array ("xml", "csv"); - $res = $rest->chooseType (); - $this->assertSame ($res, "xml"); - } + public function testChooseType2() + { + $rest = new Rest(); + $rest->allowedtypes = array ("xml", "csv"); + $res = $rest->chooseType(); + $this->assertSame($res, "xml"); + } /** Choose by the user specification : exact match */ - public function testChooseType3 () - { - $rest = new Rest (); - $_SERVER["HTTP_ACCEPT"] = "text/html,application/xml;q=0.9,*/*;q=0.8"; - $res = $rest->chooseType (); - $this->assertSame ($res, "xml"); - } + public function testChooseType3() + { + $rest = new Rest(); + $_SERVER["HTTP_ACCEPT"] = "text/html,application/xml;q=0.9,*/*;q=0.8"; + $res = $rest->chooseType(); + $this->assertSame($res, "xml"); + } /** Choose by the user specification : generic match */ - public function testChooseType4 () - { - $rest = new Rest (); - $_SERVER["HTTP_ACCEPT"] = "text/html;q=0.9,*/*;q=0.8"; - $res = $rest->chooseType (); - $this->assertSame ($res, "json"); - } + public function testChooseType4() + { + $rest = new Rest(); + $_SERVER["HTTP_ACCEPT"] = "text/html;q=0.9,*/*;q=0.8"; + $res = $rest->chooseType(); + $this->assertSame($res, "json"); + } /** Choose by the user specification : generic match with limited allowed * types */ - public function testChooseType5 () - { - $rest = new Rest (); - $rest->allowedtypes = array ("xml", "csv"); - $_SERVER["HTTP_ACCEPT"] = "text/html;q=0.9,*/*;q=0.8"; - $res = $rest->chooseType (); - $this->assertSame ($res, "xml"); - } + public function testChooseType5() + { + $rest = new Rest(); + $rest->allowedtypes = array ("xml", "csv"); + $_SERVER["HTTP_ACCEPT"] = "text/html;q=0.9,*/*;q=0.8"; + $res = $rest->chooseType(); + $this->assertSame($res, "xml"); + } } diff --git a/Tests/RobotstxtTest.php b/Tests/RobotstxtTest.php index ad159eb..8b494a5 100644 --- a/Tests/RobotstxtTest.php +++ b/Tests/RobotstxtTest.php @@ -1,4 +1,5 @@ @@ -14,216 +15,253 @@ use Domframework\Robotstxt; class RobotstxtTest extends \PHPUnit_Framework_TestCase { // Empty Robots - public function test_Construct_1 () - { - $robotstxt = new Robotstxt ("", "domsearch"); - $res = $robotstxt->allow (); - $this->assertSame ($res, ["/"]); - } - public function test_Construct_2 () - { - $robotstxt = new Robotstxt ("", "domsearch"); - $res = $robotstxt->disallow (); - $this->assertSame ($res, array ()); - } - public function test_Construct_3 () - { - $robotstxt = new Robotstxt ("", "domsearch"); - $res = $robotstxt->sitemaps (); - $this->assertSame ($res, array ()); - } - public function test_Construct_4 () - { - $robotstxt = new Robotstxt ("", "domsearch"); - $res = $robotstxt->crawldelay (); - $this->assertSame ($res, null); - } + public function test_Construct_1() + { + $robotstxt = new Robotstxt("", "domsearch"); + $res = $robotstxt->allow(); + $this->assertSame($res, ["/"]); + } + public function test_Construct_2() + { + $robotstxt = new Robotstxt("", "domsearch"); + $res = $robotstxt->disallow(); + $this->assertSame($res, array ()); + } + public function test_Construct_3() + { + $robotstxt = new Robotstxt("", "domsearch"); + $res = $robotstxt->sitemaps(); + $this->assertSame($res, array ()); + } + public function test_Construct_4() + { + $robotstxt = new Robotstxt("", "domsearch"); + $res = $robotstxt->crawldelay(); + $this->assertSame($res, null); + } // Allow - public function test_allow_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow:\n", "domsearch"); - $res = $robotstxt->allow (); - $this->assertSame ($res, ["/"]); - } - public function test_allow_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow:\n\nUser-Agent: DomSearch\nDisallow:\n", - "domsearch"); - $res = $robotstxt->allow (); - $this->assertSame ($res, ["/"]); - } - public function test_allow_3 () - { - $robotstxt = new Robotstxt ( - "User-Agent: DomSearch\nDisallow:\n\nUser-Agent: *\nDisallow:\n", - "domsearch"); - $res = $robotstxt->allow (); - $this->assertSame ($res, ["/"]); - } - public function test_allow_4 () - { - $robotstxt = new Robotstxt ( - "User-Agent: DomSearch\n". - "User-Agent: User1\n". - "User-Agent: User2\n". - "Disallow:\n\n". - "User-Agent: *\n". - "Disallow: /\n", "domsearch"); - $res = $robotstxt->allow (); - $this->assertSame ($res, ["/"]); - } + public function test_allow_1() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow:\n", + "domsearch" + ); + $res = $robotstxt->allow(); + $this->assertSame($res, ["/"]); + } + public function test_allow_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow:\n\nUser-Agent: DomSearch\nDisallow:\n", + "domsearch" + ); + $res = $robotstxt->allow(); + $this->assertSame($res, ["/"]); + } + public function test_allow_3() + { + $robotstxt = new Robotstxt( + "User-Agent: DomSearch\nDisallow:\n\nUser-Agent: *\nDisallow:\n", + "domsearch" + ); + $res = $robotstxt->allow(); + $this->assertSame($res, ["/"]); + } + public function test_allow_4() + { + $robotstxt = new Robotstxt( + "User-Agent: DomSearch\n" . + "User-Agent: User1\n" . + "User-Agent: User2\n" . + "Disallow:\n\n" . + "User-Agent: *\n" . + "Disallow: /\n", + "domsearch" + ); + $res = $robotstxt->allow(); + $this->assertSame($res, ["/"]); + } // Disallow - public function test_disallow_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n", "domsearch"); - $res = $robotstxt->disallow (); - $this->assertSame ($res, ["/"]); - } - public function test_disallow_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n\nUser-Agent: DomSearch\nDisallow: /\n", - "domsearch"); - $res = $robotstxt->disallow (); - $this->assertSame ($res, ["/"]); - } - public function test_disallow_3 () - { - $robotstxt = new Robotstxt ( - "User-Agent: DomSearch\nDisallow: /\n\nUser-Agent: *\nDisallow: /\n", - "domsearch"); - $res = $robotstxt->disallow (); - $this->assertSame ($res, ["/"]); - } + public function test_disallow_1() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n", + "domsearch" + ); + $res = $robotstxt->disallow(); + $this->assertSame($res, ["/"]); + } + public function test_disallow_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n\nUser-Agent: DomSearch\nDisallow: /\n", + "domsearch" + ); + $res = $robotstxt->disallow(); + $this->assertSame($res, ["/"]); + } + public function test_disallow_3() + { + $robotstxt = new Robotstxt( + "User-Agent: DomSearch\nDisallow: /\n\nUser-Agent: *\nDisallow: /\n", + "domsearch" + ); + $res = $robotstxt->disallow(); + $this->assertSame($res, ["/"]); + } // Sitemaps - public function test_sitemaps_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: DomSearch\nDisallow: /\n\nUser-Agent: *\nDisallow: /\n", - "domsearch"); - $res = $robotstxt->sitemaps (); - $this->assertSame ($res, []); - } - public function test_sitemaps_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nSitemap: http://example.com/sitemap.xml", - "domsearch"); - $res = $robotstxt->sitemaps (); - $this->assertSame ($res, ["http://example.com/sitemap.xml"]); - } - public function test_sitemaps_3 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n". - "Sitemap: http://example.com/sitemap.xml\n". - "Sitemap: http://example.com/SITEMAP.XML", "domsearch"); - $res = $robotstxt->sitemaps (); - $this->assertSame ($res, - ["http://example.com/sitemap.xml", "http://example.com/SITEMAP.XML"]); - } + public function test_sitemaps_1() + { + $robotstxt = new Robotstxt( + "User-Agent: DomSearch\nDisallow: /\n\nUser-Agent: *\nDisallow: /\n", + "domsearch" + ); + $res = $robotstxt->sitemaps(); + $this->assertSame($res, []); + } + public function test_sitemaps_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nSitemap: http://example.com/sitemap.xml", + "domsearch" + ); + $res = $robotstxt->sitemaps(); + $this->assertSame($res, ["http://example.com/sitemap.xml"]); + } + public function test_sitemaps_3() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n" . + "Sitemap: http://example.com/sitemap.xml\n" . + "Sitemap: http://example.com/SITEMAP.XML", + "domsearch" + ); + $res = $robotstxt->sitemaps(); + $this->assertSame( + $res, + ["http://example.com/sitemap.xml", "http://example.com/SITEMAP.XML"] + ); + } - public function test_sitemaps_error_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nSitemap: URL", - "domsearch"); - $res = $robotstxt->errors (); - $this->assertSame ($res, [2 => "Sitemap : Invalid URL provided"]); - } + public function test_sitemaps_error_1() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nSitemap: URL", + "domsearch" + ); + $res = $robotstxt->errors(); + $this->assertSame($res, [2 => "Sitemap : Invalid URL provided"]); + } // Host - public function test_host_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n", "domsearch"); - $res = $robotstxt->host (); - $this->assertSame ($res, null); - } - public function test_host_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n\nHost: localhost", "domsearch"); - $res = $robotstxt->host (); - $this->assertSame ($res, "localhost"); - } - public function test_host_error_1 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n\nHost: localhost\nHoST: toto", "domsearch"); - $res = $robotstxt->host (); - $this->assertSame ($res, "localhost"); - } - public function test_host_error_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\n\nHost: localhost\nHoST: toto", "domsearch"); - $res = $robotstxt->errors (); - $this->assertSame ($res, [4 => "Multiple Hosts set"]); - } + public function test_host_1() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n", + "domsearch" + ); + $res = $robotstxt->host(); + $this->assertSame($res, null); + } + public function test_host_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n\nHost: localhost", + "domsearch" + ); + $res = $robotstxt->host(); + $this->assertSame($res, "localhost"); + } + public function test_host_error_1() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n\nHost: localhost\nHoST: toto", + "domsearch" + ); + $res = $robotstxt->host(); + $this->assertSame($res, "localhost"); + } + public function test_host_error_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\n\nHost: localhost\nHoST: toto", + "domsearch" + ); + $res = $robotstxt->errors(); + $this->assertSame($res, [4 => "Multiple Hosts set"]); + } // URLAllow - public function test_urlallow_1 () - { - $robotstxt = new Robotstxt ("", "domsearch"); - $res = $robotstxt->URLAllow ("/"); - $this->assertSame ($res, true); - } - public function test_urlallow_2 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /", "domsearch"); - $res = $robotstxt->URLAllow ("/"); - $this->assertSame ($res, false); - } - public function test_urlallow_3 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nAllow: /allow/", "domsearch"); - $res = $robotstxt->URLAllow ("/"); - $this->assertSame ($res, false); - } - public function test_urlallow_4 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nAllow: /allow/", "domsearch"); - $res = $robotstxt->URLAllow ("/allow/file"); - $this->assertSame ($res, true); - } - public function test_urlallow_5 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif$", "domsearch"); - $res = $robotstxt->URLAllow ("/allow/file.gif"); - $this->assertSame ($res, true); - } - public function test_urlallow_6 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif$", "domsearch"); - $res = $robotstxt->URLAllow ("/allow/.gif"); - $this->assertSame ($res, false); - } - public function test_urlallow_7 () - { - $robotstxt = new Robotstxt ( - "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif\$", "domsearch"); - $res = $robotstxt->URLAllow ("/allow/file.png"); - $this->assertSame ($res, false); - } + public function test_urlallow_1() + { + $robotstxt = new Robotstxt("", "domsearch"); + $res = $robotstxt->URLAllow("/"); + $this->assertSame($res, true); + } + public function test_urlallow_2() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /", + "domsearch" + ); + $res = $robotstxt->URLAllow("/"); + $this->assertSame($res, false); + } + public function test_urlallow_3() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nAllow: /allow/", + "domsearch" + ); + $res = $robotstxt->URLAllow("/"); + $this->assertSame($res, false); + } + public function test_urlallow_4() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nAllow: /allow/", + "domsearch" + ); + $res = $robotstxt->URLAllow("/allow/file"); + $this->assertSame($res, true); + } + public function test_urlallow_5() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif$", + "domsearch" + ); + $res = $robotstxt->URLAllow("/allow/file.gif"); + $this->assertSame($res, true); + } + public function test_urlallow_6() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif$", + "domsearch" + ); + $res = $robotstxt->URLAllow("/allow/.gif"); + $this->assertSame($res, false); + } + public function test_urlallow_7() + { + $robotstxt = new Robotstxt( + "User-Agent: *\nDisallow: /\nAllow: /allow/*.gif\$", + "domsearch" + ); + $res = $robotstxt->URLAllow("/allow/file.png"); + $this->assertSame($res, false); + } // Tests like http://www.robotstxt.org/norobots-rfc.txt - public function test_rfc_unhipbot_1 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + public function test_rfc_unhipbot_1() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -238,17 +276,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/"), false); - } - public function test_rfc_unhipbot_2 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/"), + false + ); + } + public function test_rfc_unhipbot_2() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -263,17 +304,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/index.html"), false); - } - public function test_rfc_unhipbot_3 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/index.html"), + false + ); + } + public function test_rfc_unhipbot_3() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -288,17 +332,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/robots.txt"), true); - } - public function test_rfc_unhipbot_4 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/robots.txt"), + true + ); + } + public function test_rfc_unhipbot_4() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -313,17 +360,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/server.html"), false); - } - public function test_rfc_unhipbot_5 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/server.html"), + false + ); + } + public function test_rfc_unhipbot_5() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -338,17 +388,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/fast.html"), false); - } - public function test_rfc_unhipbot_6 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/fast.html"), + false + ); + } + public function test_rfc_unhipbot_6() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -363,17 +416,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/slow.html"), false); - } - public function test_rfc_unhipbot_7 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/slow.html"), + false + ); + } + public function test_rfc_unhipbot_7() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -388,17 +444,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/orgo.gif"), false); - } - public function test_rfc_unhipbot_8 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/orgo.gif"), + false + ); + } + public function test_rfc_unhipbot_8() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -413,17 +472,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/about.html"), false); - } - public function test_rfc_unhipbot_9 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/about.html"), + false + ); + } + public function test_rfc_unhipbot_9() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -438,17 +500,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/plans.html"), false); - } - public function test_rfc_unhipbot_10 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/plans.html"), + false + ); + } + public function test_rfc_unhipbot_10() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -463,17 +528,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~jim/jim.html"), false); - } - public function test_rfc_unhipbot_11 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~jim/jim.html"), + false + ); + } + public function test_rfc_unhipbot_11() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -488,17 +556,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "unhipbot" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~mak/mak.html"), false); - } - public function test_rfc_webcrawler_1 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "unhipbot" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~mak/mak.html"), + false + ); + } + public function test_rfc_webcrawler_1() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -513,17 +584,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/"), true); - } - public function test_rfc_webcrawler_2 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/"), + true + ); + } + public function test_rfc_webcrawler_2() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -538,17 +612,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/index.html"), true); - } - public function test_rfc_webcrawler_3 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/index.html"), + true + ); + } + public function test_rfc_webcrawler_3() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -563,17 +640,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/robots.txt"), true); - } - public function test_rfc_webcrawler_4 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/robots.txt"), + true + ); + } + public function test_rfc_webcrawler_4() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -588,17 +668,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/server.html"), true); - } - public function test_rfc_webcrawler_5 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/server.html"), + true + ); + } + public function test_rfc_webcrawler_5() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -613,17 +696,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/fast.html"), true); - } - public function test_rfc_webcrawler_6 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/fast.html"), + true + ); + } + public function test_rfc_webcrawler_6() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -638,17 +724,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/slow.html"), true); - } - public function test_rfc_webcrawler_7 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/slow.html"), + true + ); + } + public function test_rfc_webcrawler_7() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -663,17 +752,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/orgo.gif"), true); - } - public function test_rfc_webcrawler_8 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/orgo.gif"), + true + ); + } + public function test_rfc_webcrawler_8() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -688,17 +780,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/about.html"), true); - } - public function test_rfc_webcrawler_9 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/about.html"), + true + ); + } + public function test_rfc_webcrawler_9() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -713,17 +808,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/plans.html"), true); - } - public function test_rfc_webcrawler_10 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/plans.html"), + true + ); + } + public function test_rfc_webcrawler_10() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -738,17 +836,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~jim/jim.html"), true); - } - public function test_rfc_webcrawler_11 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~jim/jim.html"), + true + ); + } + public function test_rfc_webcrawler_11() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -763,17 +864,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "webcrawler" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~mak/mak.html"), true); - } - public function test_rfc_excite_1 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "webcrawler" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~mak/mak.html"), + true + ); + } + public function test_rfc_excite_1() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -788,17 +892,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/"), true); - } - public function test_rfc_excite_2 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/"), + true + ); + } + public function test_rfc_excite_2() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -813,17 +920,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/index.html"), true); - } - public function test_rfc_excite_3 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/index.html"), + true + ); + } + public function test_rfc_excite_3() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -838,17 +948,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/robots.txt"), true); - } - public function test_rfc_excite_4 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/robots.txt"), + true + ); + } + public function test_rfc_excite_4() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -863,17 +976,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/server.html"), true); - } - public function test_rfc_excite_5 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/server.html"), + true + ); + } + public function test_rfc_excite_5() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -888,17 +1004,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/fast.html"), true); - } - public function test_rfc_excite_6 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/fast.html"), + true + ); + } + public function test_rfc_excite_6() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -913,17 +1032,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/slow.html"), true); - } - public function test_rfc_excite_7 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/slow.html"), + true + ); + } + public function test_rfc_excite_7() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -938,17 +1060,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/orgo.gif"), true); - } - public function test_rfc_excite_8 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/orgo.gif"), + true + ); + } + public function test_rfc_excite_8() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -963,17 +1088,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/about.html"), true); - } - public function test_rfc_excite_9 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/about.html"), + true + ); + } + public function test_rfc_excite_9() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -988,17 +1116,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/plans.html"), true); - } - public function test_rfc_excite_10 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/plans.html"), + true + ); + } + public function test_rfc_excite_10() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1013,17 +1144,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~jim/jim.html"), true); - } - public function test_rfc_excite_11 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~jim/jim.html"), + true + ); + } + public function test_rfc_excite_11() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1038,17 +1172,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "excite" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~mak/mak.html"), true); - } - public function test_rfc_other_1 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "excite" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~mak/mak.html"), + true + ); + } + public function test_rfc_other_1() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1063,16 +1200,17 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ($robotstxt->URLAllow ("http://www.fict.org/"), false); - } - public function test_rfc_other_2 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame($robotstxt->URLAllow("http://www.fict.org/"), false); + } + public function test_rfc_other_2() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1087,17 +1225,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/index.html"), false); - } - public function test_rfc_other_3 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/index.html"), + false + ); + } + public function test_rfc_other_3() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1112,17 +1253,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/robots.txt"), true); - } - public function test_rfc_other_4 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/robots.txt"), + true + ); + } + public function test_rfc_other_4() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1137,17 +1281,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/server.html"), true); - } - public function test_rfc_other_5 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/server.html"), + true + ); + } + public function test_rfc_other_5() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1162,17 +1309,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/fast.html"), true); - } - public function test_rfc_other_6 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/fast.html"), + true + ); + } + public function test_rfc_other_6() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1187,17 +1337,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/services/slow.html"), true); - } - public function test_rfc_other_7 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/services/slow.html"), + true + ); + } + public function test_rfc_other_7() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1212,17 +1365,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/orgo.gif"), false); - } - public function test_rfc_other_8 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/orgo.gif"), + false + ); + } + public function test_rfc_other_8() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1237,17 +1393,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/about.html"), true); - } - public function test_rfc_other_9 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/about.html"), + true + ); + } + public function test_rfc_other_9() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1262,17 +1421,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/org/plans.html"), false); - } - public function test_rfc_other_10 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/org/plans.html"), + false + ); + } + public function test_rfc_other_10() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1287,17 +1449,20 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~jim/jim.html"), false); - } - public function test_rfc_other_11 () - { - // {{{ - $robotstxt = new Robotstxt ( - "# /robots.txt for http://www.fict.org/ + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~jim/jim.html"), + false + ); + } + public function test_rfc_other_11() + { + // {{{ + $robotstxt = new Robotstxt( + "# /robots.txt for http://www.fict.org/ # comments to webmaster@fict.org User-agent: unhipbot @@ -1312,10 +1477,13 @@ class RobotstxtTest extends \PHPUnit_Framework_TestCase Allow: /org/ Allow: /serv Allow: /~mak - Disallow: /", "other" - ); - // }}} - $this->assertSame ( - $robotstxt->URLAllow ("http://www.fict.org/~mak/mak.html"), true); - } + Disallow: /", + "other" + ); + // }}} + $this->assertSame( + $robotstxt->URLAllow("http://www.fict.org/~mak/mak.html"), + true + ); + } } diff --git a/Tests/RouteTest.php b/Tests/RouteTest.php index 3fe226d..352e6d7 100644 --- a/Tests/RouteTest.php +++ b/Tests/RouteTest.php @@ -1,4 +1,5 @@ @@ -14,335 +15,335 @@ class RouteTest extends \PHPUnit_Framework_TestCase { /// RELATIVE /// /** Entry null */ - public function test_baseURL_1_relative () - { - $route = new Route (); - $route->baseURL (); - $this->expectOutputString(""); - } + public function test_baseURL_1_relative() + { + $route = new Route(); + $route->baseURL(); + $this->expectOutputString(""); + } /** Port 80 and HTTP without module */ - public function test_baseURL_2_relative () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (); - $this->expectOutputString("/"); - } + public function test_baseURL_2_relative() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(); + $this->expectOutputString("/"); + } /** Port 443 and HTTPS without module */ - public function test_baseURL_3_relative () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (); - $this->expectOutputString("/"); - } + public function test_baseURL_3_relative() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(); + $this->expectOutputString("/"); + } /** Port 888 and HTTP without module */ - public function test_baseURL_4_relative () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (); - $this->expectOutputString("/"); - } + public function test_baseURL_4_relative() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(); + $this->expectOutputString("/"); + } /** Port 888 and HTTPS without module */ - public function test_baseURL_5_relative () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (); - $this->expectOutputString("/"); - } + public function test_baseURL_5_relative() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(); + $this->expectOutputString("/"); + } /** Port 80 and HTTP with module */ - public function test_baseURL_2_module_relative () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module"); - $this->expectOutputString("/"); - } + public function test_baseURL_2_module_relative() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module"); + $this->expectOutputString("/"); + } /** Port 443 and HTTPS with module */ - public function test_baseURL_3_module_relative () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module"); - $this->expectOutputString("/"); - } + public function test_baseURL_3_module_relative() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module"); + $this->expectOutputString("/"); + } /** Port 888 and HTTP with module */ - public function test_baseURL_4_module_relative () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module"); - $this->expectOutputString("/"); - } + public function test_baseURL_4_module_relative() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module"); + $this->expectOutputString("/"); + } /** Port 888 and HTTPS with module */ - public function test_baseURL_5_module_relative () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module"); - $this->expectOutputString("/"); - } + public function test_baseURL_5_module_relative() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module"); + $this->expectOutputString("/"); + } /// ABSOLUTE /// /** Entry null */ - public function test_baseURL_1_absolute () - { - $route = new Route (); - $route->baseURL (false, true); - $this->expectOutputString(""); - } + public function test_baseURL_1_absolute() + { + $route = new Route(); + $route->baseURL(false, true); + $this->expectOutputString(""); + } /** Port 80 and HTTP without module */ - public function test_baseURL_2_absolute () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (false, true); - $this->expectOutputString("https://localhost:80/"); - } + public function test_baseURL_2_absolute() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(false, true); + $this->expectOutputString("https://localhost:80/"); + } /** Port 443 and HTTPS without module */ - public function test_baseURL_3_absolute () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (false, true); - $this->expectOutputString("https://localhost/"); - } + public function test_baseURL_3_absolute() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(false, true); + $this->expectOutputString("https://localhost/"); + } /** Port 888 and HTTP without module */ - public function test_baseURL_4_absolute () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (false, true); - $this->expectOutputString("http://localhost:888/"); - } + public function test_baseURL_4_absolute() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(false, true); + $this->expectOutputString("http://localhost:888/"); + } /** Port 888 and HTTPS without module */ - public function test_baseURL_5_absolute () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $route = new Route (); - echo $route->baseURL (false, true); - $this->expectOutputString("https://localhost:888/"); - } + public function test_baseURL_5_absolute() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $route = new Route(); + echo $route->baseURL(false, true); + $this->expectOutputString("https://localhost:888/"); + } /** Port 80 and HTTP with module */ - public function test_baseURL_2_module_absolute () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module", true); - $this->expectOutputString("http://localhost/"); - } + public function test_baseURL_2_module_absolute() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module", true); + $this->expectOutputString("http://localhost/"); + } /** Port 443 and HTTPS with module */ - public function test_baseURL_3_module_absolute () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module", true); - $this->expectOutputString("https://localhost/"); - } + public function test_baseURL_3_module_absolute() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module", true); + $this->expectOutputString("https://localhost/"); + } /** Port 888 and HTTP with module */ - public function test_baseURL_4_module_absolute () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module", true); - $this->expectOutputString("http://localhost:888/"); - } + public function test_baseURL_4_module_absolute() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module", true); + $this->expectOutputString("http://localhost:888/"); + } /** Port 888 and HTTPS with module */ - public function test_baseURL_5_module_absolute () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/module/index.php"; - $route = new Route (); - echo $route->baseURL ("module", true); - $this->expectOutputString("https://localhost:888/"); - } + public function test_baseURL_5_module_absolute() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/module/index.php"; + $route = new Route(); + echo $route->baseURL("module", true); + $this->expectOutputString("https://localhost:888/"); + } /// REQUESTURL /// /** Port 80 and HTTP requestURL */ - public function test_requestURL_2_direct () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/index.php?url=bla"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("index.php?url=bla"); - } + public function test_requestURL_2_direct() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/index.php?url=bla"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("index.php?url=bla"); + } /** Port 443 and HTTPS requestURL */ - public function test_requestURL_3_direct () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/index.php?var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("index.php?var=1"); - } + public function test_requestURL_3_direct() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/index.php?var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("index.php?var=1"); + } /** Port 888 and HTTP requestURL */ - public function test_requestURL_4_direct () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/index.php?var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("index.php?var=1"); - } + public function test_requestURL_4_direct() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/index.php?var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("index.php?var=1"); + } /** Port 888 and HTTPS requestURL */ - public function test_requestURL_5_direct () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/index.php?var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("index.php?var=1"); - } + public function test_requestURL_5_direct() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/index.php?var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("index.php?var=1"); + } /** Port 80 and HTTP requestURL */ - public function test_requestURL_2_rewrite () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "80"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/bla"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("bla"); - } + public function test_requestURL_2_rewrite() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "80"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/bla"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("bla"); + } /** Port 443 and HTTPS requestURL */ - public function test_requestURL_3_rewrite () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "443"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("var=1"); - } + public function test_requestURL_3_rewrite() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "443"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("var=1"); + } /** Port 888 and HTTP requestURL */ - public function test_requestURL_4_rewrite () - { - unset ($_SERVER["HTTPS"]); - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("var=1"); - } + public function test_requestURL_4_rewrite() + { + unset($_SERVER["HTTPS"]); + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("var=1"); + } /** Port 888 and HTTPS requestURL */ - public function test_requestURL_5_rewrite () - { - $_SERVER["SERVER_NAME"] = "localhost"; - $_SERVER["SERVER_PORT"] = "888"; - $_SERVER["HTTPS"] = true; - $_SERVER["SCRIPT_NAME"] = "/index.php"; - $_SERVER["REQUEST_URI"] = "/var=1"; - $route = new Route (); - echo $route->requestURL (); - $this->expectOutputString("var=1"); - } + public function test_requestURL_5_rewrite() + { + $_SERVER["SERVER_NAME"] = "localhost"; + $_SERVER["SERVER_PORT"] = "888"; + $_SERVER["HTTPS"] = true; + $_SERVER["SCRIPT_NAME"] = "/index.php"; + $_SERVER["REQUEST_URI"] = "/var=1"; + $route = new Route(); + echo $route->requestURL(); + $this->expectOutputString("var=1"); + } /** Ratelimiting in errors */ - public function test_errorRateLimit1 () - { - $route = new Route (); - $route->ratelimiter->storageDir = "/tmp/ratelimit-".time(); - $route->error (new \Exception ("test1", 500)); - $route->error (new \Exception ("test2", 500)); - $route->error (new \Exception ("test3", 500)); - $route->error (new \Exception ("test4", 500)); - $route->error (new \Exception ("test5", 500)); - $route->error (new \Exception ("test6", 500)); - $route->error (new \Exception ("test7", 500)); - $route->error (new \Exception ("test8", 500)); - $route->error (new \Exception ("test9", 500)); - $route->error (new \Exception ("test0", 500)); - $route->error (new \Exception ("test11", 500)); - $this->expectOutputRegex("#Too much error requests#"); - } + public function test_errorRateLimit1() + { + $route = new Route(); + $route->ratelimiter->storageDir = "/tmp/ratelimit-" . time(); + $route->error(new \Exception("test1", 500)); + $route->error(new \Exception("test2", 500)); + $route->error(new \Exception("test3", 500)); + $route->error(new \Exception("test4", 500)); + $route->error(new \Exception("test5", 500)); + $route->error(new \Exception("test6", 500)); + $route->error(new \Exception("test7", 500)); + $route->error(new \Exception("test8", 500)); + $route->error(new \Exception("test9", 500)); + $route->error(new \Exception("test0", 500)); + $route->error(new \Exception("test11", 500)); + $this->expectOutputRegex("#Too much error requests#"); + } } diff --git a/Tests/RssTest.php b/Tests/RssTest.php index 753c678..919cc9f 100644 --- a/Tests/RssTest.php +++ b/Tests/RssTest.php @@ -1,4 +1,5 @@ @@ -12,31 +13,31 @@ use Domframework\Rss; /** Test the RSS */ class RssTest extends \PHPUnit_Framework_TestCase { - public function test_empty0 () - { - // Empty - $this->expectException ("Exception", "No title is provided for this RSS"); - $rss = new Rss (); - $res = $rss->asXML (); - } + public function test_empty0() + { + // Empty + $this->expectException("Exception", "No title is provided for this RSS"); + $rss = new Rss(); + $res = $rss->asXML(); + } - public function test_functional1 () - { - // Functionnal 1 - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $rss->addItem ()->title ("Item1 Title") - ->link ("http://Item1Link") - ->description ("Item1 Description"); - $rss->addItem ()->title ("Item2 Title") - ->pubDate ("2017-04-13 12:25:30") - ->link ("http://Item2Link") - ->description ("Item2 Description"); - $res = $rss->asXML (); - $this->assertSame ($res, " + public function test_functional1() + { + // Functionnal 1 + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->language("fr-fr") + ->description("The Super Global Description"); + $rss->addItem()->title("Item1 Title") + ->link("http://Item1Link") + ->description("Item1 Description"); + $rss->addItem()->title("Item2 Title") + ->pubDate("2017-04-13 12:25:30") + ->link("http://Item2Link") + ->description("Item2 Description"); + $res = $rss->asXML(); + $this->assertSame($res, " Global Title @@ -57,99 +58,109 @@ class RssTest extends \PHPUnit_Framework_TestCase "); - } + } - public function test_error1 () - { - // Missing global description - $this->expectException ("Exception", - "No description is provided for this RSS"); - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->language ("fr-fr"); - $res = $rss->asXML (); - } + public function test_error1() + { + // Missing global description + $this->expectException( + "Exception", + "No description is provided for this RSS" + ); + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->language("fr-fr"); + $res = $rss->asXML(); + } - public function test_error2 () - { - // Missing global link - $this->expectException ("Exception", "No link is provided for this RSS"); - $rss = new Rss (); - $rss->title ("Global Title") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $res = $rss->asXML (); - } + public function test_error2() + { + // Missing global link + $this->expectException("Exception", "No link is provided for this RSS"); + $rss = new Rss(); + $rss->title("Global Title") + ->language("fr-fr") + ->description("The Super Global Description"); + $res = $rss->asXML(); + } - public function test_error3 () - { - // Missing global title - $this->expectException ("Exception", "No title is provided for this RSS"); - $rss = new Rss (); - $rss->link ("http://localhost") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $res = $rss->asXML (); - } + public function test_error3() + { + // Missing global title + $this->expectException("Exception", "No title is provided for this RSS"); + $rss = new Rss(); + $rss->link("http://localhost") + ->language("fr-fr") + ->description("The Super Global Description"); + $res = $rss->asXML(); + } - public function test_error4 () - { - // Invalid date provided - $this->expectException ("Exception", - "lastBuildDate provided to RSS is not a valid date"); - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->lastBuildDate ("2017-04-33") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $res = $rss->asXML (); - } + public function test_error4() + { + // Invalid date provided + $this->expectException( + "Exception", + "lastBuildDate provided to RSS is not a valid date" + ); + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->lastBuildDate("2017-04-33") + ->language("fr-fr") + ->description("The Super Global Description"); + $res = $rss->asXML(); + } - public function test_itemError1 () - { - // Empty Item provided - $this->expectException ("Exception", - "No title nor description defined in the RSS item"); - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->lastBuildDate ("2017-04-30 12:35:32") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $rss->addItem (); - $res = $rss->asXML (); - } + public function test_itemError1() + { + // Empty Item provided + $this->expectException( + "Exception", + "No title nor description defined in the RSS item" + ); + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->lastBuildDate("2017-04-30 12:35:32") + ->language("fr-fr") + ->description("The Super Global Description"); + $rss->addItem(); + $res = $rss->asXML(); + } - public function test_itemError2 () - { - // Item without Title and Description - $this->expectException ("Exception", - "No title nor description defined in the RSS item"); - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->lastBuildDate ("2017-04-30 12:35:32") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $rss->addItem ()->link ("http://localhost/link"); - $res = $rss->asXML (); - } + public function test_itemError2() + { + // Item without Title and Description + $this->expectException( + "Exception", + "No title nor description defined in the RSS item" + ); + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->lastBuildDate("2017-04-30 12:35:32") + ->language("fr-fr") + ->description("The Super Global Description"); + $rss->addItem()->link("http://localhost/link"); + $res = $rss->asXML(); + } - public function test_itemError3 () - { - // Item with invalid date - $this->expectException ("Exception", - "pubDate provided to RSS Item is not a valid date"); - $rss = new Rss (); - $rss->title ("Global Title") - ->link ("http://localhost") - ->lastBuildDate ("2017-10-30 12:35:32") - ->language ("fr-fr") - ->description ("The Super Global Description"); - $rss->addItem ()->title ("Item title") - ->pubDate ("2017-14-33 12:32:32"); - $res = $rss->asXML (); - } + public function test_itemError3() + { + // Item with invalid date + $this->expectException( + "Exception", + "pubDate provided to RSS Item is not a valid date" + ); + $rss = new Rss(); + $rss->title("Global Title") + ->link("http://localhost") + ->lastBuildDate("2017-10-30 12:35:32") + ->language("fr-fr") + ->description("The Super Global Description"); + $rss->addItem()->title("Item title") + ->pubDate("2017-14-33 12:32:32"); + $res = $rss->asXML(); + } } diff --git a/Tests/SitemapTest.php b/Tests/SitemapTest.php index ed1e3da..0bdbfe9 100644 --- a/Tests/SitemapTest.php +++ b/Tests/SitemapTest.php @@ -1,4 +1,5 @@ @@ -14,46 +15,52 @@ use Domframework\Sitemap; class SitemapTest extends \PHPUnit_Framework_TestCase { // Empty Sitemap - public function test_EmptySitemap_1 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze ("", "http://example.com"); - $this->assertSame ($res, ["urls" => [], "sitemaps" => []]); - } + public function test_EmptySitemap_1() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze("", "http://example.com"); + $this->assertSame($res, ["urls" => [], "sitemaps" => []]); + } // Empty Sitemap - public function test_EmptySitemap_2 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze (" ", "http://example.com"); - $this->assertSame ($res, ["urls" => [], "sitemaps" => []]); - } + public function test_EmptySitemap_2() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze(" ", "http://example.com"); + $this->assertSame($res, ["urls" => [], "sitemaps" => []]); + } // Textual Sitemap - public function test_TextualSitemap_1 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze ("http://example.com", "http://example.com"); - $this->assertSame ($res, - ["urls" => ["http://example.com" => []], - "sitemaps" => []]); - } - public function test_TextualSitemap_2 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze ("http://example.com\nhttps://www.example.com\n\n", - "http://example.com"); - $this->assertSame ($res, - ["urls" => ["http://example.com" => [], "https://www.example.com" => []], - "sitemaps" => []]); - } + public function test_TextualSitemap_1() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze("http://example.com", "http://example.com"); + $this->assertSame( + $res, + ["urls" => ["http://example.com" => []], + "sitemaps" => []] + ); + } + public function test_TextualSitemap_2() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze( + "http://example.com\nhttps://www.example.com\n\n", + "http://example.com" + ); + $this->assertSame( + $res, + ["urls" => ["http://example.com" => [], "https://www.example.com" => []], + "sitemaps" => []] + ); + } // XML Sitemap - public function test_XMLSitemap_1 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze ( -' + public function test_XMLSitemap_1() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze( + ' @@ -64,21 +71,24 @@ class SitemapTest extends \PHPUnit_Framework_TestCase 0.8 ', -"http://example.com"); - $this->assertSame ($res, - ["urls" => [ - "http://example.com/" => ["changefreq" => "daily", + "http://example.com" + ); + $this->assertSame( + $res, + ["urls" => [ + "http://example.com/" => ["changefreq" => "daily", "priority" => 0.8, "lastmod" => 1163808000] - ], - "sitemaps" => []]); - } + ], + "sitemaps" => []] + ); + } - public function test_XMLSitemap_2 () - { - $sitemap = new Sitemap (); - $res = $sitemap->analyze ( -' + public function test_XMLSitemap_2() + { + $sitemap = new Sitemap(); + $res = $sitemap->analyze( + ' http://www.example.com/sitemap1.xml.gz @@ -89,14 +99,17 @@ class SitemapTest extends \PHPUnit_Framework_TestCase 2005-01-01 ', -"http://example.com"); - $this->assertSame ($res, - ["urls" => [], - "sitemaps" => [ - "http://www.example.com/sitemap1.xml.gz" => [ - "lastmod" => 1096654997,], - "http://www.example.com/sitemap2.xml.gz" => [ - "lastmod" => 1104537600, ], - ]]); - } + "http://example.com" + ); + $this->assertSame( + $res, + ["urls" => [], + "sitemaps" => [ + "http://www.example.com/sitemap1.xml.gz" => [ + "lastmod" => 1096654997,], + "http://www.example.com/sitemap2.xml.gz" => [ + "lastmod" => 1104537600, ], + ]] + ); + } } diff --git a/Tests/SpfcheckTest.php b/Tests/SpfcheckTest.php index dd7910b..9d5d3c9 100644 --- a/Tests/SpfcheckTest.php +++ b/Tests/SpfcheckTest.php @@ -1,4 +1,5 @@ @@ -13,256 +14,302 @@ use Domframework\Spfcheck; */ class SpfcheckTest extends \PHPUnit_Framework_TestCase { - public function test_getRecords_NoSPF () - { - $this->expectException ("Exception", - "Can not find a valid SPF TXT entry in DNS for domain ". - "'notfound.tester.fournier38.fr'", 403); - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("notfound.tester.fournier38.fr"); - } + public function test_getRecords_NoSPF() + { + $this->expectException( + "Exception", + "Can not find a valid SPF TXT entry in DNS for domain " . + "'notfound.tester.fournier38.fr'", + 403 + ); + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("notfound.tester.fournier38.fr"); + } - public function test_getRecords_SPFReject () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("reject.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("reject.spf.tester.fournier38.fr" => - array ("-all" => array ()))); - } + public function test_getRecords_SPFReject() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("reject.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("reject.spf.tester.fournier38.fr" => + array ("-all" => array ())) + ); + } - public function test_getRecords_Loop () - { - $this->expectException ("Exception", - "SPFCheck : Too much DNS requests (30 >= 30)", 500); - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("loop.spf.tester.fournier38.fr"); - $this->assertSame ($res, array ()); - } + public function test_getRecords_Loop() + { + $this->expectException( + "Exception", + "SPFCheck : Too much DNS requests (30 >= 30)", + 500 + ); + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("loop.spf.tester.fournier38.fr"); + $this->assertSame($res, array ()); + } - public function test_getRecords_Include_emptyInclude () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("includeempty.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("includeempty.spf.tester.fournier38.fr" => - array ("include:" => array (), "-all" => array ()))); - } + public function test_getRecords_Include_emptyInclude() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("includeempty.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("includeempty.spf.tester.fournier38.fr" => + array ("include:" => array (), "-all" => array ())) + ); + } - public function test_getRecords_Redirect_emptyRedirect () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("redirectempty.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("redirectempty.spf.tester.fournier38.fr" => - array ("redirect=" => array (), "-all" => array ()))); - } + public function test_getRecords_Redirect_emptyRedirect() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("redirectempty.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("redirectempty.spf.tester.fournier38.fr" => + array ("redirect=" => array (), "-all" => array ())) + ); + } - public function test_getRecords_MX_emptyMX () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("mx.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("mx.spf.tester.fournier38.fr" => - array ("mx" => array (), "-all" => array ()))); - } + public function test_getRecords_MX_emptyMX() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("mx.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("mx.spf.tester.fournier38.fr" => + array ("mx" => array (), "-all" => array ())) + ); + } - public function test_getRecords_MX_validMX () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("mxvalid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("mxvalid.spf.tester.fournier38.fr" => array ( - "mx:tester.fournier38.fr" => array ( - "2a01:e0a:2a7:9cd1::103", - "2a01:e0a:392:ab60::206", - "82.64.75.195", - "82.66.67.64"), - "-all" => array ()))); - } + public function test_getRecords_MX_validMX() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("mxvalid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("mxvalid.spf.tester.fournier38.fr" => array ( + "mx:tester.fournier38.fr" => array ( + "2a01:e0a:2a7:9cd1::103", + "2a01:e0a:392:ab60::206", + "82.64.75.195", + "82.66.67.64"), + "-all" => array ())) + ); + } - public function test_getRecords_A_emptyA () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("a.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("a.spf.tester.fournier38.fr" => - array ("a" => array (), "-all" => array ()))); - } + public function test_getRecords_A_emptyA() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("a.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("a.spf.tester.fournier38.fr" => + array ("a" => array (), "-all" => array ())) + ); + } - public function test_getRecords_A_validA () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("avalid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("avalid.spf.tester.fournier38.fr" => array ( - "a:tester.fournier38.fr" => array ( - "2a01:e0a:2a7:9cd1::100", - "82.64.75.195",), - "-all" => array ()))); - } + public function test_getRecords_A_validA() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("avalid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("avalid.spf.tester.fournier38.fr" => array ( + "a:tester.fournier38.fr" => array ( + "2a01:e0a:2a7:9cd1::100", + "82.64.75.195",), + "-all" => array ())) + ); + } - public function test_getRecords_IP4_emptyIP4 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip4empty.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip4empty.spf.tester.fournier38.fr" => array ( - "ip4:" => array (), - "-all" => array ()))); - } + public function test_getRecords_IP4_emptyIP4() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip4empty.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip4empty.spf.tester.fournier38.fr" => array ( + "ip4:" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_IP4_invalidIP4 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip4invalid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip4invalid.spf.tester.fournier38.fr" => array ( - "ip4:0::1" => array (), - "-all" => array ()))); - } + public function test_getRecords_IP4_invalidIP4() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip4invalid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip4invalid.spf.tester.fournier38.fr" => array ( + "ip4:0::1" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_IP4_validIP4 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip4valid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip4valid.spf.tester.fournier38.fr" => array ( - "ip4:192.168.1.1" => array ("192.168.1.1"), - "-all" => array ()))); - } + public function test_getRecords_IP4_validIP4() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip4valid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip4valid.spf.tester.fournier38.fr" => array ( + "ip4:192.168.1.1" => array ("192.168.1.1"), + "-all" => array ())) + ); + } - public function test_getRecords_IP6_emptyIP6 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip6empty.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip6empty.spf.tester.fournier38.fr" => array ( - "ip6:" => array (), - "-all" => array ()))); - } + public function test_getRecords_IP6_emptyIP6() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip6empty.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip6empty.spf.tester.fournier38.fr" => array ( + "ip6:" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_IP6_invalidIP6 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip6invalid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip6invalid.spf.tester.fournier38.fr" => array ( - "ip6:192.168.1.1" => array (), - "-all" => array ()))); - } + public function test_getRecords_IP6_invalidIP6() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip6invalid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip6invalid.spf.tester.fournier38.fr" => array ( + "ip6:192.168.1.1" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_IP6_validIP6 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ip6valid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ip6valid.spf.tester.fournier38.fr" => array ( - "ip6:0::1" => array ("0::1"), - "-all" => array ()))); - } + public function test_getRecords_IP6_validIP6() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ip6valid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ip6valid.spf.tester.fournier38.fr" => array ( + "ip6:0::1" => array ("0::1"), + "-all" => array ())) + ); + } - public function test_getRecords_PTR () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("ptrvalid.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("ptrvalid.spf.tester.fournier38.fr" => array ( - "ptr" => array (), - "-all" => array ()))); - } + public function test_getRecords_PTR() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("ptrvalid.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("ptrvalid.spf.tester.fournier38.fr" => array ( + "ptr" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_All_Multiple () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("allmultiple.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("allmultiple.spf.tester.fournier38.fr" => array ( - "+all" => array (), - "-all" => array ()))); - } + public function test_getRecords_All_Multiple() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("allmultiple.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("allmultiple.spf.tester.fournier38.fr" => array ( + "+all" => array (), + "-all" => array ())) + ); + } - public function test_getRecords_All_NotEnd () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("allnotend.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("allnotend.spf.tester.fournier38.fr" => array ( - "+all" => array (), - "mx" => array ()))); - } + public function test_getRecords_All_NotEnd() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("allnotend.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("allnotend.spf.tester.fournier38.fr" => array ( + "+all" => array (), + "mx" => array ())) + ); + } - public function test_getRecords_All_NotSet () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("allnotset.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("allnotset.spf.tester.fournier38.fr" => array ( - "mx" => array ()))); - } + public function test_getRecords_All_NotSet() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("allnotset.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("allnotset.spf.tester.fournier38.fr" => array ( + "mx" => array ())) + ); + } - public function test_wideIPRange () - { - $spfcheck = new Spfcheck (); - $spfcheck->getRecords ("wide.spf.tester.fournier38.fr"); - $res = $spfcheck->getErrors (); - $this->assertSame ($res, - array ("wide.spf.tester.fournier38.fr" => array ( - "ip4:213.131.32.0/2" => "Invalid ip4 set for domain 'wide.spf.tester.fournier38.fr' : Mask '/2' too wide", - "ip6:2001::/20" => "Invalid ip6 set for domain 'wide.spf.tester.fournier38.fr' : Mask '/20' too wide" - ))); - } + public function test_wideIPRange() + { + $spfcheck = new Spfcheck(); + $spfcheck->getRecords("wide.spf.tester.fournier38.fr"); + $res = $spfcheck->getErrors(); + $this->assertSame( + $res, + array ("wide.spf.tester.fournier38.fr" => array ( + "ip4:213.131.32.0/2" => "Invalid ip4 set for domain 'wide.spf.tester.fournier38.fr' : Mask '/2' too wide", + "ip6:2001::/20" => "Invalid ip6 set for domain 'wide.spf.tester.fournier38.fr' : Mask '/20' too wide" + )) + ); + } - public function test_recordsWithPlus () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("plus.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("plus.spf.tester.fournier38.fr" => array ( - "+a" => array (), - "+mx" => array (), - "+ip4:178.33.236.5" => array ("178.33.236.5"), - "-ip4:137.74.69.64" => array ("137.74.69.64"), - "+ip4:51.254.45.81" => array ("51.254.45.81"), - "-all" => array (), - ))); - } + public function test_recordsWithPlus() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("plus.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("plus.spf.tester.fournier38.fr" => array ( + "+a" => array (), + "+mx" => array (), + "+ip4:178.33.236.5" => array ("178.33.236.5"), + "-ip4:137.74.69.64" => array ("137.74.69.64"), + "+ip4:51.254.45.81" => array ("51.254.45.81"), + "-all" => array (), + )) + ); + } - public function test_getRecords_Unknown () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->getRecords ("unknown.spf.tester.fournier38.fr"); - $this->assertSame ($res, - array ("unknown.spf.tester.fournier38.fr" => array ( - "unknown" => array (), - "-all" => array ()))); - } + public function test_getRecords_Unknown() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->getRecords("unknown.spf.tester.fournier38.fr"); + $this->assertSame( + $res, + array ("unknown.spf.tester.fournier38.fr" => array ( + "unknown" => array (), + "-all" => array ())) + ); + } - public function test_ipCheckToSPF_OK_inA () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->ipCheckToSPF ("plus.spf.tester.fournier38.fr", "178.33.236.5"); - $this->assertSame ($res, "PASS"); - } + public function test_ipCheckToSPF_OK_inA() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->ipCheckToSPF("plus.spf.tester.fournier38.fr", "178.33.236.5"); + $this->assertSame($res, "PASS"); + } - public function test_ipCheckToSPF_FAIL_inALL () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->ipCheckToSPF ("plus.spf.tester.fournier38.fr", "1.3.6.5"); - $this->assertSame ($res, "FAIL"); - } + public function test_ipCheckToSPF_FAIL_inALL() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->ipCheckToSPF("plus.spf.tester.fournier38.fr", "1.3.6.5"); + $this->assertSame($res, "FAIL"); + } - public function test_ipCheckToSPF_OK_inALL () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->ipCheckToSPF ("plus.spf.tester.fournier38.fr", "1.3.6.5"); - $this->assertSame ($res, "FAIL"); - } + public function test_ipCheckToSPF_OK_inALL() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->ipCheckToSPF("plus.spf.tester.fournier38.fr", "1.3.6.5"); + $this->assertSame($res, "FAIL"); + } - public function test_ipCheckToSPF_FAIL_inIP4 () - { - $spfcheck = new Spfcheck (); - $res = $spfcheck->ipCheckToSPF ("plus.spf.tester.fournier38.fr", "137.74.69.64"); - $this->assertSame ($res, "FAIL"); - } + public function test_ipCheckToSPF_FAIL_inIP4() + { + $spfcheck = new Spfcheck(); + $res = $spfcheck->ipCheckToSPF("plus.spf.tester.fournier38.fr", "137.74.69.64"); + $this->assertSame($res, "FAIL"); + } } diff --git a/Tests/SseTest.php b/Tests/SseTest.php index 373a074..03da606 100644 --- a/Tests/SseTest.php +++ b/Tests/SseTest.php @@ -1,4 +1,5 @@ @@ -12,143 +13,156 @@ use Domframework\Sse; /** Test the domframework Server-Sent Events part */ class SseTest extends \PHPUnit_Framework_TestCase { - public function test_loop_NOTDEFINED () - { - $this->expectException ("Exception"); - $sse = new Sse (); - $res = $sse->loop (); - } + public function test_loop_NOTDEFINED() + { + $this->expectException("Exception"); + $sse = new Sse(); + $res = $sse->loop(); + } - public function test_loop_JUSTPING () - { - $this->expectOutputString(str_repeat (": ping\n\n", 5)); - $sse = new Sse (); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - $sse->setBackendFiles ("/tmp/dfwTestSSE1") + public function test_loop_JUSTPING() + { + $this->expectOutputString(str_repeat(": ping\n\n", 5)); + $sse = new Sse(); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + $sse->setBackendFiles("/tmp/dfwTestSSE1") ->setPingTime(1); - $sse->loop (); - } + $sse->loop(); + } - public function test_loop_SKIP_START () - { - $this->expectOutputString(str_repeat (": ping\n\n", 5)); - $sse = new Sse (); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - file_put_contents ("/tmp/dfwTestSSE1", "NOT SEEN"); - $sse->setBackendFiles ("/tmp/dfwTestSSE1") + public function test_loop_SKIP_START() + { + $this->expectOutputString(str_repeat(": ping\n\n", 5)); + $sse = new Sse(); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + file_put_contents("/tmp/dfwTestSSE1", "NOT SEEN"); + $sse->setBackendFiles("/tmp/dfwTestSSE1") ->setPingTime(1); - $sse->loop (); - } + $sse->loop(); + } - public function test_loop_DATA () - { - $this->expectOutputString(str_repeat (": ping\n\n", 4). - "data: WILL BE SEEN\n\n: ping\n\n"); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - $sse = new Sse (); - pcntl_signal(SIGALRM, function () { - file_put_contents ("/tmp/dfwTestSSE1", "WILL BE SEEN\n"); - }, false); - pcntl_alarm(3); - $sse->setBackendFiles ("/tmp/dfwTestSSE1") + public function test_loop_DATA() + { + $this->expectOutputString(str_repeat(": ping\n\n", 4) . + "data: WILL BE SEEN\n\n: ping\n\n"); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + $sse = new Sse(); + pcntl_signal(SIGALRM, function () { + file_put_contents("/tmp/dfwTestSSE1", "WILL BE SEEN\n"); + }, false); + pcntl_alarm(3); + $sse->setBackendFiles("/tmp/dfwTestSSE1") ->setPingTime(1); - $sse->loop (); - } + $sse->loop(); + } - public function test_loop_EVENTS () - { - $this->expectOutputString(str_repeat (": ping\n\n", 4). - "event: event1\ndata: WILL BE SEEN 1\n\n". - "event: event2\ndata: WILL BE SEEN 2\n\n". - ": ping\n\n"); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - if (file_exists ("/tmp/dfwTestSSE2")) - unlink ("/tmp/dfwTestSSE2"); - $sse = new Sse (); - pcntl_signal(SIGALRM, function () { - file_put_contents ("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); - file_put_contents ("/tmp/dfwTestSSE2", "WILL BE SEEN 2\n"); - }, false); - pcntl_alarm(3); - $sse->setBackendFiles (["event1" => "/tmp/dfwTestSSE1", + public function test_loop_EVENTS() + { + $this->expectOutputString(str_repeat(": ping\n\n", 4) . + "event: event1\ndata: WILL BE SEEN 1\n\n" . + "event: event2\ndata: WILL BE SEEN 2\n\n" . + ": ping\n\n"); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + if (file_exists("/tmp/dfwTestSSE2")) { + unlink("/tmp/dfwTestSSE2"); + } + $sse = new Sse(); + pcntl_signal(SIGALRM, function () { + file_put_contents("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); + file_put_contents("/tmp/dfwTestSSE2", "WILL BE SEEN 2\n"); + }, false); + pcntl_alarm(3); + $sse->setBackendFiles(["event1" => "/tmp/dfwTestSSE1", "event2" => "/tmp/dfwTestSSE2"]) ->setPingTime(1); - $sse->loop (); - } - - public function test_loop_HandlersEvent () - { - $this->expectOutputString(str_repeat (": ping\n\n", 4). - "event: event1\ndata: will be seen 1\n\n". - "event: event2\ndata: WILL BE SEEN 2\n\n". - ": ping\n\n"); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - if (file_exists ("/tmp/dfwTestSSE2")) - unlink ("/tmp/dfwTestSSE2"); - $sse = new Sse (); - pcntl_signal(SIGALRM, function () { - file_put_contents ("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); - file_put_contents ("/tmp/dfwTestSSE2", "WILL BE SEEN 2\n"); - }, false); - pcntl_alarm(3); - function lowerHandlersEvent ($val) { - return strtolower ($val); + $sse->loop(); } - $sse->setBackendFiles (["event1" => "/tmp/dfwTestSSE1", + + public function test_loop_HandlersEvent() + { + $this->expectOutputString(str_repeat(": ping\n\n", 4) . + "event: event1\ndata: will be seen 1\n\n" . + "event: event2\ndata: WILL BE SEEN 2\n\n" . + ": ping\n\n"); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + if (file_exists("/tmp/dfwTestSSE2")) { + unlink("/tmp/dfwTestSSE2"); + } + $sse = new Sse(); + pcntl_signal(SIGALRM, function () { + file_put_contents("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); + file_put_contents("/tmp/dfwTestSSE2", "WILL BE SEEN 2\n"); + }, false); + pcntl_alarm(3); + function lowerHandlersEvent($val) + { + return strtolower($val); + } + $sse->setBackendFiles(["event1" => "/tmp/dfwTestSSE1", "event2" => "/tmp/dfwTestSSE2"]) - ->setHandlersEvent ([ - "event1" => __NAMESPACE__."\\lowerHandlersEvent"]) + ->setHandlersEvent([ + "event1" => __NAMESPACE__ . "\\lowerHandlersEvent"]) ->setPingTime(1); - $sse->loop (); - } - - public function test_loop_HandlerDataonly () - { - $this->expectOutputString(str_repeat (": ping\n\n", 4). - "data: will be seen 1\n\n". - ": ping\n\n"); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - $sse = new Sse (); - pcntl_signal(SIGALRM, function () { - file_put_contents ("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); - }, false); - pcntl_alarm(3); - function lowerHandlerDataonly ($val) { - return strtolower ($val); + $sse->loop(); } - $sse->setBackendFiles ("/tmp/dfwTestSSE1") - ->setHandlerDataonly (__NAMESPACE__."\\lowerHandlerDataonly") - ->setPingTime(1); - $sse->loop (); - } - public function test_loop_HandlerDataonlyWithParams () - { - $this->expectOutputString(str_repeat (": ping\n\n", 4). - "data: PREwill be seen 1POST\n\n". - ": ping\n\n"); - if (file_exists ("/tmp/dfwTestSSE1")) - unlink ("/tmp/dfwTestSSE1"); - $sse = new Sse (); - pcntl_signal(SIGALRM, function () { - file_put_contents ("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); - }, false); - pcntl_alarm(3); - function lowerHandlerDataonlyWithParams ($val, $param1, $param2) { - return $param1.strtolower ($val).$param2; - } - $sse->setBackendFiles ("/tmp/dfwTestSSE1") - ->setHandlerDataonly ( - __NAMESPACE__."\\lowerHandlerDataonlyWithParams", "PRE", "POST") + public function test_loop_HandlerDataonly() + { + $this->expectOutputString(str_repeat(": ping\n\n", 4) . + "data: will be seen 1\n\n" . + ": ping\n\n"); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + $sse = new Sse(); + pcntl_signal(SIGALRM, function () { + file_put_contents("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); + }, false); + pcntl_alarm(3); + function lowerHandlerDataonly($val) + { + return strtolower($val); + } + $sse->setBackendFiles("/tmp/dfwTestSSE1") + ->setHandlerDataonly(__NAMESPACE__ . "\\lowerHandlerDataonly") ->setPingTime(1); - $sse->loop (); - } + $sse->loop(); + } + + public function test_loop_HandlerDataonlyWithParams() + { + $this->expectOutputString(str_repeat(": ping\n\n", 4) . + "data: PREwill be seen 1POST\n\n" . + ": ping\n\n"); + if (file_exists("/tmp/dfwTestSSE1")) { + unlink("/tmp/dfwTestSSE1"); + } + $sse = new Sse(); + pcntl_signal(SIGALRM, function () { + file_put_contents("/tmp/dfwTestSSE1", "WILL BE SEEN 1\n"); + }, false); + pcntl_alarm(3); + function lowerHandlerDataonlyWithParams($val, $param1, $param2) + { + return $param1 . strtolower($val) . $param2; + } + $sse->setBackendFiles("/tmp/dfwTestSSE1") + ->setHandlerDataonly( + __NAMESPACE__ . "\\lowerHandlerDataonlyWithParams", + "PRE", + "POST" + ) + ->setPingTime(1); + $sse->loop(); + } } - - diff --git a/Tests/TcpclientTest.php b/Tests/TcpclientTest.php index 5048cdb..12607f8 100644 --- a/Tests/TcpclientTest.php +++ b/Tests/TcpclientTest.php @@ -1,4 +1,5 @@ @@ -10,72 +11,76 @@ namespace Domframework\Tests; use Domframework\Tcpclient; /** Test the TCP client */ -class TcpclientTest extends \PHPUnit_Framework_TestCase +class TcpclientTest extends \PHPUnit_Framework_TestCase { - public function test_GoogleIPv4 () - { - $tcpclient = new Tcpclient ("www.google.fr", 80); - $tcpclient->preferIPv4 (true); - $tcpclient->connect (); - $tcpclient->send ("GET / HTTP/1.1\r\n". - "Host: www.google.fr\r\n". - "User-Agent: DomFramework\r\n". - "Accept: *"."/*\r\n". - "\r\n"); - $res = ""; - while (($read = $tcpclient->read ()) !== "") - $res .= $read."\r\n"; - $tcpclient->disconnect (); - $this->assertSame (substr ($res, 0, 15), "HTTP/1.1 200 OK"); - } + public function test_GoogleIPv4() + { + $tcpclient = new Tcpclient("www.google.fr", 80); + $tcpclient->preferIPv4(true); + $tcpclient->connect(); + $tcpclient->send("GET / HTTP/1.1\r\n" . + "Host: www.google.fr\r\n" . + "User-Agent: DomFramework\r\n" . + "Accept: *" . "/*\r\n" . + "\r\n"); + $res = ""; + while (($read = $tcpclient->read()) !== "") { + $res .= $read . "\r\n"; + } + $tcpclient->disconnect(); + $this->assertSame(substr($res, 0, 15), "HTTP/1.1 200 OK"); + } - public function test_GoogleIPv4orIpv6 () - { - $tcpclient = new Tcpclient ("www.google.fr", 80); - $tcpclient->connect (); - $tcpclient->send ("GET / HTTP/1.1\r\n". - "Host: www.google.fr\r\n". - "User-Agent: DomFramework\r\n". - "Accept: *"."/*\r\n". - "\r\n"); - $res = ""; - while (($read = $tcpclient->read ()) !== "") - $res .= $read."\r\n"; - $tcpclient->disconnect (); - $this->assertSame (substr ($res, 0, 15), "HTTP/1.1 200 OK"); - } + public function test_GoogleIPv4orIpv6() + { + $tcpclient = new Tcpclient("www.google.fr", 80); + $tcpclient->connect(); + $tcpclient->send("GET / HTTP/1.1\r\n" . + "Host: www.google.fr\r\n" . + "User-Agent: DomFramework\r\n" . + "Accept: *" . "/*\r\n" . + "\r\n"); + $res = ""; + while (($read = $tcpclient->read()) !== "") { + $res .= $read . "\r\n"; + } + $tcpclient->disconnect(); + $this->assertSame(substr($res, 0, 15), "HTTP/1.1 200 OK"); + } - public function test_GoogleSSL () - { - $tcpclient = new Tcpclient ("www.google.fr", 443); - $tcpclient->connect (); - $tcpclient->cryptoEnable (true); - $tcpclient->send ("GET / HTTP/1.1\r\n". - "Host: www.google.fr\r\n". - "User-Agent: DomFramework\r\n". - "Accept: *"."/*\r\n". - "\r\n"); - $res = ""; - while (($read = $tcpclient->read ()) !== "") - $res .= $read."\r\n"; - $tcpclient->disconnect (); - $this->assertSame (substr ($res, 0, 15), "HTTP/1.1 200 OK"); - } + public function test_GoogleSSL() + { + $tcpclient = new Tcpclient("www.google.fr", 443); + $tcpclient->connect(); + $tcpclient->cryptoEnable(true); + $tcpclient->send("GET / HTTP/1.1\r\n" . + "Host: www.google.fr\r\n" . + "User-Agent: DomFramework\r\n" . + "Accept: *" . "/*\r\n" . + "\r\n"); + $res = ""; + while (($read = $tcpclient->read()) !== "") { + $res .= $read . "\r\n"; + } + $tcpclient->disconnect(); + $this->assertSame(substr($res, 0, 15), "HTTP/1.1 200 OK"); + } - public function test_GoogleSSLIPv6 () - { - $tcpclient = new Tcpclient ("ipv6.google.com", 443); - $tcpclient->connect (); - $tcpclient->cryptoEnable (true); - $tcpclient->send ("GET / HTTP/1.1\r\n". - "Host: www.google.fr\r\n". - "User-Agent: DomFramework\r\n". - "Accept: *"."/*\r\n". - "\r\n"); - $res = ""; - while (($read = $tcpclient->read ()) !== "") - $res .= $read."\r\n"; - $tcpclient->disconnect (); - $this->assertSame (substr ($res, 0, 15), "HTTP/1.1 200 OK"); - } + public function test_GoogleSSLIPv6() + { + $tcpclient = new Tcpclient("ipv6.google.com", 443); + $tcpclient->connect(); + $tcpclient->cryptoEnable(true); + $tcpclient->send("GET / HTTP/1.1\r\n" . + "Host: www.google.fr\r\n" . + "User-Agent: DomFramework\r\n" . + "Accept: *" . "/*\r\n" . + "\r\n"); + $res = ""; + while (($read = $tcpclient->read()) !== "") { + $res .= $read . "\r\n"; + } + $tcpclient->disconnect(); + $this->assertSame(substr($res, 0, 15), "HTTP/1.1 200 OK"); + } } diff --git a/Tests/UserssqlTest.php b/Tests/UserssqlTest.php index 6999089..d11c19a 100644 --- a/Tests/UserssqlTest.php +++ b/Tests/UserssqlTest.php @@ -1,4 +1,5 @@ @@ -12,118 +13,122 @@ use Domframework\Userssql; /** Test the Userssql.php file */ class UserssqlTest extends \PHPUnit_Framework_TestCase { - public function test_clean () - { - @unlink ("/tmp/database.db"); - } + public function test_clean() + { + @unlink("/tmp/database.db"); + } - public function test_initStorage () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->initStorage (); - $this->assertSame ($res, 0); - } + public function test_initStorage() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->initStorage(); + $this->assertSame($res, 0); + } - public function test_listusers1 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->listusers (); - $this->assertSame ($res, array ()); - } + public function test_listusers1() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->listusers(); + $this->assertSame($res, array ()); + } - public function test_adduser1 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->adduser ("toto@toto.com", "Toto", "Toto2"); - $this->assertSame ($res, "toto@toto.com"); - } + public function test_adduser1() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->adduser("toto@toto.com", "Toto", "Toto2"); + $this->assertSame($res, "toto@toto.com"); + } - public function test_listusers2 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->listusers (); - $this->assertSame ($res, array (array ("email"=>"toto@toto.com", - "firstname"=>"Toto", - "lastname"=>"Toto2"))); - } + public function test_listusers2() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->listusers(); + $this->assertSame($res, array (array ("email" => "toto@toto.com", + "firstname" => "Toto", + "lastname" => "Toto2"))); + } - public function test_overwritepassword1 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->overwritepassword ("toto@toto.com", "PassW0rd"); - $this->assertSame ($res, 1); - } + public function test_overwritepassword1() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->overwritepassword("toto@toto.com", "PassW0rd"); + $this->assertSame($res, 1); + } - public function test_checkValidPassword1 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->checkValidPassword ("toto@toto.com", "PassW0rd"); - $this->assertSame ($res, true); - } + public function test_checkValidPassword1() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->checkValidPassword("toto@toto.com", "PassW0rd"); + $this->assertSame($res, true); + } - public function test_checkValidPassword2 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->checkValidPassword ("toto@toto.com", "BAD PASSWD"); - $this->assertSame ($res, false); - } + public function test_checkValidPassword2() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->checkValidPassword("toto@toto.com", "BAD PASSWD"); + $this->assertSame($res, false); + } - public function test_changepassword1 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->changepassword ("toto@toto.com", "PassW0rd", "NEW PASS!"); - $this->assertSame ($res, 1); - } + public function test_changepassword1() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->changepassword("toto@toto.com", "PassW0rd", "NEW PASS!"); + $this->assertSame($res, 1); + } - public function test_checkValidPassword3 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->checkValidPassword ("toto@toto.com", "PassW0rd"); - $this->assertSame ($res, false); - } + public function test_checkValidPassword3() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->checkValidPassword("toto@toto.com", "PassW0rd"); + $this->assertSame($res, false); + } - public function test_checkValidPassword4 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->checkValidPassword ("toto@toto.com", "NEW PASS!"); - $this->assertSame ($res, true); - } + public function test_checkValidPassword4() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->checkValidPassword("toto@toto.com", "NEW PASS!"); + $this->assertSame($res, true); + } - public function test_updateuser () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->updateuser ("toto@toto.com", "titi@titi.com", "titi", - "titi2"); - $this->assertSame ($res, 1); - } + public function test_updateuser() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->updateuser( + "toto@toto.com", + "titi@titi.com", + "titi", + "titi2" + ); + $this->assertSame($res, 1); + } - public function test_listusers3 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->listusers (); - $this->assertSame ($res, array (array ("email"=>"titi@titi.com", - "firstname"=>"titi", - "lastname"=>"titi2"))); - } + public function test_listusers3() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->listusers(); + $this->assertSame($res, array (array ("email" => "titi@titi.com", + "firstname" => "titi", + "lastname" => "titi2"))); + } - public function test_checkValidPassword5 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->checkValidPassword ("titi@titi.com", "NEW PASS!"); - $this->assertSame ($res, true); - } + public function test_checkValidPassword5() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->checkValidPassword("titi@titi.com", "NEW PASS!"); + $this->assertSame($res, true); + } - public function test_deluser () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->deluser ("titi@titi.com"); - $this->assertSame ($res, 1); - } + public function test_deluser() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->deluser("titi@titi.com"); + $this->assertSame($res, 1); + } - public function test_listusers4 () - { - $userssql = new Userssql ("sqlite:///tmp/database.db"); - $res = $userssql->listusers (); - $this->assertSame ($res, array ()); - } + public function test_listusers4() + { + $userssql = new Userssql("sqlite:///tmp/database.db"); + $res = $userssql->listusers(); + $this->assertSame($res, array ()); + } } diff --git a/Tests/UuidTest.php b/Tests/UuidTest.php index 1924fbe..4ac25b7 100644 --- a/Tests/UuidTest.php +++ b/Tests/UuidTest.php @@ -1,4 +1,5 @@ @@ -12,16 +13,16 @@ use Domframework\Uuid; /** Test the Uuid.php file */ class UuidTest extends \PHPUnit_Framework_TestCase { - public function test_uuid1 () - { - $res = Uuid::uuid4 (); - $this->assertRegExp (36, strlen ($res)); - } + public function test_uuid1() + { + $res = Uuid::uuid4(); + $this->assertRegExp(36, strlen($res)); + } - public function test_uuid2 () - { - $res = Uuid::uuid4 (); - $this->assertRegExp (true, strspn ("0123456789abcdef-", $res) == - strlen ($res)); - } + public function test_uuid2() + { + $res = Uuid::uuid4(); + $this->assertRegExp(true, strspn("0123456789abcdef-", $res) == + strlen($res)); + } } diff --git a/Tests/VerifyTest.php b/Tests/VerifyTest.php index f228823..2930ee7 100644 --- a/Tests/VerifyTest.php +++ b/Tests/VerifyTest.php @@ -1,4 +1,5 @@ @@ -15,99 +16,99 @@ class VerifyTest extends \PHPUnit_Framework_TestCase /////////////// // DATES // /////////////// - public function test_is_datetimeSQL1 () - { - $verify = new Verify (); - $res = $verify->is_datetimeSQL ("2017-04-13 22:55:17"); - $this->assertSame ($res, true); - } + public function test_is_datetimeSQL1() + { + $verify = new Verify(); + $res = $verify->is_datetimeSQL("2017-04-13 22:55:17"); + $this->assertSame($res, true); + } - public function test_is_datetimeSQL2 () - { - $verify = new Verify (); - $res = $verify->is_datetimeSQL ("2017-13-55 22:55:17"); - $this->assertSame ($res, false); - } + public function test_is_datetimeSQL2() + { + $verify = new Verify(); + $res = $verify->is_datetimeSQL("2017-13-55 22:55:17"); + $this->assertSame($res, false); + } - public function test_staticIs_datetimeSQL1 () - { - $res = Verify::staticIs_datetimeSQL ("2017-04-13 22:55:17"); - $this->assertSame ($res, true); - } + public function test_staticIs_datetimeSQL1() + { + $res = Verify::staticIs_datetimeSQL("2017-04-13 22:55:17"); + $this->assertSame($res, true); + } - public function test_staticIs_datetimeSQL2 () - { - $res = Verify::staticIs_datetimeSQL ("2017-13-55 22:55:17"); - $this->assertSame ($res, false); - } - public function test_is_dateSQL1 () - { - $verify = new Verify (); - $res = $verify->is_dateSQL ("2017-04-13"); - $this->assertSame ($res, true); - } + public function test_staticIs_datetimeSQL2() + { + $res = Verify::staticIs_datetimeSQL("2017-13-55 22:55:17"); + $this->assertSame($res, false); + } + public function test_is_dateSQL1() + { + $verify = new Verify(); + $res = $verify->is_dateSQL("2017-04-13"); + $this->assertSame($res, true); + } - public function test_is_dateSQL2 () - { - $verify = new Verify (); - $res = $verify->is_dateSQL ("2017-13-55"); - $this->assertSame ($res, false); - } + public function test_is_dateSQL2() + { + $verify = new Verify(); + $res = $verify->is_dateSQL("2017-13-55"); + $this->assertSame($res, false); + } - public function test_staticIs_dateSQL1 () - { - $res = Verify::staticIs_dateSQL ("2017-04-13"); - $this->assertSame ($res, true); - } + public function test_staticIs_dateSQL1() + { + $res = Verify::staticIs_dateSQL("2017-04-13"); + $this->assertSame($res, true); + } - public function test_staticIs_dateSQL2 () - { - $res = Verify::staticIs_dateSQL ("2017-13-55"); - $this->assertSame ($res, false); - } + public function test_staticIs_dateSQL2() + { + $res = Verify::staticIs_dateSQL("2017-13-55"); + $this->assertSame($res, false); + } ///////////////// // STRINGS // ///////////////// - public function test_staticIsAllowedChars_1 () - { - $res = Verify::staticIsAllowedChars ("éléphant", "abcd"); - $this->assertSame ($res, false); - } + public function test_staticIsAllowedChars_1() + { + $res = Verify::staticIsAllowedChars("éléphant", "abcd"); + $this->assertSame($res, false); + } - public function test_staticIsAllowedChars_2 () - { - $res = Verify::staticIsAllowedChars ("éléphant", "anhplté"); - $this->assertSame ($res, true); - } + public function test_staticIsAllowedChars_2() + { + $res = Verify::staticIsAllowedChars("éléphant", "anhplté"); + $this->assertSame($res, true); + } ///////////////// // NUMBERS // ///////////////// - public function test_staticIs_integer1 () - { - $res = Verify::staticIs_integer ("2017-04-13 22:55:17"); - $this->assertSame ($res, false); - } + public function test_staticIs_integer1() + { + $res = Verify::staticIs_integer("2017-04-13 22:55:17"); + $this->assertSame($res, false); + } - public function test_staticIs_integer2 () - { - $res = Verify::staticIs_integer ("01234"); - $this->assertSame ($res, true); - } + public function test_staticIs_integer2() + { + $res = Verify::staticIs_integer("01234"); + $this->assertSame($res, true); + } - public function test_staticIs_integer3 () - { - $res = Verify::staticIs_integer ("0x1234"); - $this->assertSame ($res, false); - } + public function test_staticIs_integer3() + { + $res = Verify::staticIs_integer("0x1234"); + $this->assertSame($res, false); + } - public function test_staticIs_integer4 () - { - $res = Verify::staticIs_integer (""); - $this->assertSame ($res, false); - } + public function test_staticIs_integer4() + { + $res = Verify::staticIs_integer(""); + $this->assertSame($res, false); + } //////////////// // EMAILS // @@ -116,71 +117,71 @@ class VerifyTest extends \PHPUnit_Framework_TestCase ///////////// // URL // ///////////// - public function test_is_url1 () - { - $verify = new Verify (); - $res = $verify->is_url ("invalid"); - $this->assertsame ($res, false); - } + public function test_is_url1() + { + $verify = new Verify(); + $res = $verify->is_url("invalid"); + $this->assertsame($res, false); + } - public function test_is_url2 () - { - $verify = new Verify (); - $res = $verify->is_url ("http://valid"); - $this->assertsame ($res, true); - } + public function test_is_url2() + { + $verify = new Verify(); + $res = $verify->is_url("http://valid"); + $this->assertsame($res, true); + } - public function test_staticIs_url1 () - { - $res = Verify::staticIs_url ("invalid"); - $this->assertsame ($res, false); - } + public function test_staticIs_url1() + { + $res = Verify::staticIs_url("invalid"); + $this->assertsame($res, false); + } - public function test_staticIs_url2 () - { - $res = Verify::staticIs_url ("http://valid"); - $this->assertsame ($res, true); - } + public function test_staticIs_url2() + { + $res = Verify::staticIs_url("http://valid"); + $this->assertsame($res, true); + } //////////////// // OTHERS // //////////////// - public function test_is_UUID1 () - { - $verify = new Verify (); - $res = $verify->is_UUID ("ca39275f-9224-425f-ba94-efce2aa5b52c"); - $this->assertsame ($res, true); - } + public function test_is_UUID1() + { + $verify = new Verify(); + $res = $verify->is_UUID("ca39275f-9224-425f-ba94-efce2aa5b52c"); + $this->assertsame($res, true); + } - public function test_is_UUID2 () - { - $verify = new Verify (); - $res = $verify->is_UUID ("zz39275f-9224-425f-ba94-efce2aa5b52c"); - $this->assertsame ($res, false); - } + public function test_is_UUID2() + { + $verify = new Verify(); + $res = $verify->is_UUID("zz39275f-9224-425f-ba94-efce2aa5b52c"); + $this->assertsame($res, false); + } - public function test_is_UUID3 () - { - $verify = new Verify (); - $res = $verify->is_UUID ("2c"); - $this->assertsame ($res, false); - } + public function test_is_UUID3() + { + $verify = new Verify(); + $res = $verify->is_UUID("2c"); + $this->assertsame($res, false); + } - public function test_staticis_UUID1 () - { - $res = Verify::staticis_UUID ("ca39275f-9224-425f-ba94-efce2aa5b52c"); - $this->assertsame ($res, true); - } + public function test_staticis_UUID1() + { + $res = Verify::staticis_UUID("ca39275f-9224-425f-ba94-efce2aa5b52c"); + $this->assertsame($res, true); + } - public function test_staticis_UUID2 () - { - $res = Verify::staticis_UUID ("zz39275f-9224-425f-ba94-efce2aa5b52c"); - $this->assertsame ($res, false); - } + public function test_staticis_UUID2() + { + $res = Verify::staticis_UUID("zz39275f-9224-425f-ba94-efce2aa5b52c"); + $this->assertsame($res, false); + } - public function test_staticis_UUID3 () - { - $res = Verify::staticis_UUID ("2c"); - $this->assertsame ($res, false); - } + public function test_staticis_UUID3() + { + $res = Verify::staticis_UUID("2c"); + $this->assertsame($res, false); + } } diff --git a/Tests/XdiffTest.php b/Tests/XdiffTest.php index ff08caa..f572579 100644 --- a/Tests/XdiffTest.php +++ b/Tests/XdiffTest.php @@ -1,4 +1,5 @@ @@ -14,7 +15,7 @@ class xdiffTest extends \PHPUnit_Framework_TestCase { // Declaration of $string1 and $string2 // {{{ - private $string1 = "This part of the + private $string1 = "This part of the document has stayed the same from version to version. It shouldn't @@ -39,7 +40,7 @@ this paragraph needs to be changed. Things can be added after it. "; - private $string2 = "This is an important + private $string2 = "This is an important notice! It should therefore be located at the beginning of this @@ -71,12 +72,12 @@ to this document. "; // }}} - public function test_diff_normal_1 () - { - // Mode normal - $xdiff = new Xdiff (); - $res = $xdiff->diff ($this->string1, $this->string2); - $this->assertSame ($res, "0a1,6 + public function test_diff_normal_1() + { + // Mode normal + $xdiff = new Xdiff(); + $res = $xdiff->diff($this->string1, $this->string2); + $this->assertSame($res, "0a1,6 > This is an important > notice! It should > therefore be located at @@ -99,14 +100,14 @@ to this document. > important new additions > to this document. "); - } + } - public function test_diff_normal_2 () - { - // Mode normal - $xdiff = new Xdiff (); - $res = $xdiff->diff ("NEWLINE\n".$this->string1, $this->string2); - $this->assertSame ($res, "1c1,6 + public function test_diff_normal_2() + { + // Mode normal + $xdiff = new Xdiff(); + $res = $xdiff->diff("NEWLINE\n" . $this->string1, $this->string2); + $this->assertSame($res, "1c1,6 < NEWLINE --- > This is an important @@ -131,64 +132,64 @@ to this document. > important new additions > to this document. "); - } + } - public function test_diff_normal_3 () - { - // Mode normal - $xdiff = new Xdiff (); - $res = $xdiff->diff ("NEWLINE\n", "\n"); - $this->assertSame ($res, "1c1 + public function test_diff_normal_3() + { + // Mode normal + $xdiff = new Xdiff(); + $res = $xdiff->diff("NEWLINE\n", "\n"); + $this->assertSame($res, "1c1 < NEWLINE --- > "); - } + } - public function test_diff_normal_4 () - { - // Mode normal - $xdiff = new Xdiff (); - $res = $xdiff->diff ("\n", "NEWLINE\n"); - $this->assertSame ($res, "1c1 + public function test_diff_normal_4() + { + // Mode normal + $xdiff = new Xdiff(); + $res = $xdiff->diff("\n", "NEWLINE\n"); + $this->assertSame($res, "1c1 < --- > NEWLINE "); - } + } - public function test_diff_normal_5 () - { - $xdiff = new Xdiff (); - $res = $xdiff->diff ("\n", "\n"); - $this->assertSame ($res, ""); - } + public function test_diff_normal_5() + { + $xdiff = new Xdiff(); + $res = $xdiff->diff("\n", "\n"); + $this->assertSame($res, ""); + } - public function test_diff_normal_6 () - { - $xdiff = new Xdiff (); - $res = $xdiff->diff ("\n", ""); - $this->assertSame ($res, "1d0 + public function test_diff_normal_6() + { + $xdiff = new Xdiff(); + $res = $xdiff->diff("\n", ""); + $this->assertSame($res, "1d0 < \n"); - } + } - public function test_diff_normal_7 () - { - $xdiff = new Xdiff (); - $res = $xdiff->diff ("", "\n"); - $this->assertSame ($res, "0a1 + public function test_diff_normal_7() + { + $xdiff = new Xdiff(); + $res = $xdiff->diff("", "\n"); + $this->assertSame($res, "0a1 > \n"); - } + } - public function test_diff_unified_1 () - { - // Mode unified - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ($this->string1, $this->string2); - $date = date ("Y-m-d H:i:s.u00"); - // DST must answer +0200 in winter and +0100 in summer - $dst = date ("O"); - $this->assertSame ($res, "--- Original ${date}0 $dst + public function test_diff_unified_1() + { + // Mode unified + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff($this->string1, $this->string2); + $date = date("Y-m-d H:i:s.u00"); + // DST must answer +0200 in winter and +0100 in summer + $dst = date("O"); + $this->assertSame($res, "--- Original ${date}0 $dst +++ New ${date}1 $dst @@ -0,0 +1,6 @@ +This is an important @@ -212,15 +213,15 @@ to this document. +important new additions +to this document. "); - } + } - public function test_diff_unified_2 () - { - // Mode unified - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("NEWLINE\n".$this->string1, $this->string2); - $this->assertSame ($res, "--- Original ".date ("Y-m-d H:i:s.u000 O")." -+++ New ".date ("Y-m-d H:i:s.u001 O")." + public function test_diff_unified_2() + { + // Mode unified + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("NEWLINE\n" . $this->string1, $this->string2); + $this->assertSame($res, "--- Original " . date("Y-m-d H:i:s.u000 O") . " ++++ New " . date("Y-m-d H:i:s.u001 O") . " @@ -1 +1,6 @@ -NEWLINE +This is an important @@ -244,67 +245,67 @@ to this document. +important new additions +to this document. "); - } + } - public function test_diff_unified_3 () - { - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("NEWLINE\n", "\n"); - $this->assertSame ($res, "--- Original ".date ("Y-m-d H:i:s.u000 O")." -+++ New ".date ("Y-m-d H:i:s.u001 O")." + public function test_diff_unified_3() + { + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("NEWLINE\n", "\n"); + $this->assertSame($res, "--- Original " . date("Y-m-d H:i:s.u000 O") . " ++++ New " . date("Y-m-d H:i:s.u001 O") . " @@ -1 +1 @@ -NEWLINE + "); - } + } - public function test_diff_unified_4 () - { - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("\n", "NEWLINE\n"); - $this->assertSame ($res, "--- Original ".date ("Y-m-d H:i:s.u000 O")." -+++ New ".date ("Y-m-d H:i:s.u001 O")." + public function test_diff_unified_4() + { + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("\n", "NEWLINE\n"); + $this->assertSame($res, "--- Original " . date("Y-m-d H:i:s.u000 O") . " ++++ New " . date("Y-m-d H:i:s.u001 O") . " @@ -1 +1 @@ - +NEWLINE "); - } + } - public function test_diff_unified_5 () - { - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("\n", "\n"); - $this->assertSame ($res, ""); - } + public function test_diff_unified_5() + { + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("\n", "\n"); + $this->assertSame($res, ""); + } - public function test_diff_unified_6 () - { - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("\n", ""); - $this->assertSame ($res, "--- Original ".date ("Y-m-d H:i:s.u000 O")." -+++ New ".date ("Y-m-d H:i:s.u001 O")." + public function test_diff_unified_6() + { + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("\n", ""); + $this->assertSame($res, "--- Original " . date("Y-m-d H:i:s.u000 O") . " ++++ New " . date("Y-m-d H:i:s.u001 O") . " @@ -1 +0,0 @@ -\n"); - } + } - public function test_diff_unified_7 () - { - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diff ("", "\n"); - $this->assertSame ($res, "--- Original ".date ("Y-m-d H:i:s.u000 O")." -+++ New ".date ("Y-m-d H:i:s.u001 O")." + public function test_diff_unified_7() + { + $xdiff = new Xdiff("unified"); + $res = $xdiff->diff("", "\n"); + $this->assertSame($res, "--- Original " . date("Y-m-d H:i:s.u000 O") . " ++++ New " . date("Y-m-d H:i:s.u001 O") . " @@ -0,0 +1 @@ +\n"); - } + } - public function test_diffFile_unified_1 () - { - file_put_contents ("/tmp/test_xdiff1", $this->string1); - file_put_contents ("/tmp/test_xdiff2", $this->string2); - $xdiff = new Xdiff ("unified"); - $res = $xdiff->diffFile ("/tmp/test_xdiff1", "/tmp/test_xdiff2"); - $this->assertSame ($res, "--- /tmp/test_xdiff1 ".date ("Y-m-d H:i:s.u000 O")." -+++ /tmp/test_xdiff2 ".date ("Y-m-d H:i:s.u001 O")." + public function test_diffFile_unified_1() + { + file_put_contents("/tmp/test_xdiff1", $this->string1); + file_put_contents("/tmp/test_xdiff2", $this->string2); + $xdiff = new Xdiff("unified"); + $res = $xdiff->diffFile("/tmp/test_xdiff1", "/tmp/test_xdiff2"); + $this->assertSame($res, "--- /tmp/test_xdiff1 " . date("Y-m-d H:i:s.u000 O") . " ++++ /tmp/test_xdiff2 " . date("Y-m-d H:i:s.u001 O") . " @@ -0,0 +1,6 @@ +This is an important +notice! It should @@ -327,31 +328,31 @@ to this document. +important new additions +to this document. "); + } - } + public function test_diffFile_unified_2() + { + $xdiff = new Xdiff("unified"); + $this->setExpectedException(); + $res = $xdiff->diffFile("/tmp/test_xdiffNOTEXISTS", "/tmp/test_xdiff2"); + } - public function test_diffFile_unified_2 () - { - $xdiff = new Xdiff ("unified"); - $this->setExpectedException (); - $res = $xdiff->diffFile ("/tmp/test_xdiffNOTEXISTS", "/tmp/test_xdiff2"); - } + public function test_diffFile_unified_3() + { + $xdiff = new Xdiff("unified"); + $this->setExpectedException(); + $res = $xdiff->diffFile("/tmp/test_xdiff1", "/tmp/test_xdiffNOTEXISTS"); + } - public function test_diffFile_unified_3 () - { - $xdiff = new Xdiff ("unified"); - $this->setExpectedException (); - $res = $xdiff->diffFile ("/tmp/test_xdiff1", "/tmp/test_xdiffNOTEXISTS"); - } - - public function test_diffFile_sideBySide_1 () - { - file_put_contents ("/tmp/test_xdiff1", $this->string1); - file_put_contents ("/tmp/test_xdiff2", $this->string2); - $xdiff = new Xdiff ("sideBySide"); - $res = $xdiff->diffFile ("/tmp/test_xdiff1", "/tmp/test_xdiff2"); - $this->assertSame ($res, -" > This is an important + public function test_diffFile_sideBySide_1() + { + file_put_contents("/tmp/test_xdiff1", $this->string1); + file_put_contents("/tmp/test_xdiff2", $this->string2); + $xdiff = new Xdiff("sideBySide"); + $res = $xdiff->diffFile("/tmp/test_xdiff1", "/tmp/test_xdiff2"); + $this->assertSame( + $res, + " > This is an important > notice! It should > therefore be located at > the beginning of this @@ -385,6 +386,7 @@ be added after it. be added after it. > This paragraph contains > important new additions > to this document. -"); - } +" + ); + } } diff --git a/Tests/XmppclientTest.php b/Tests/XmppclientTest.php index bc3eb2f..35f89dd 100644 --- a/Tests/XmppclientTest.php +++ b/Tests/XmppclientTest.php @@ -1,4 +1,5 @@ @@ -12,49 +13,71 @@ use Domframework\Xmppclient; /** Test the domframework xmppclient part */ class xmppclientTest extends \PHPUnit_Framework_TestCase { - public function test_connection_BADNAME () - { - $this->expectException ("Exception"); - $xmppclient = new Xmppclient (); - $res = $xmppclient->connect ("NOTFOUND.fournier38.fr", 5222, "", ""); - } + public function test_connection_BADNAME() + { + $this->expectException("Exception"); + $xmppclient = new Xmppclient(); + $res = $xmppclient->connect("NOTFOUND.fournier38.fr", 5222, "", ""); + } - public function test_connection_authenticate_1 () - { - $xmppclient = new Xmppclient (); - $res = $xmppclient->connect ("xmpp.fournier38.fr", 5222, - "testxmpp@xmpp.fournier38.fr", "LSqmBXDUZWxk"); - $this->assertSame (is_object ($res), true); - } + public function test_connection_authenticate_1() + { + $xmppclient = new Xmppclient(); + $res = $xmppclient->connect( + "xmpp.fournier38.fr", + 5222, + "testxmpp@xmpp.fournier38.fr", + "LSqmBXDUZWxk" + ); + $this->assertSame(is_object($res), true); + } - public function test_connection_disco_1 () - { - $xmppclient = new Xmppclient (); - $xmppclient->connect ("xmpp.fournier38.fr", 5222, - "testxmpp@xmpp.fournier38.fr", "LSqmBXDUZWxk"); - $res = $xmppclient->discoveryService (); - $this->assertSame (is_array ($res) && count ($res) > 5, true); - } + public function test_connection_disco_1() + { + $xmppclient = new Xmppclient(); + $xmppclient->connect( + "xmpp.fournier38.fr", + 5222, + "testxmpp@xmpp.fournier38.fr", + "LSqmBXDUZWxk" + ); + $res = $xmppclient->discoveryService(); + $this->assertSame(is_array($res) && count($res) > 5, true); + } - public function test_connection_sendMessage_1 () - { - $xmppclient = new Xmppclient (); - $xmppclient->connect ("xmpp.fournier38.fr", 5222, - "testxmpp@xmpp.fournier38.fr", "LSqmBXDUZWxk"); - $res = $xmppclient->sendMessagePrivate ("dominique@fournier38.fr", - "DFW TEST XMPP : test_connection_sendMessage_1"); - $this->assertSame (is_object ($res), true); - } + public function test_connection_sendMessage_1() + { + $xmppclient = new Xmppclient(); + $xmppclient->connect( + "xmpp.fournier38.fr", + 5222, + "testxmpp@xmpp.fournier38.fr", + "LSqmBXDUZWxk" + ); + $res = $xmppclient->sendMessagePrivate( + "dominique@fournier38.fr", + "DFW TEST XMPP : test_connection_sendMessage_1" + ); + $this->assertSame(is_object($res), true); + } - public function test_connection_sendMessage_2 () - { - $xmppclient = new Xmppclient (); - $xmppclient->connect ("xmpp.fournier38.fr", 5222, - "testxmpp@xmpp.fournier38.fr", "LSqmBXDUZWxk"); - $res = $xmppclient->sendMessagePrivate ("dominique@fournier38.fr", - "DFW TEST XMPP : test_connection_sendMessage_2 : MESSAGE 1"); - $res = $xmppclient->sendMessagePrivate ("dominique@fournier38.fr", - "DFW TEST XMPP : test_connection_sendMessage_2 : MESSAGE 2"); - $this->assertSame (is_object ($res), true); - } + public function test_connection_sendMessage_2() + { + $xmppclient = new Xmppclient(); + $xmppclient->connect( + "xmpp.fournier38.fr", + 5222, + "testxmpp@xmpp.fournier38.fr", + "LSqmBXDUZWxk" + ); + $res = $xmppclient->sendMessagePrivate( + "dominique@fournier38.fr", + "DFW TEST XMPP : test_connection_sendMessage_2 : MESSAGE 1" + ); + $res = $xmppclient->sendMessagePrivate( + "dominique@fournier38.fr", + "DFW TEST XMPP : test_connection_sendMessage_2 : MESSAGE 2" + ); + $this->assertSame(is_object($res), true); + } } diff --git a/Tests/configuration.php b/Tests/configuration.php index 8276d1a..161c8d2 100644 --- a/Tests/configuration.php +++ b/Tests/configuration.php @@ -1,4 +1,5 @@ @@ -6,8 +7,9 @@ */ namespace Domframework\Tests; + $conf = array ( - "database"=> array ( + "database" => array ( "dsn" => "sqlite:/tmp/database.db", "username" => null, "password" => null, diff --git a/src/Auth.php b/src/Auth.php index a8fd138..be8d649 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -1,4 +1,5 @@ @@ -10,50 +11,50 @@ namespace Domframework; /** User authentication (abstract class) */ class Auth { - /** The application name */ - public $appName = null; + /** The application name */ + public $appName = null; - /** 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 - * @param string $baseURL The URL base to use for the links - * @param string|null $message Message to display to the user - * @param string|null $url URL to go back after successful authentication - * @param mixed $alreadyAuth If the user is already authenticated, the value - * will be displayed if the user is coming on the page. - */ - public function pageHTML ($baseURL, $message="", $url="", $alreadyAuth=false) - { - $res = ""; - $res .= "\n"; - $res .= "\n"; - $res .= "\n"; - $res .= "".dgettext ("domframework", "Sign in")."\n"; - $res .= "\n"; + $res .= "\n"; + $res .= "" . dgettext("domframework", "Sign in") . "\n"; + $res .= "appName !== null) - $res .= "

                ".$this->appName."

                \n"; - $res .= " \n"; - $res .= " \n"; - $res .= " \n"; - } - else - { - $res .= " \n"; - if (is_string ($alreadyAuth)) - { - $res .= "

                ".dgettext ("domframework", "With login:")."

                \n"; - $res .= "

                $alreadyAuth

                \n"; - } - $res .= "

                ". - dgettext ("domframework", "Logout")."\n"; - if ($url !== "") - $res .= "". - dgettext ("domframework", "Go back to the calling page"). + $res .= "h1 { color: #bbb }\n"; + $res .= "h2 { padding-top: 0px; padding-bottom: 30px;}\n"; + $res .= " \n"; + $res .= " \n"; + $res .= " \n"; + $res .= "

                \n"; + $res .= "\n"; + $res .= "\n"; + return $res; } - if ($message !== "" && $message !== null) - $res .= "
                $message
                \n"; - $res .= " \n"; - $res .= "\n"; - $res .= "\n"; - $res .= "\n"; - return $res; - } - /** Establish the connection to authentication server - */ - public function connect () - { - throw new \Exception (dgettext ("domframework", - "No connect to authentication available"), - 405); - } + /** Establish the connection to authentication server + */ + public function connect() + { + throw new \Exception( + dgettext( + "domframework", + "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 - * @param string $email Email to authenticate - * @param string $password Password to authenticate - */ - public function authentication ($email, $password) - { - throw new \Exception (dgettext ("domframework", - "No 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 + * @param string $email Email to authenticate + * @param string $password Password to authenticate + */ + public function authentication($email, $password) + { + throw new \Exception(dgettext( + "domframework", + "No authentication available" + ), 405); + } - /** Return all the parameters recorded for the authenticate user - */ - public function getdetails () - { - throw new \Exception (dgettext ("domframework", - "No getdetails available"), 405); - } + /** Return all the parameters recorded for the authenticate user + */ + public function getdetails() + { + throw new \Exception(dgettext( + "domframework", + "No getdetails available" + ), 405); + } - /** Method to change the password - * @param string $oldpassword The old password (to check if the user have the - * rights to change the password) - * @param string $newpassword The new password to be recorded - */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "No password change available"), 405); - } + /** Method to change the password + * @param string $oldpassword The old password (to check if the user have the + * rights to change the password) + * @param string $newpassword The new password to be recorded + */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "No password change available" + ), 405); + } - /** Method to overwrite the password (without oldpassword check) - * Must be reserved to the administrators. For the users, use changepassword - * method - * @param string $email the user identifier to select - * @param string $newpassword The new password to be recorded - */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "No password overwrite available"), 405); - } + /** Method to overwrite the password (without oldpassword check) + * Must be reserved to the administrators. For the users, use changepassword + * method + * @param string $email the user identifier to select + * @param string $newpassword The new password to be recorded + */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "No password overwrite 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 (dgettext ("domframework", - "No List User 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(dgettext( + "domframework", + "No List User available" + ), 405); + } - /** Method to disconnect the authenticated user - */ - public function logout () - { - throw new \Exception (dgettext ("domframework", - "No logout method available"), 405); - } + /** Method to disconnect the authenticated user + */ + public function logout() + { + throw new \Exception(dgettext( + "domframework", + "No logout method available" + ), 405); + } } diff --git a/src/Authentication.php b/src/Authentication.php index 6e24deb..dbd7bf2 100644 --- a/src/Authentication.php +++ b/src/Authentication.php @@ -1,4 +1,5 @@ @@ -10,497 +11,566 @@ namespace Domframework; /** All the authentication protocol */ class Authentication { - /** The email of the authenticated/nonauthenticated user */ - //private $email = "anonymous"; + /** The email of the authenticated/nonauthenticated user */ + //private $email = "anonymous"; - /** The debug of the authentication methods */ - public $debug = 0; + /** The debug of the authentication methods */ + public $debug = 0; - /** The route object */ - private $route; + /** The route object */ + private $route; - /** Number of authentication maximum by minute */ - public $ratelimitAuth = 3; + /** Number of authentication maximum by minute */ + public $ratelimitAuth = 3; - /** Directory to store the ratelimit files */ - public $ratelimitDir = "/tmp/ratelimit/"; + /** Directory to store the ratelimit files */ + public $ratelimitDir = "/tmp/ratelimit/"; - /** The rest authentication methods. Can be post, session, http, shibboleth, - * jwt - * Attention : session case = CSRF ! - */ - public $restMethods = array ("http", "jwt"); + /** The rest authentication methods. Can be post, session, http, shibboleth, + * jwt + * Attention : session case = CSRF ! + */ + public $restMethods = array("http", "jwt"); - /** The html authentication methods. Can be : post, session, http, shibboleth, - * jwt - * The "post" is already used when using verifAuthLoginPage method (usually - * only in authentication page) - */ - public $htmlMethods = array ("session"); + /** The html authentication methods. Can be : post, session, http, shibboleth, + * jwt + * The "post" is already used when using verifAuthLoginPage method (usually + * only in authentication page) + */ + public $htmlMethods = array("session"); - /** The authentication methods. Can be ldap, sympa...*/ - public $authMethods = array (); + /** The authentication methods. Can be ldap, sympa...*/ + public $authMethods = array(); - /** The authentication servers configuration - * array ("authXXXX" => array ( - * array ("ldapserver" => "ldaps://server.domain.fr", - * "ldapport" => 636, - * "ldaptimeout" => 5, - * "ldapauth" => "uid=XXX,dc=domain,dc=fr", - * "ldappwd" => "XXX", - * "ldapbase" => "", - * "ldapfilter" => "(mail=%s)", - * "ldapfield" => "mail", - * "ldapfiltersearch" => "(objectClass=inetOrgPerson)" - * ), - * ), - * ); - */ - public $authServers = array (); + /** The authentication servers configuration + * array ("authXXXX" => array ( + * array ("ldapserver" => "ldaps://server.domain.fr", + * "ldapport" => 636, + * "ldaptimeout" => 5, + * "ldapauth" => "uid=XXX,dc=domain,dc=fr", + * "ldappwd" => "XXX", + * "ldapbase" => "", + * "ldapfilter" => "(mail=%s)", + * "ldapfield" => "mail", + * "ldapfiltersearch" => "(objectClass=inetOrgPerson)" + * ), + * ), + * ); + */ + public $authServers = array(); - /** The application Name displayed on authentication page */ - public $appName = null; + /** The application Name displayed on authentication page */ + public $appName = null; - /** The class and method to use to log the errors */ - public $loggingFunc; + /** The class and method to use to log the errors */ + public $loggingFunc; - /** The constructor - * @param object $route The route object - */ - public function __construct ($route) - { - $this->route = $route; - $this->loggingFunc = array ($this, "logging"); - } - -/* public function email () - { - return $this->email; - }*/ - - /** Setter/Getter for debug - * @param integer|null $debug The debug value to get/set - * @return integer|self the actual value or this - */ - public function debug ($debug = null) - { - if ($debug === null) - return $this->debug; - $this->debug = intval ($debug); - return $this; - } - - /** Disconnect the user - * @param string|null $url The url to be redirected after a valid - * logout - */ - public function logout ($url = "") - { - // TODO : Foreach authentication methods->logout (); - if (session_id () === "") - session_start (); - if ($this->debug) echo "
                LOGOUT\n";
                -    $authsession = new Authsession ();
                -    $param = $authsession->getdetails ();
                -    if ($this->debug) echo "Logout for '".$param["email"]."'\n";
                -    call_user_func ($this->loggingFunc,
                -                    LOG_NOTICE,
                -                    "Logout for '".$param["email"]."'");
                -    $authsession->logout ();
                -    unset ($_SESSION["domframework"]["authentication"]);
                -    if (isset ($this->authServers["authjwt"]["serverKey"]))
                +    /** The constructor
                +      * @param object $route The route object
                +      */
                +    public function __construct($route)
                     {
                -      $tokenName = "DFKJWT";
                -      if (isset ($this->authServers["authjwt"]["tokenName"]))
                -        $tokenName = $this->authServers["authjwt"]["tokenName"];
                -      // Unset the JSON Web Token as the authentication
                -      if ($this->route->debug)
                -        echo "Unset the JSON Web Token '$tokenName'
                \n"; - if (! key_exists ("CONTENT_TYPE", $_SERVER) || - $_SERVER["CONTENT_TYPE"] !== "application/json") - echo "\n"; - $algorithm = "HS256"; - $cipherKey = null; - $cacheDir = "data/jwtCache"; - $authjwt = new Authjwt (); - $authjwt->serverKey = $this->authServers["authjwt"]["serverKey"]; - if (isset ($this->authServers["authjwt"]["cipherKey"])) - $authjwt->cipherKey = $this->authServers["authjwt"]["cipherKey"]; - if (isset ($this->authServers["authjwt"]["algorithm"])) - $authjwt->algorithm = $this->authServers["authjwt"]["algorithm"]; - if (isset ($this->authServers["authjwt"]["cacheDir"])) - $authjwt->cacheDir = $this->authServers["authjwt"]["cacheDir"]; - $authjwt->logout (); + $this->route = $route; + $this->loggingFunc = array($this, "logging"); } - if ($this->debug) echo "Redirect to authentication page"; - if ($this->debug) $this->route->debug = $this->debug; - if ($url === "" || $url === null) - { - $_SESSION["domframework"]["authentication"]["message"] = - dgettext ("domframework", "You have been logged out"); - $this->route->redirect ("/authentication", ""); - } - else - $this->route->redirect ($url); - } - /** Display the login page - * @param string|null $url The url to be redirected after a valid - * authentication - */ - public function pageHTML ($url = "") - { - // If the user is already connected, redirect to the main page of the site - if (session_id () === "") - session_start (); - $auth = new Auth (); - $authparams = new Authparams (array ("session")); - if (isset ($_SESSION["domframework"]["authentication"]["message"])) - $message = $_SESSION["domframework"]["authentication"]["message"]; - else - $message = ""; - unset ($_SESSION["domframework"]["authentication"]["message"]); - $alreadyAuth = false; - if ($authparams->email !== "anonymous") - $alreadyAuth = $authparams->email; - if ($this->appName !== null) - $auth->appName = $this->appName; - @header ('X-Frame-Options: SAMEORIGIN'); - echo $auth->pageHTML ($this->route->baseURL(), $message, $url, - $alreadyAuth); - } - - /** Check the authentication page - * @param string|null $url The url to be redirected after a valid - * authentication - */ - public function verifAuthLoginPage ($url = "") - { - if (session_id () === "") - session_start (); - if ($this->debug) echo "Call verifAuthLoginPage ($url) : Start\n"; - // rate-limit the connections - $ratelimiter = new Ratelimitfile (); - // 3 connections by minutes - $ratelimiter->maxEntries = $this->ratelimitAuth; - $ratelimiter->storageDir = $this->ratelimitDir; - if (isset ($_SERVER["HTTP_X_FORWARDED_FOR"])) - $ipClient = $_SERVER["HTTP_X_FORWARDED_FOR"]; - else - $ipClient = $_SERVER["REMOTE_ADDR"]; - if ($ratelimiter->set ("loggin-$ipClient") === false) - { - if ($this->debug) echo "Call verifAuthLoginPage ($url) : Ratelimit\n"; - call_user_func ($this->loggingFunc, - LOG_WARNING, - "Ratelimiting for $ipClient"); - $_SESSION["domframework"]["authentication"]["message"] = - dgettext ("domframework", "Too much connections"); - if ($url === "") + /* public function email () { - $this->route->redirect ("/authentication", ""); - } - else - { - $this->route->redirect ("/authentication/$url", ""); - } - } - $authparams = new Authparams (array ("post")); - $res = $this->verifAuth ($authparams->email, $authparams->password); - if (! is_array ($res)) - { - if ($this->debug) echo "Call verifAuthLoginPage ($url) : ERROR\n"; - // Authentication error - // Redirect to login page after logout - call_user_func ($this->loggingFunc, - LOG_WARNING, - "Logging error for '$authparams->email' (HTML) : $res"); - $authsession = new Authsession (); - $authsession->logout (); - $baseURL = $this->route->baseURL (); - $_SESSION["domframework"]["authentication"]["message"] = $res; - // Check the provided URL before using it - if ($url === "") - { - $this->route->redirect ("/authentication", ""); - } - else - { - $this->route->redirect ("/authentication/$url", ""); - } - } - // Login OK : save in SESSION and go to main page - if ($this->debug) echo "Call verifAuthLoginPage ($url) : USER OK\n"; - call_user_func ($this->loggingFunc, - LOG_NOTICE, - "Logging in for '$authparams->email'"); - if (! array_key_exists ("lastname", $res)) - $res["lastname"] = null; - if (! array_key_exists ("firstname", $res)) - $res["firstname"] = null; - $session = new Authsession (); - $session->savedata ($authparams->email, $authparams->password, - $res["lastname"], $res["firstname"]); - if (isset ($this->authServers["authjwt"]["serverKey"])) - { - // Set the JSON Web Token as the authentication is valid - $tokenName = "DFKJWT"; - if (isset ($this->authServers["authjwt"]["tokenName"])) - $tokenName = $this->authServers["authjwt"]["tokenName"]; - $token = $this->createJwtToken ($authparams->email); - echo "\n"; - } - if ($url === "") - $this->route->redirect ("/", ""); - else - $this->route->redirect ("/$url", ""); - } + return $this->email; + }*/ - /** Check all the REST API - * @param boolean|null $savePassword return the user password if the - * authentication is valid - * @return array The details provided by the authentication mecanism - */ - public function verifAuthREST ($savePassword = false) - { - if ($this->debug) - echo "=== entering verifAuthREST (restMethods=". - print_r ($this->restMethods, true).")\n"; - $authparams = new Authparams ($this->restMethods); - $res = array ("email"=>"anonymous", "password"=>"anonymous"); - if ($authparams->email !== "anonymous" && - $authparams->password !== "anonymous") + /** Setter/Getter for debug + * @param integer|null $debug The debug value to get/set + * @return integer|self the actual value or this + */ + public function debug($debug = null) { - $res = $this->verifAuth ($authparams->email, $authparams->password); + if ($debug === null) { + return $this->debug; + } + $this->debug = intval($debug); + return $this; } - if (! is_array ($res)) - { - call_user_func ($this->loggingFunc, - LOG_WARNING, - "Logging error for '$authparams->email' (REST) : $res"); - // Authentication error - throw new \Exception (dgettext ("domframework", - "Authentication error"), 403); - } - if ($savePassword === true && $authparams->email !== "anonymous") - $res["password"] = $authparams->password; - return $res; - } - /** Return the JSON Web Token - * @param string|array $auth The user data to store in JSON Web Token cache. - * The $this->authServers["authjwt"]["algorithm"], - * $this->authServers["authjwt"]["cipherKey"] and - * $this->authServers["authjwt"]["serverKey"] can be set - */ - public function createJwtToken ($auth) - { - if (isset ($this->authServers["authjwt"]["serverKey"])) + /** Disconnect the user + * @param string|null $url The url to be redirected after a valid + * logout + */ + public function logout($url = "") { - // Set the JSON Web Token as the authentication is valid - $algorithm = "HS256"; - $cipherKey = null; - $cacheDir = "data/jwtCache"; - if (isset ($this->authServers["authjwt"]["algorithm"])) - $algorithm = $this->authServers["authjwt"]["algorithm"]; - if (isset ($this->authServers["authjwt"]["cipherKey"])) - $cipherKey = $this->authServers["authjwt"]["cipherKey"]; - if (isset ($this->authServers["authjwt"]["cacheDir"])) - $cacheDir = $this->authServers["authjwt"]["cacheDir"]; - $payloadArray = array(); - $payloadArray["email"] = $auth; - if (is_array ($auth)) - $payloadArray = $auth; - if (! key_exists ("email", $payloadArray) || - $payloadArray["email"] === "anonymous") - throw new \Exception ("JWT Must authenticate", 401); - $authjwt = new Authjwt (); - $authjwt->serverKey = $this->authServers["authjwt"]["serverKey"]; - $authjwt->cipherKey = $cipherKey; - $authjwt->algorithm = $algorithm; - $authjwt->cacheDir = $cacheDir; - return $authjwt->createJwtToken ($payloadArray); + // TODO : Foreach authentication methods->logout (); + if (session_id() === "") { + session_start(); + } + if ($this->debug) { + echo "
                LOGOUT\n";
                +        }
                +        $authsession = new Authsession();
                +        $param = $authsession->getdetails();
                +        if ($this->debug) {
                +            echo "Logout for '" . $param["email"] . "'\n";
                +        }
                +        call_user_func(
                +            $this->loggingFunc,
                +            LOG_NOTICE,
                +            "Logout for '" . $param["email"] . "'"
                +        );
                +        $authsession->logout();
                +        unset($_SESSION["domframework"]["authentication"]);
                +        if (isset($this->authServers["authjwt"]["serverKey"])) {
                +            $tokenName = "DFKJWT";
                +            if (isset($this->authServers["authjwt"]["tokenName"])) {
                +                $tokenName = $this->authServers["authjwt"]["tokenName"];
                +            }
                +            // Unset the JSON Web Token as the authentication
                +            if ($this->route->debug) {
                +                echo "Unset the JSON Web Token '$tokenName'
                \n"; + } + if ( + ! key_exists("CONTENT_TYPE", $_SERVER) || + $_SERVER["CONTENT_TYPE"] !== "application/json" + ) { + echo "\n"; + } + $algorithm = "HS256"; + $cipherKey = null; + $cacheDir = "data/jwtCache"; + $authjwt = new Authjwt(); + $authjwt->serverKey = $this->authServers["authjwt"]["serverKey"]; + if (isset($this->authServers["authjwt"]["cipherKey"])) { + $authjwt->cipherKey = $this->authServers["authjwt"]["cipherKey"]; + } + if (isset($this->authServers["authjwt"]["algorithm"])) { + $authjwt->algorithm = $this->authServers["authjwt"]["algorithm"]; + } + if (isset($this->authServers["authjwt"]["cacheDir"])) { + $authjwt->cacheDir = $this->authServers["authjwt"]["cacheDir"]; + } + $authjwt->logout(); + } + if ($this->debug) { + echo "Redirect to authentication page"; + } + if ($this->debug) { + $this->route->debug = $this->debug; + } + if ($url === "" || $url === null) { + $_SESSION["domframework"]["authentication"]["message"] = + dgettext("domframework", "You have been logged out"); + $this->route->redirect("/authentication", ""); + } else { + $this->route->redirect($url); + } } - } - /** Check all the others pages of the site - * @return array The details provided by the authentication mecanism - */ - public function verifAuthHTML () - { - // Do not force the session_start ! We don't want the cookie on all the - // pages - if ($this->debug) - echo "=== entering verifAuthHTML (htmlMethods=". - print_r ($this->htmlMethods, true).")\n"; - $authparams = new Authparams ($this->htmlMethods); - // Don't ask to the provider if anonymous is known - if ($authparams->email === "anonymous" || $authparams->email === null) + /** Display the login page + * @param string|null $url The url to be redirected after a valid + * authentication + */ + public function pageHTML($url = "") { - if ($this->debug) echo "Anonymous\n"; - return array ("email"=>"anonymous", "lastname"=>"Anonymous", - "firstname"=>"", "password"=>""); + // If the user is already connected, redirect to the main page of the site + if (session_id() === "") { + session_start(); + } + $auth = new Auth(); + $authparams = new Authparams(array("session")); + if (isset($_SESSION["domframework"]["authentication"]["message"])) { + $message = $_SESSION["domframework"]["authentication"]["message"]; + } else { + $message = ""; + } + unset($_SESSION["domframework"]["authentication"]["message"]); + $alreadyAuth = false; + if ($authparams->email !== "anonymous") { + $alreadyAuth = $authparams->email; + } + if ($this->appName !== null) { + $auth->appName = $this->appName; + } + @header('X-Frame-Options: SAMEORIGIN'); + echo $auth->pageHTML( + $this->route->baseURL(), + $message, + $url, + $alreadyAuth + ); } - if ($this->debug) - echo "verifAuth ($authparams->email, $authparams->password)\n"; - $res = $this->verifAuth ($authparams->email, $authparams->password); - if (! is_array ($res)) - { - // Authentication error - if ($this->debug) echo "Previous session not found"; - $msg = dgettext ("domframework", "Previous session not found"); - $_SESSION["domframework"]["authentication"]["message"] = $msg; - call_user_func ($this->loggingFunc, - LOG_WARNING, - "Previous session not found for '$authparams->email'"); - $url = $this->route->requestURL(); - $this->route->redirect ("/authentication/$url"); - } - return $res; - } - /** Do the real authentication process on all the providers defined in the - * properties of the class. - * @param string $email The email to check - * @param string $password The password to check - * @return array containing the user data if the authentication is - * correct, - * an exception if noting is found - */ - private function verifAuth ($email, $password) - { - if ($this->debug) - echo "Entering in verifAuth ($email, xxxxxxxx)\n"; - if (! is_array ($this->authMethods) || count ($this->authMethods) === 0) - throw new \Exception ("No authentication method defined", 500); - if ($this->debug < 2 && - isset ($_SESSION["domframework"]["authentication"]["lastcheck"]) && - $_SESSION["domframework"]["authentication"]["lastcheck"] + 180 < - time ()) + /** Check the authentication page + * @param string|null $url The url to be redirected after a valid + * authentication + */ + public function verifAuthLoginPage($url = "") { - // Test the authentication each 3 minutes if there is a session, else - // return the previous values - if ($this->debug) - echo "verifAuth : using auth cache (push in debug=2 to skip)\n"; - return $_SESSION["domframework"]["authentication"]["authcache"]; + if (session_id() === "") { + session_start(); + } + if ($this->debug) { + echo "Call verifAuthLoginPage ($url) : Start\n"; + } + // rate-limit the connections + $ratelimiter = new Ratelimitfile(); + // 3 connections by minutes + $ratelimiter->maxEntries = $this->ratelimitAuth; + $ratelimiter->storageDir = $this->ratelimitDir; + if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { + $ipClient = $_SERVER["HTTP_X_FORWARDED_FOR"]; + } else { + $ipClient = $_SERVER["REMOTE_ADDR"]; + } + if ($ratelimiter->set("loggin-$ipClient") === false) { + if ($this->debug) { + echo "Call verifAuthLoginPage ($url) : Ratelimit\n"; + } + call_user_func( + $this->loggingFunc, + LOG_WARNING, + "Ratelimiting for $ipClient" + ); + $_SESSION["domframework"]["authentication"]["message"] = + dgettext("domframework", "Too much connections"); + if ($url === "") { + $this->route->redirect("/authentication", ""); + } else { + $this->route->redirect("/authentication/$url", ""); + } + } + $authparams = new Authparams(array("post")); + $res = $this->verifAuth($authparams->email, $authparams->password); + if (! is_array($res)) { + if ($this->debug) { + echo "Call verifAuthLoginPage ($url) : ERROR\n"; + } + // Authentication error + // Redirect to login page after logout + call_user_func( + $this->loggingFunc, + LOG_WARNING, + "Logging error for '$authparams->email' (HTML) : $res" + ); + $authsession = new Authsession(); + $authsession->logout(); + $baseURL = $this->route->baseURL(); + $_SESSION["domframework"]["authentication"]["message"] = $res; + // Check the provided URL before using it + if ($url === "") { + $this->route->redirect("/authentication", ""); + } else { + $this->route->redirect("/authentication/$url", ""); + } + } + // Login OK : save in SESSION and go to main page + if ($this->debug) { + echo "Call verifAuthLoginPage ($url) : USER OK\n"; + } + call_user_func( + $this->loggingFunc, + LOG_NOTICE, + "Logging in for '$authparams->email'" + ); + if (! array_key_exists("lastname", $res)) { + $res["lastname"] = null; + } + if (! array_key_exists("firstname", $res)) { + $res["firstname"] = null; + } + $session = new Authsession(); + $session->savedata( + $authparams->email, + $authparams->password, + $res["lastname"], + $res["firstname"] + ); + if (isset($this->authServers["authjwt"]["serverKey"])) { + // Set the JSON Web Token as the authentication is valid + $tokenName = "DFKJWT"; + if (isset($this->authServers["authjwt"]["tokenName"])) { + $tokenName = $this->authServers["authjwt"]["tokenName"]; + } + $token = $this->createJwtToken($authparams->email); + echo "\n"; + } + if ($url === "") { + $this->route->redirect("/", ""); + } else { + $this->route->redirect("/$url", ""); + } } - $authServers = $this->authServers; - foreach ($this->authMethods as $method) + /** Check all the REST API + * @param boolean|null $savePassword return the user password if the + * authentication is valid + * @return array The details provided by the authentication mecanism + */ + public function verifAuthREST($savePassword = false) { - if ($this->debug) - echo "Authentication method=$method\n"; - if (! is_string ($method)) - throw new \Exception ("The authentication method is not a string", 500); - $classname = "auth$method"; - //require_once ("domframework/$classname.php"); - if (! array_key_exists ($classname, $authServers)) - throw new \Exception ("No authentication server '$classname' enabled", - 500); - // If only one server is defined, the parameters can directely be pushed - // to the classname - if (! is_array (reset ($authServers[$classname]))) - { - $authServers[$classname] = array ($authServers[$classname]); - } - if ($this->debug >= 2) - echo "Authentication method=$method : authServers=". - var_export ($authServers[$classname])."\n"; - if (! is_array ($authServers[$classname]) || - count ($authServers[$classname]) === 0) - throw new \Exception ("No authentication server defined for method ". + if ($this->debug) { + echo "=== entering verifAuthREST (restMethods=" . + print_r($this->restMethods, true) . ")\n"; + } + $authparams = new Authparams($this->restMethods); + $res = array("email" => "anonymous", "password" => "anonymous"); + if ( + $authparams->email !== "anonymous" && + $authparams->password !== "anonymous" + ) { + $res = $this->verifAuth($authparams->email, $authparams->password); + } + if (! is_array($res)) { + call_user_func( + $this->loggingFunc, + LOG_WARNING, + "Logging error for '$authparams->email' (REST) : $res" + ); + // Authentication error + throw new \Exception(dgettext( + "domframework", + "Authentication error" + ), 403); + } + if ($savePassword === true && $authparams->email !== "anonymous") { + $res["password"] = $authparams->password; + } + return $res; + } + + /** Return the JSON Web Token + * @param string|array $auth The user data to store in JSON Web Token cache. + * The $this->authServers["authjwt"]["algorithm"], + * $this->authServers["authjwt"]["cipherKey"] and + * $this->authServers["authjwt"]["serverKey"] can be set + */ + public function createJwtToken($auth) + { + if (isset($this->authServers["authjwt"]["serverKey"])) { + // Set the JSON Web Token as the authentication is valid + $algorithm = "HS256"; + $cipherKey = null; + $cacheDir = "data/jwtCache"; + if (isset($this->authServers["authjwt"]["algorithm"])) { + $algorithm = $this->authServers["authjwt"]["algorithm"]; + } + if (isset($this->authServers["authjwt"]["cipherKey"])) { + $cipherKey = $this->authServers["authjwt"]["cipherKey"]; + } + if (isset($this->authServers["authjwt"]["cacheDir"])) { + $cacheDir = $this->authServers["authjwt"]["cacheDir"]; + } + $payloadArray = array(); + $payloadArray["email"] = $auth; + if (is_array($auth)) { + $payloadArray = $auth; + } + if ( + ! key_exists("email", $payloadArray) || + $payloadArray["email"] === "anonymous" + ) { + throw new \Exception("JWT Must authenticate", 401); + } + $authjwt = new Authjwt(); + $authjwt->serverKey = $this->authServers["authjwt"]["serverKey"]; + $authjwt->cipherKey = $cipherKey; + $authjwt->algorithm = $algorithm; + $authjwt->cacheDir = $cacheDir; + return $authjwt->createJwtToken($payloadArray); + } + } + + /** Check all the others pages of the site + * @return array The details provided by the authentication mecanism + */ + public function verifAuthHTML() + { + // Do not force the session_start ! We don't want the cookie on all the + // pages + if ($this->debug) { + echo "=== entering verifAuthHTML (htmlMethods=" . + print_r($this->htmlMethods, true) . ")\n"; + } + $authparams = new Authparams($this->htmlMethods); + // Don't ask to the provider if anonymous is known + if ($authparams->email === "anonymous" || $authparams->email === null) { + if ($this->debug) { + echo "Anonymous\n"; + } + return array("email" => "anonymous", "lastname" => "Anonymous", + "firstname" => "", "password" => ""); + } + if ($this->debug) { + echo "verifAuth ($authparams->email, $authparams->password)\n"; + } + $res = $this->verifAuth($authparams->email, $authparams->password); + if (! is_array($res)) { + // Authentication error + if ($this->debug) { + echo "Previous session not found"; + } + $msg = dgettext("domframework", "Previous session not found"); + $_SESSION["domframework"]["authentication"]["message"] = $msg; + call_user_func( + $this->loggingFunc, + LOG_WARNING, + "Previous session not found for '$authparams->email'" + ); + $url = $this->route->requestURL(); + $this->route->redirect("/authentication/$url"); + } + return $res; + } + + /** Do the real authentication process on all the providers defined in the + * properties of the class. + * @param string $email The email to check + * @param string $password The password to check + * @return array containing the user data if the authentication is + * correct, + * an exception if noting is found + */ + private function verifAuth($email, $password) + { + if ($this->debug) { + echo "Entering in verifAuth ($email, xxxxxxxx)\n"; + } + if (! is_array($this->authMethods) || count($this->authMethods) === 0) { + throw new \Exception("No authentication method defined", 500); + } + if ( + $this->debug < 2 && + isset($_SESSION["domframework"]["authentication"]["lastcheck"]) && + $_SESSION["domframework"]["authentication"]["lastcheck"] + 180 < + time() + ) { + // Test the authentication each 3 minutes if there is a session, else + // return the previous values + if ($this->debug) { + echo "verifAuth : using auth cache (push in debug=2 to skip)\n"; + } + return $_SESSION["domframework"]["authentication"]["authcache"]; + } + $authServers = $this->authServers; + + foreach ($this->authMethods as $method) { + if ($this->debug) { + echo "Authentication method=$method\n"; + } + if (! is_string($method)) { + throw new \Exception("The authentication method is not a string", 500); + } + $classname = "auth$method"; + //require_once ("domframework/$classname.php"); + if (! array_key_exists($classname, $authServers)) { + throw new \Exception( + "No authentication server '$classname' enabled", + 500 + ); + } + // If only one server is defined, the parameters can directely be pushed + // to the classname + if (! is_array(reset($authServers[$classname]))) { + $authServers[$classname] = array($authServers[$classname]); + } + if ($this->debug >= 2) { + echo "Authentication method=$method : authServers=" . + var_export($authServers[$classname]) . "\n"; + } + if ( + ! is_array($authServers[$classname]) || + count($authServers[$classname]) === 0 + ) { + throw new \Exception("No authentication server defined for method " . "'$method'", 500); - foreach ($authServers[$classname] as $key=>$serversParam) - { - if ($this->debug) - echo "Test auth server $method # $classname # $key\n"; - if (! is_array ($serversParam)) - throw new \Exception ("Auth Server $key configuration error : ". + } + foreach ($authServers[$classname] as $key => $serversParam) { + if ($this->debug) { + echo "Test auth server $method # $classname # $key\n"; + } + if (! is_array($serversParam)) { + throw new \Exception("Auth Server $key configuration error : " . "not an array", 500); - $class = __NAMESPACE__."\\".ucfirst ($classname); - $authmethod = new $class (); - foreach ($serversParam as $param=>$value) - { - if ($this->debug) - { - if (is_array ($value)) - echo "Add param '$param' to auth$method : ". - var_export ($value, true)."\n"; - else - echo "Add param '$param' with value '$value' to auth$method\n"; - } - $authmethod->$param = $value; + } + $class = __NAMESPACE__ . "\\" . ucfirst($classname); + $authmethod = new $class(); + foreach ($serversParam as $param => $value) { + if ($this->debug) { + if (is_array($value)) { + echo "Add param '$param' to auth$method : " . + var_export($value, true) . "\n"; + } else { + echo "Add param '$param' with value '$value' to auth$method\n"; + } + } + $authmethod->$param = $value; + } + $authmethod->connect(); + try { + $authmethod->authentication($email, $password); + $_SESSION["domframework"]["authentication"]["authcache"] = + $authmethod->getdetails(); + $_SESSION["domframework"]["authentication"]["lastcheck"] = time(); + return $authmethod->getdetails(); + } catch (\Exception $e) { + call_user_func( + $this->loggingFunc, + LOG_DEBUG, + "Authentication error for '$email' : " . + "$classname : " . $e->getMessage() + ); + } + } } - $authmethod->connect (); - try - { - $authmethod->authentication ($email, $password); - $_SESSION["domframework"]["authentication"]["authcache"] = - $authmethod->getdetails (); - $_SESSION["domframework"]["authentication"]["lastcheck"] = time (); - return $authmethod->getdetails (); - } - catch (\Exception $e) - { - call_user_func ($this->loggingFunc, - LOG_DEBUG, - "Authentication error for '$email' : ". - "$classname : ".$e->getMessage()); - } - } + return dgettext("domframework", "Bad login/password"); } - return dgettext ("domframework", "Bad login/password"); - } - /** Add the authentication routes to the routing model for HTML - * authentication. Not needed if using shibboleth, HTTP auth... - */ - public function routes () - { - $authObj = $this; - $route=$this->route; - $this->route - ->get ("authentication/logout({url})?", function ($url) use ($authObj) + /** Add the authentication routes to the routing model for HTML + * authentication. Not needed if using shibboleth, HTTP auth... + */ + public function routes() { - if (session_id () === "") - session_start (); - $authObj->logout ($url); - }) + $authObj = $this; + $route = $this->route; + $this->route + ->get("authentication/logout({url})?", function ($url) use ($authObj) { + if (session_id() === "") { + session_start(); + } + $authObj->logout($url); + }) - ->get ("authentication", function () use ($route) + ->get("authentication", function () use ($route) { + $route->redirect("/authentication/"); + }) + + ->get("authentication/({url})?", function ($url) use ($authObj) { + if (session_id() === "") { + session_start(); + } + $authObj->pageHTML($url); + exit; + }) + + ->post("authentication/({url})?", function ($url) use ($authObj) { + if (session_id() === "") { + session_start(); + } + $authObj->verifAuthLoginPage($url); + exit; + }) + ; + $this->route->authenticationURL = "/authentication/"; + } + + /** The default method to display the error messages. + * Do not display the debug messages, and write the errors on screen + * @param integer $priority The priority of the message + * @param string $message The message to log + */ + private function logging($priority, $message) { - $route->redirect ("/authentication/"); - }) - - ->get ("authentication/({url})?", function ($url) use ($authObj) - { - if (session_id () === "") - session_start (); - $authObj->pageHTML ($url); - exit; - }) - - ->post ("authentication/({url})?", function ($url) use ($authObj) - { - if (session_id () === "") - session_start (); - $authObj->verifAuthLoginPage ($url); - exit; - }) - ; - $this->route->authenticationURL = "/authentication/"; - } - - /** The default method to display the error messages. - * Do not display the debug messages, and write the errors on screen - * @param integer $priority The priority of the message - * @param string $message The message to log - */ - private function logging ($priority, $message) - { - if ($this->debug === 0 && $priority > 4) - return; - file_put_contents ("/tmp/auth.log", "$priority : $message\n", FILE_APPEND); - } + if ($this->debug === 0 && $priority > 4) { + return; + } + file_put_contents("/tmp/auth.log", "$priority : $message\n", FILE_APPEND); + } } diff --git a/src/Authhtpasswd.php b/src/Authhtpasswd.php index 3e5ed43..6585040 100644 --- a/src/Authhtpasswd.php +++ b/src/Authhtpasswd.php @@ -1,4 +1,5 @@ @@ -13,82 +14,103 @@ namespace Domframework; */ class Authhtpasswd extends Auth { - /** The .htpasswd file to use for authentication */ - public $htpasswdFile; + /** The .htpasswd file to use for authentication */ + public $htpasswdFile; - /** The details to return if the user is authenticated */ - private $details = null; + /** The details to return if the user is authenticated */ + private $details = null; - /** There is no real connection to htpasswd */ - public function connect () - { - if (! file_exists ($this->htpasswdFile)) - throw new \Exception (sprintf (dgettext ("domframework", - "The HTPasswd file '%s' is not found"), - $this->htpasswdFile), 500); - if (! is_readable ($this->htpasswdFile)) - throw new \Exception (sprintf (dgettext ("domframework", - "The HTPasswd file '%s' is not readable"), - $this->htpasswdFile), 500); - } - - /** Try to authenticate the email/password of the user - @param string $email Email to authenticate - @param string $password Password to authenticate */ - public function authentication ($email, $password) - { - // Redo the checks of connect to not have a property to add - $this->connect (); - $file = file_get_contents ($this->htpasswdFile); - $lines = explode ("\n", $file); - foreach ($lines as $line) + /** There is no real connection to htpasswd */ + public function connect() { - // Comment line : skip it - if (isset ($line[0]) && $line[0] === "#") - continue; - $line = trim ($line); - $user = strstr ($line, ":", true); - $cryptedPassword = substr (strstr ($line, ':'), 1); - if ($user === $email) - { - if (substr ($cryptedPassword, 0, 6) === '$apr1$') - throw new \Exception (dgettext ("domframework", - "Invalid format of password"), 500); - if (crypt ($password, $cryptedPassword) !== $cryptedPassword) - throw new \Exception ("Bad password for '$email'", 401); - $this->details = array ("email"=>$email); - return TRUE; - } + if (! file_exists($this->htpasswdFile)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "The HTPasswd file '%s' is not found" + ), + $this->htpasswdFile + ), 500); + } + if (! is_readable($this->htpasswdFile)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "The HTPasswd file '%s' is not readable" + ), + $this->htpasswdFile + ), 500); + } } - throw new \Exception ("Unable to find the user : '$email'", 401); - } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - return $this->details; - } + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + public function authentication($email, $password) + { + // Redo the checks of connect to not have a property to add + $this->connect(); + $file = file_get_contents($this->htpasswdFile); + $lines = explode("\n", $file); + foreach ($lines as $line) { + // Comment line : skip it + if (isset($line[0]) && $line[0] === "#") { + continue; + } + $line = trim($line); + $user = strstr($line, ":", true); + $cryptedPassword = substr(strstr($line, ':'), 1); + if ($user === $email) { + if (substr($cryptedPassword, 0, 6) === '$apr1$') { + throw new \Exception(dgettext( + "domframework", + "Invalid format of password" + ), 500); + } + if (crypt($password, $cryptedPassword) !== $cryptedPassword) { + throw new \Exception("Bad password for '$email'", 401); + } + $this->details = array("email" => $email); + return true; + } + } + throw new \Exception("Unable to find the user : '$email'", 401); + } - /** Method to change the password - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for HTPasswd users"), - 405); - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + return $this->details; + } + + /** Method to change the password + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be change for HTPasswd users" + ), + 405 + ); + } /** Method to overwrite the password (without oldpassword check) Must be reserved to the administrators. For the users, use changepassword method @param string $email the user identifier to select @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for HTPasswd users"), - 405); - } + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be change for HTPasswd users" + ), + 405 + ); + } } diff --git a/src/Authimap.php b/src/Authimap.php index d2dec41..8954d19 100644 --- a/src/Authimap.php +++ b/src/Authimap.php @@ -1,4 +1,5 @@ @@ -10,78 +11,92 @@ namespace Domframework; /** User authentication against IMAP server */ class Authimap extends Auth { - /** IMAP server */ - public $imapServer = "localhost"; - /** IMAP TCP port (143 by default) */ - public $imapPort = 143; - /** IMAP SSL connection */ - public $imapSSL = false; - /** IMAP SSL CheckCertificate */ - public $imapSSLCheckCertificates = true; + /** IMAP server */ + public $imapServer = "localhost"; + /** IMAP TCP port (143 by default) */ + public $imapPort = 143; + /** IMAP SSL connection */ + public $imapSSL = false; + /** IMAP SSL CheckCertificate */ + public $imapSSLCheckCertificates = true; - /** The details available after authentication */ - private $details = null; + /** The details available after authentication */ + private $details = null; - /** Check the availablity of the IMAP support in PHP */ - function __construct () - { - if (!function_exists ("imap_open")) - throw new \Exception ("IMAP support unavailable in PHP", 500); - } + /** Check the availablity of the IMAP support in PHP */ + public function __construct() + { + if (!function_exists("imap_open")) { + throw new \Exception("IMAP support unavailable in PHP", 500); + } + } - /** Establish the connection to IMAP server. Don't do anything as the - needed parameters are username and password */ - public function connect () - { - // Nothing to do - } + /** Establish the connection to IMAP server. Don't do anything as the + needed parameters are username and password */ + public function connect() + { + // Nothing to do + } - /** Try to authenticate the email/password of the user - @param string $email Email to authenticate - @param string $password Password to authenticate */ - public function authentication ($email, $password) - { - $imap = new Imap ($this->imapServer, $this->imapPort, - $email, $password, - $this->imapSSL, $this->imapSSLCheckCertificates); - $this->details = array ("email" => $email); - // Let the throw Exception be catched by the parent - return true; - } + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + public function authentication($email, $password) + { + $imap = new Imap( + $this->imapServer, + $this->imapPort, + $email, + $password, + $this->imapSSL, + $this->imapSSLCheckCertificates + ); + $this->details = array("email" => $email); + // Let the throw Exception be catched by the parent + return true; + } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - return $this->details; - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + return $this->details; + } - /** Method to change the password - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for IMAP users"), 405); - } + /** Method to change the password + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "The password can't be change for IMAP users" + ), 405); + } - /** Method to overwrite the password (without oldpassword check) - Must be reserved to the administrators. For the users, use changepassword - method - @param string $email the user identifier to select - @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite for IMAP users"), - 405); - } + /** Method to overwrite the password (without oldpassword check) + Must be reserved to the administrators. For the users, use changepassword + method + @param string $email the user identifier to select + @param string $newpassword The new password to be recorded */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be overwrite for IMAP users" + ), + 405 + ); + } - /** List all the users available in the database - Return firstname, lastname, mail, with mail is an array */ - public function listusers () - { - throw new \Exception (dgettext ("domframework", - "Can't get list of users for IMAP server"), 405); - } + /** List all the users available in the database + Return firstname, lastname, mail, with mail is an array */ + public function listusers() + { + throw new \Exception(dgettext( + "domframework", + "Can't get list of users for IMAP server" + ), 405); + } } diff --git a/src/Authjwt.php b/src/Authjwt.php index a5f931c..d743cf7 100644 --- a/src/Authjwt.php +++ b/src/Authjwt.php @@ -1,4 +1,5 @@ @@ -13,158 +14,198 @@ namespace Domframework; */ class Authjwt extends Auth { - // PROPERTIES SET BY AUTH - /** The JSON Web Token Server key if used - */ - public $serverKey = null; + // PROPERTIES SET BY AUTH + /** The JSON Web Token Server key if used + */ + public $serverKey = null; - /** The cipher key to decrypt the token - */ - public $cipherKey = null; + /** The cipher key to decrypt the token + */ + public $cipherKey = null; - /** The allowed algorithms in array format - * If null, all the algorithms are allowed - * allowed : ['HS256', 'HS512', 'HS384'] - */ - public $allowedAlg = null; + /** The allowed algorithms in array format + * If null, all the algorithms are allowed + * allowed : ['HS256', 'HS512', 'HS384'] + */ + public $allowedAlg = null; - /** The algorithm to use, in $allowedAlg list - */ - public $algorithm = "HS256"; + /** The algorithm to use, in $allowedAlg list + */ + public $algorithm = "HS256"; - /** The directory to store the user credentials - */ - public $cacheDir = "data/jwtCache"; + /** The directory to store the user credentials + */ + public $cacheDir = "data/jwtCache"; - // INTERNAL PROPERTIES - /** If the user is valid, return the payload in details - */ - private $payload = null; + // INTERNAL PROPERTIES + /** If the user is valid, return the payload in details + */ + private $payload = null; - /** Save the token - */ - private $token = null; + /** Save the token + */ + private $token = null; - /** No connection to JWT - */ - public function connect () - { - return TRUE; - } - - /** Try to authenticate the email/password of the user - * If the token is valid, return all the data available in payload. Can - * return a value without email attribute ! - * @param string $email Email not used (wait for Bearer) - * @param string $password Password not used (wait for Bearer) - */ - public function authentication ($email, $password) - { - if (! isset ($_SERVER["HTTP_AUTHENTICATION"])) - throw new \Exception (dgettext ("domframework", - "No Authentication available"), 401); - if (substr ($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") - throw new \Exception (dgettext ("domframework", - "No Bearer Authentication available"), 401); - $token = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); - $jwt = new Jwt (); - $uuid = $jwt->decode ($token, $this->serverKey, $this->allowedAlg, - $this->cipherKey); - $cachefile = new Cachefile (); - $cachefile->directory = $this->cacheDir; - $payload = $cachefile->read ((string)$uuid); - // The JWT was tested in authparams. End of process - if (empty ($uuid) || empty ($payload) || ! key_exists ("email", $payload)) + /** No connection to JWT + */ + public function connect() { - return array ("lastname" => "anonymous", - "firstname" => "", - "email" => "anonymous"); + return true; } - $this->payload = $payload; - return $payload; - } - /** Return all the parameters recorded for the authenticate user - */ - public function getdetails () - { - if (! is_array ($this->payload) || - key_exists ("email", $this->payload) && - $this->payload["email"] === "anonymous") - return array ("lastname" => "anonymous", + /** Try to authenticate the email/password of the user + * If the token is valid, return all the data available in payload. Can + * return a value without email attribute ! + * @param string $email Email not used (wait for Bearer) + * @param string $password Password not used (wait for Bearer) + */ + public function authentication($email, $password) + { + if (! isset($_SERVER["HTTP_AUTHENTICATION"])) { + throw new \Exception(dgettext( + "domframework", + "No Authentication available" + ), 401); + } + if (substr($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") { + throw new \Exception(dgettext( + "domframework", + "No Bearer Authentication available" + ), 401); + } + $token = substr($_SERVER["HTTP_AUTHENTICATION"], 7); + $jwt = new Jwt(); + $uuid = $jwt->decode( + $token, + $this->serverKey, + $this->allowedAlg, + $this->cipherKey + ); + $cachefile = new Cachefile(); + $cachefile->directory = $this->cacheDir; + $payload = $cachefile->read((string)$uuid); + // The JWT was tested in authparams. End of process + if (empty($uuid) || empty($payload) || ! key_exists("email", $payload)) { + return array("lastname" => "anonymous", "firstname" => "", "email" => "anonymous"); - return $this->payload; - } + } + $this->payload = $payload; + return $payload; + } - /** Save the auth data in cache directory and return the JWT token - * Do not allow to store data if the $auth is anonymous - * @param array $auth The authentication to save - * @return string JWT token - */ - public function createJwtToken ($auth) - { - if ($this->serverKey === null) - return ""; - if (! key_exists ("email", $auth)) - throw new \Exception (dgettext ("domframework", - "AuthJWT : No email available in auth"), 403); - if ($auth["email"] === "anonymous") - throw new \Exception (dgettext ("domframework", - "AuthJWT : can not create token for anonymous"), 403); - $uuid = Uuid::uuid4 (); - $cachefile = new Cachefile (); - $cachefile->directory = $this->cacheDir; - $cachefile->write ($uuid, $auth); - $jwt = new Jwt (); - return $jwt->encode ($uuid, - $this->serverKey, $this->algorithm, $this->cipherKey); - } + /** Return all the parameters recorded for the authenticate user + */ + public function getdetails() + { + if ( + ! is_array($this->payload) || + key_exists("email", $this->payload) && + $this->payload["email"] === "anonymous" + ) { + return array("lastname" => "anonymous", + "firstname" => "", + "email" => "anonymous"); + } + return $this->payload; + } - /** Method to change the password : unavailable in SESSION auth - * @param string $oldpassword The old password (to check if the user have the - * rights to change the password) - * @param string $newpassword The new password to be recorded - */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for JWT users"), 405); - } + /** Save the auth data in cache directory and return the JWT token + * Do not allow to store data if the $auth is anonymous + * @param array $auth The authentication to save + * @return string JWT token + */ + public function createJwtToken($auth) + { + if ($this->serverKey === null) { + return ""; + } + if (! key_exists("email", $auth)) { + throw new \Exception(dgettext( + "domframework", + "AuthJWT : No email available in auth" + ), 403); + } + if ($auth["email"] === "anonymous") { + throw new \Exception(dgettext( + "domframework", + "AuthJWT : can not create token for anonymous" + ), 403); + } + $uuid = Uuid::uuid4(); + $cachefile = new Cachefile(); + $cachefile->directory = $this->cacheDir; + $cachefile->write($uuid, $auth); + $jwt = new Jwt(); + return $jwt->encode( + $uuid, + $this->serverKey, + $this->algorithm, + $this->cipherKey + ); + } - /** Method to overwrite the password (without oldpassword check) - * Must be reserved to the administrators. For the users, use changepassword - * method - * @param string $email the user identifier to select - * @param string $newpassword The new password to be recorded - */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite for JWT users"), 405); - } + /** Method to change the password : unavailable in SESSION auth + * @param string $oldpassword The old password (to check if the user have the + * rights to change the password) + * @param string $newpassword The new password to be recorded + */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "The password can't be change for JWT users" + ), 405); + } - /** Remove the information from the session - */ - public function logout () - { - if (! isset ($_SERVER["HTTP_AUTHENTICATION"])) - throw new \Exception (dgettext ("domframework", - "No Authentication available"), 401); - if (substr ($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") - throw new \Exception (dgettext ("domframework", - "No Bearer Authentication available"), 401); - $token = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); - $jwt = new Jwt (); - $uuid = $jwt->decode ($token, $this->serverKey, $this->allowedAlg, - $this->cipherKey); - $cachefile = new Cachefile (); - $cachefile->directory = $this->cacheDir; - $payload = $cachefile->read ((string)$uuid); - if (empty ($uuid) || empty ($payload) || ! key_exists ("email", $payload)) - throw new \Exception (dgettext ("domframework", - "Can not found the token : no logout"), 403); - $cachefile->delete ($uuid); - return true; - } + /** Method to overwrite the password (without oldpassword check) + * Must be reserved to the administrators. For the users, use changepassword + * method + * @param string $email the user identifier to select + * @param string $newpassword The new password to be recorded + */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "The password can't be overwrite for JWT users" + ), 405); + } + + /** Remove the information from the session + */ + public function logout() + { + if (! isset($_SERVER["HTTP_AUTHENTICATION"])) { + throw new \Exception(dgettext( + "domframework", + "No Authentication available" + ), 401); + } + if (substr($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") { + throw new \Exception(dgettext( + "domframework", + "No Bearer Authentication available" + ), 401); + } + $token = substr($_SERVER["HTTP_AUTHENTICATION"], 7); + $jwt = new Jwt(); + $uuid = $jwt->decode( + $token, + $this->serverKey, + $this->allowedAlg, + $this->cipherKey + ); + $cachefile = new Cachefile(); + $cachefile->directory = $this->cacheDir; + $payload = $cachefile->read((string)$uuid); + if (empty($uuid) || empty($payload) || ! key_exists("email", $payload)) { + throw new \Exception(dgettext( + "domframework", + "Can not found the token : no logout" + ), 403); + } + $cachefile->delete($uuid); + return true; + } } diff --git a/src/Authldap.php b/src/Authldap.php index 95d5576..48ba68c 100644 --- a/src/Authldap.php +++ b/src/Authldap.php @@ -1,4 +1,5 @@ @@ -10,151 +11,181 @@ namespace Domframework; /** User authentication against LDAP server */ class Authldap extends Auth { - /** LDAP server : can be ldaps://server.domain.tld if LDAPS */ - public $ldapserver="localhost"; - /** LDAP TCP Port (389 by default) */ - public $ldapport=389; - /** LDAP Connection timeout (5s by default) */ - public $ldaptimeout=5; - /** LDAP authentication to search user */ - public $ldapauth = ""; - /** LDAP authentication password */ - public $ldappwd = ""; - /** LDAP Search base */ - public $ldapbase = ""; - /** Filter used to search user */ - public $ldapfilter = "(mail=%s)"; - /** Field used to identify a user */ - public $ldapfield = "mail"; - /** Filter used to find the available data of an authenticated user */ - public $ldapfiltersearch = "(objectClass=inetOrgPerson)"; + /** LDAP server : can be ldaps://server.domain.tld if LDAPS */ + public $ldapserver = "localhost"; + /** LDAP TCP Port (389 by default) */ + public $ldapport = 389; + /** LDAP Connection timeout (5s by default) */ + public $ldaptimeout = 5; + /** LDAP authentication to search user */ + public $ldapauth = ""; + /** LDAP authentication password */ + public $ldappwd = ""; + /** LDAP Search base */ + public $ldapbase = ""; + /** Filter used to search user */ + public $ldapfilter = "(mail=%s)"; + /** Field used to identify a user */ + public $ldapfield = "mail"; + /** Filter used to find the available data of an authenticated user */ + public $ldapfiltersearch = "(objectClass=inetOrgPerson)"; - /** The opened LDAP connection identifier */ - private $ldapconn = NULL; - /** The DN of the user when found */ - private $ldapdnuser = NULL; + /** The opened LDAP connection identifier */ + private $ldapconn = null; + /** The DN of the user when found */ + private $ldapdnuser = null; - /** Check the availability of LDAP functions in PHP */ - 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 - @param string $email Email to authenticate - @param string $password Password to authenticate */ - 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); - $data = ldap_get_entries ($this->ldapconn, $search); - $res = array (); - if (isset ($data[0])) + /** Check the availability of LDAP functions in PHP */ + public function __construct() { - $res = array ("lastname"=>$data[0]["sn"][0], - "firstname"=>$data[0]["givenname"][0], - "email"=>$data[0]["mail"][0]); + if (!function_exists("ldap_connect")) { + throw new \Exception("LDAP support unavailable in PHP", 500); + } } - return $res; - } - - /** Method to change the password - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for LDAP users"), 405); - } - - /** Method to overwrite the password (without oldpassword check) - Must be reserved to the administrators. For the users, use changepassword - method - @param string $email the user identifier to select - @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite 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); - $data = array (); - foreach ($info as $key=>$vals) + /** 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() { - if ($key === "count") continue; - if (isset ($vals["sn"][0]) && isset ($vals["givenname"][0]) && - isset ($vals["mail"])) - { - $data[$key] = array ("lastname"=>$vals["sn"][0], - "firstname"=>$vals["givenname"][0], - "email"=>$vals["mail"][0]); - } + $this->ldapconn = ldap_connect($this->ldapserver, $this->ldapport); + if (!$this->ldapconn) { + throw new \Exception("Can't contact LDAP server", 500); + } - unset ($data[$key]["mail"]["count"]); + 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); + } } - return $data; - } + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + 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; + } - /** Close the LDAP connection when closing the object or PHP */ - function __destruct () - { - if (isset ($this->ldapconn)) - ldap_close ($this->ldapconn); - } + /** 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); + } + $data = ldap_get_entries($this->ldapconn, $search); + $res = array(); + if (isset($data[0])) { + $res = array("lastname" => $data[0]["sn"][0], + "firstname" => $data[0]["givenname"][0], + "email" => $data[0]["mail"][0]); + } + + return $res; + } + + /** Method to change the password + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception(dgettext( + "domframework", + "The password can't be change for LDAP users" + ), 405); + } + + /** Method to overwrite the password (without oldpassword check) + Must be reserved to the administrators. For the users, use changepassword + method + @param string $email the user identifier to select + @param string $newpassword The new password to be recorded */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be overwrite 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); + $data = array(); + foreach ($info as $key => $vals) { + if ($key === "count") { + continue; + } + if ( + isset($vals["sn"][0]) && isset($vals["givenname"][0]) && + isset($vals["mail"]) + ) { + $data[$key] = array("lastname" => $vals["sn"][0], + "firstname" => $vals["givenname"][0], + "email" => $vals["mail"][0]); + } + + unset($data[$key]["mail"]["count"]); + } + + return $data; + } + + /** Close the LDAP connection when closing the object or PHP */ + public function __destruct() + { + if (isset($this->ldapconn)) { + ldap_close($this->ldapconn); + } + } } diff --git a/src/Authorization.php b/src/Authorization.php index 2fa035c..0ba017e 100644 --- a/src/Authorization.php +++ b/src/Authorization.php @@ -1,4 +1,5 @@ @@ -11,89 +12,89 @@ namespace Domframework; user */ class Authorization { - /** Separator between differents modules/objects */ - private $separator = "/"; + /** Separator between differents modules/objects */ + private $separator = "/"; - /** The user ID of the authenticated user */ - public $authiduser = ""; // user id - /** The groups ID of the authenticated user */ - public $authgroups = array (); // List of user's groups id + /** The user ID of the authenticated user */ + public $authiduser = ""; // user id + /** The groups ID of the authenticated user */ + public $authgroups = array(); // List of user's groups id - /** Establish a connexion to the authorization database */ - public function connect () - { - } + /** Establish a connexion to the authorization database */ + public function connect() + { + } - /** Create the structure to store the authorization database */ - public function initialize () - { - } + /** Create the structure to store the authorization database */ + public function initialize() + { + } - /** Return if the user right is NONE, READ, WRITE, EXECUTE - if the object doesn't exists, or is not readable, throw an exception - @param string $object The object path to examine - @return NONE, READ, WRITE, EXECUTE */ - public function validate ($object) - { - } + /** Return if the user right is NONE, READ, WRITE, EXECUTE + if the object doesn't exists, or is not readable, throw an exception + @param string $object The object path to examine + @return NONE, READ, WRITE, EXECUTE */ + public function validate($object) + { + } - /** Add a new object, with owner and group, and mode bits - @param string $object Object path to add - @param integer $owner Owner ID of the object - @param integer $group Group ID of the object - @param integer $modbits Bits of authorization */ - public function add ($object, $owner, $group, $modbits) - { - } + /** Add a new object, with owner and group, and mode bits + @param string $object Object path to add + @param integer $owner Owner ID of the object + @param integer $group Group ID of the object + @param integer $modbits Bits of authorization */ + public function add($object, $owner, $group, $modbits) + { + } - /** Remove the information about an object and all its sub-objects - @param string $object Object path to drop */ - public function drop ($object) - { - } + /** Remove the information about an object and all its sub-objects + @param string $object Object path to drop */ + public function drop($object) + { + } - /** Change the owner of an object - Need to be the root administrator - @param string $object Object path to add - @param integer $owner Owner ID of the object */ - public function chown ($object, $owner) - { - } + /** Change the owner of an object + Need to be the root administrator + @param string $object Object path to add + @param integer $owner Owner ID of the object */ + public function chown($object, $owner) + { + } - /** Change the group of an object - Need to be the owner of the object or the root administrator - @param string $object Object path to add - @param integer $group Group ID of the object */ - public function chgrp ($object, $group) - { - } + /** Change the group of an object + Need to be the owner of the object or the root administrator + @param string $object Object path to add + @param integer $group Group ID of the object */ + public function chgrp($object, $group) + { + } - /** Change mode bits for an object - Need to be the owner of the object or the root administrator - @param string $object Object path to change - @param integer $mod Bits of authorization */ - public function chmod ($object, $mod) - { - } + /** Change mode bits for an object + Need to be the owner of the object or the root administrator + @param string $object Object path to change + @param integer $mod Bits of authorization */ + public function chmod($object, $mod) + { + } - /** Return the mode bits for an object if all his parents are readable for - the user - @param string $object Object path to examine */ - public function lsmod ($object) - { - } + /** Return the mode bits for an object if all his parents are readable for + the user + @param string $object Object path to examine */ + public function lsmod($object) + { + } - /** Return the owner for an object if all his parents are readable for - the user - @param string $object Object path to examine */ - public function lsown ($object) - { - } + /** Return the owner for an object if all his parents are readable for + the user + @param string $object Object path to examine */ + public function lsown($object) + { + } - /** Return the owner for an object if all his parents are readable for - the user - @param string $object Object path to examine */ - public function lsgrp ($object) - { - } + /** Return the owner for an object if all his parents are readable for + the user + @param string $object Object path to examine */ + public function lsgrp($object) + { + } } diff --git a/src/Authorizationdb.php b/src/Authorizationdb.php index 058a282..ad419d1 100644 --- a/src/Authorizationdb.php +++ b/src/Authorizationdb.php @@ -1,4 +1,5 @@ @@ -11,620 +12,783 @@ namespace Domframework; user */ class Authorizationdb extends Authorization { - /** Separator between differents modules/objects */ - private $separator = "/"; - /** Database PDO connector */ - private $db = null; - /** The prefix for the table */ - public $tableprefix = ""; + /** Separator between differents modules/objects */ + private $separator = "/"; + /** Database PDO connector */ + private $db = null; + /** The prefix for the table */ + public $tableprefix = ""; - /** Establish a connexion to the authorization database - @param string $dsn The DSN needed to connect to database - @param string|null $username The username needed to connect to database - @param string|null $password The password needed to connect to database - @param string|null $driver_options The driver options need to connect to - database */ - public function connectdb ($dsn, $username=null, $password=null, - $driver_options=null) - { - // Define the structure of the table in the database - $this->db = new Dblayer ($dsn, $username, $password, $driver_options); - $this->db->table = "domframework_authorization"; - $this->db->tableprefix = $this->tableprefix; - $this->db->fields = array ( - "object"=>array ("varchar", "255", "not null"), - "ownerid"=>array ("integer", "not null"), - "groupid"=>array ("integer", "not null"), - "modbits"=>array ("integer", "not null")); - $this->db->primary = "object"; - $this->db->unique = array ("object"); - } - - /** Create the structure to store the authorization database */ - public function initialize () - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - $tables = $this->db->listTables (); - if (!in_array ($this->db->tableprefix.$this->db->table, $tables)) - { - $this->db->createTable (); - $first = array ("object"=>"/", "ownerid"=>0, "groupid"=>0, - "modbits"=>755); - $this->db->create ($first); - } - } - - /** Return if the user right is NONE, READ, WRITE, EXECUTE - if the object doesn't exists, or is not readable, throw an exception - @param string $object The object path to examine - @return array with READ, WRITE, EXECUTE */ - public function validate ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + /** Establish a connexion to the authorization database + @param string $dsn The DSN needed to connect to database + @param string|null $username The username needed to connect to database + @param string|null $password The password needed to connect to database + @param string|null $driver_options The driver options need to connect to + database */ + public function connectdb( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + // Define the structure of the table in the database + $this->db = new Dblayer($dsn, $username, $password, $driver_options); + $this->db->table = "domframework_authorization"; + $this->db->tableprefix = $this->tableprefix; + $this->db->fields = array( + "object" => array("varchar", "255", "not null"), + "ownerid" => array("integer", "not null"), + "groupid" => array("integer", "not null"), + "modbits" => array("integer", "not null")); + $this->db->primary = "object"; + $this->db->unique = array("object"); } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), - $object), - 404); - $search = reset ($search); - $ownerid = intval ($search["ownerid"]); - $groupid = intval ($search["groupid"]); - $modbits = octdec ($search["modbits"]); - if ($this->authiduser === 0) - return array ("READ", "WRITE", "EXECUTE"); - - $res = array (); - if ($this->authiduser === $ownerid) + /** Create the structure to store the authorization database */ + public function initialize() { - if (($modbits & 0100) === 0100) - $res[] = "EXECUTE"; - if (($modbits & 0200) === 0200) - $res[] = "WRITE"; - if (($modbits & 0400) === 0400) - $res[] = "READ"; + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + $tables = $this->db->listTables(); + if (!in_array($this->db->tableprefix . $this->db->table, $tables)) { + $this->db->createTable(); + $first = array("object" => "/", "ownerid" => 0, "groupid" => 0, + "modbits" => 755); + $this->db->create($first); + } } - foreach ($this->authgroups as $group) + /** Return if the user right is NONE, READ, WRITE, EXECUTE + if the object doesn't exists, or is not readable, throw an exception + @param string $object The object path to examine + @return array with READ, WRITE, EXECUTE */ + public function validate($object) { - if ($group !== $groupid) - continue; - if (($modbits & 0010) === 0010) - $res[] = "EXECUTE"; - if (($modbits & 0020) === 0020) - $res[] = "WRITE"; - if (($modbits & 0040) === 0040) - $res[] = "READ"; + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf( + dgettext( + "domframework", + "Object %s doesn't exists" + ), + $object + ), + 404 + ); + } + $search = reset($search); + $ownerid = intval($search["ownerid"]); + $groupid = intval($search["groupid"]); + $modbits = octdec($search["modbits"]); + if ($this->authiduser === 0) { + return array("READ", "WRITE", "EXECUTE"); + } + + $res = array(); + if ($this->authiduser === $ownerid) { + if (($modbits & 0100) === 0100) { + $res[] = "EXECUTE"; + } + if (($modbits & 0200) === 0200) { + $res[] = "WRITE"; + } + if (($modbits & 0400) === 0400) { + $res[] = "READ"; + } + } + + foreach ($this->authgroups as $group) { + if ($group !== $groupid) { + continue; + } + if (($modbits & 0010) === 0010) { + $res[] = "EXECUTE"; + } + if (($modbits & 0020) === 0020) { + $res[] = "WRITE"; + } + if (($modbits & 0040) === 0040) { + $res[] = "READ"; + } + } + + if (($modbits & 0001) === 0001) { + $res[] = "EXECUTE"; + } + if (($modbits & 0002) === 0002) { + $res[] = "WRITE"; + } + if (($modbits & 0004) === 0004) { + $res[] = "READ"; + } + + return array_unique($res); } - if (($modbits & 0001) === 0001) - $res[] = "EXECUTE"; - if (($modbits & 0002) === 0002) - $res[] = "WRITE"; - if (($modbits & 0004) === 0004) - $res[] = "READ"; - - return array_unique ($res); - } - - /** Add a new object, with ownerid and groupid, and mode bits - @param string $object Object path to add - @param integer $ownerid Owner ID of the object - @param integer $groupid Group ID of the object - @param integer $modbits Bits of authorization - @return boolean TRUE or an exception with the error message */ - public function add ($object, $ownerid, $groupid, $modbits) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - // The modbits are stored in octal to be more readable - $modbits = decoct ($modbits); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - if ($this->authiduser !== 0 && $this->authiduser !== $ownerid) - throw new \Exception (dgettext ("domframework", - "Can't create object not owned by myself"), 406); - if ($this->authiduser !== 0 && !in_array ($groupid, $this->authgroups)) - throw new \Exception (dgettext ("domframework", - "Can't create object with not owned group"), 406); - try + /** Add a new object, with ownerid and groupid, and mode bits + @param string $object Object path to add + @param integer $ownerid Owner ID of the object + @param integer $groupid Group ID of the object + @param integer $modbits Bits of authorization + @return boolean TRUE or an exception with the error message */ + public function add($object, $ownerid, $groupid, $modbits) { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + // The modbits are stored in octal to be more readable + $modbits = decoct($modbits); + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + if ($this->authiduser !== 0 && $this->authiduser !== $ownerid) { + throw new \Exception(dgettext( + "domframework", + "Can't create object not owned by myself" + ), 406); + } + if ($this->authiduser !== 0 && !in_array($groupid, $this->authgroups)) { + throw new \Exception(dgettext( + "domframework", + "Can't create object with not owned group" + ), 406); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search)) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s already defined" + ), $object), + 400 + ); + } + + // All the folder structure is accessible. Check if we can add the file in + // the last folder (Write modbit). Root can always write. + if ($this->authiduser === 0) { + $this->db->create(array("object" => $object, + "ownerid" => $ownerid, + "groupid" => $groupid, + "modbits" => $modbits)); + return true; + } + + try { + $this->treecheckWrite($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + $this->db->create(array("object" => $object, + "ownerid" => $ownerid, + "groupid" => $groupid, + "modbits" => $modbits)); + return true; } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search)) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s already defined"), $object), - 400); - - // All the folder structure is accessible. Check if we can add the file in - // the last folder (Write modbit). Root can always write. - if ($this->authiduser === 0) + /** Remove the information about an object and all its sub-objects + @param string $object Object path to drop + @return boolean TRUE or an exception with the error message */ + public function drop($object) { - $this->db->create (array ("object"=>$object, - "ownerid"=>$ownerid, - "groupid"=>$groupid, - "modbits"=>$modbits)); - return TRUE; + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + if ($object === "/") { + throw new \Exception(dgettext( + "domframework", + "The root can not be removed" + ), 406); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Object %s doesn't exists" + ), + $object + ), 400); + } + + // All the folder structure is accessible. Check if we can remove the file + // in the last folder (Write modbit). Root can always write. + if ($this->authiduser === 0) { + $rc = $this->db->delete($object); + if ($rc > 1) { + throw new \Exception(dgettext( + "domframework", + "Removing more than one object" + ), 406); + } + if ($rc == 0) { + throw new \Exception(dgettext( + "domframework", + "No object removed" + ), 406); + } + $rc = $this->db->delete("$object$this->separator%"); + return true; + } + + try { + $this->treecheckWrite($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + $rc = $this->db->delete($object); + if ($rc > 1) { + throw new \Exception(dgettext( + "domframework", + "Removing more than one object" + ), 406); + } + if ($rc == 0) { + throw new \Exception(dgettext( + "domframework", + "No object removed" + ), 406); + } + $rc = $this->db->delete("$object$this->separator%"); + return true; } - try + /** Change the owner of an object + Need to be the root administrator + @param string $object Object path to add + @param integer $ownerid Owner ID of the object + @return boolean TRUE or an exception with the error message */ + public function chown($object, $ownerid) { - $this->treecheckWrite ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + if ($this->authiduser !== 0) { + throw new \Exception(dgettext( + "domframework", + "The chown is reserved to root user" + ), 405); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 400 + ); + } + $search = reset($search); + $this->db->update($object, array("ownerid" => $ownerid)); + return true; } - $this->db->create (array ("object"=>$object, - "ownerid"=>$ownerid, - "groupid"=>$groupid, - "modbits"=>$modbits)); - return TRUE; - } + /** Change the group of an object + Need to be the ownerid of the object or the root administrator + @param string $object Object path to add + @param integer $groupid Group ID of the object + @return boolean TRUE or an exception with the error message */ + public function chgrp($object, $groupid) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + if ($this->authiduser !== 0 && !in_array($groupid, $this->authgroups)) { + throw new \Exception(dgettext( + "domframework", + "The user must be in the wanted group" + ), 405); + } + if (!in_array("WRITE", $this->validate($object))) { + throw new \Exception(sprintf(dgettext( + "domframework", + "%s is write protected" + ), $object), 405); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } - /** Remove the information about an object and all its sub-objects - @param string $object Object path to drop - @return boolean TRUE or an exception with the error message */ - public function drop ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - if ($object === "/") - throw new \Exception (dgettext ("domframework", - "The root can not be removed"), 406); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 400 + ); + } + $search = reset($search); + $this->db->update($object, array("groupid" => $groupid)); + return true; } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), - $object), 400); - - // All the folder structure is accessible. Check if we can remove the file - // in the last folder (Write modbit). Root can always write. - if ($this->authiduser === 0) + /** Change mode bits for an object + Need to be the owner of the object or the root administrator + @param string $object Object path to change + @param integer $mod Bits of authorization + @return boolean TRUE or an exception with the error message */ + public function chmod($object, $mod) { - $rc = $this->db->delete ($object); - if ($rc > 1) - throw new \Exception (dgettext ("domframework", - "Removing more than one object"), 406); - if ($rc == 0) - throw new \Exception (dgettext ("domframework", - "No object removed"), 406); - $rc = $this->db->delete ("$object$this->separator%"); - return TRUE; + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + if (!in_array("WRITE", $this->validate($object))) { + throw new \Exception(sprintf(dgettext( + "domframework", + "%s is write protected" + ), $object), 405); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 400 + ); + } + $search = reset($search); + // TODO : Don't update if the user is not the owner of the file + $this->db->update($object, array("modbits" => $modbits)); + return true; } - try + /** Return the mode bits for an object if all his parents are readable for + the user + @param string $object Object path to examine + @return int|float the modbits or an exception with the error message */ + public function lsmod($object) { - $this->treecheckWrite ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } + + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 400 + ); + } + $search = reset($search); + return octdec($search["modbits"]); } - $rc = $this->db->delete ($object); - if ($rc > 1) - throw new \Exception (dgettext ("domframework", - "Removing more than one object"), 406); - if ($rc == 0) - throw new \Exception (dgettext ("domframework", - "No object removed"), 406); - $rc = $this->db->delete ("$object$this->separator%"); - return TRUE; - } + /** Return the ownerid for an object if all his parents are readable for + the user + @param string $object Object path to examine + @return integer the ownerid or an exception with the error message */ + public function lsown($object) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } - /** Change the owner of an object - Need to be the root administrator - @param string $object Object path to add - @param integer $ownerid Owner ID of the object - @return boolean TRUE or an exception with the error message */ - public function chown ($object, $ownerid) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - if ($this->authiduser !== 0) - throw new \Exception (dgettext ("domframework", - "The chown is reserved to root user"), 405); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 400 + ); + } + $search = reset($search); + return intval($search["ownerid"]); } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 400); - $search = reset ($search); - $this->db->update ($object, array ("ownerid"=>$ownerid)); - return TRUE; - } + /** Return the groupid for an object if all his parents are readable for + the user + @param string $object Object path to examine + @return integer the groupid or an exception with the error message */ + public function lsgrp($object) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + if (substr($object, -1) === "/") { + $object = substr($object, 0, -1); + } + if (substr($object, 0, 1) !== "/") { + throw new \Exception(dgettext( + "domframework", + "Object don't start by slash" + ), 406); + } + $object = preg_replace("#//+#", "/", $object); + if ($this->authiduser === "") { + throw new \Exception(dgettext( + "domframework", + "Not authenticated" + ), 401); + } + try { + $this->treecheckExecute($object); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 405); + } - /** Change the group of an object - Need to be the ownerid of the object or the root administrator - @param string $object Object path to add - @param integer $groupid Group ID of the object - @return boolean TRUE or an exception with the error message */ - public function chgrp ($object, $groupid) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - if ($this->authiduser !== 0 && !in_array ($groupid, $this->authgroups)) - throw new \Exception (dgettext ("domframework", - "The user must be in the wanted group"), 405); - if (!in_array ("WRITE", $this->validate ($object))) - throw new \Exception (sprintf (dgettext ("domframework", - "%s is write protected"), $object), 405); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); + // All the folder structure is accessible. Check if the object already + // exists + $search = $this->db->read(array(array("object", $object))); + if (count($search) === 0) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Object %s doesn't exists" + ), $object), + 404 + ); + } + $search = reset($search); + return intval($search["groupid"]); } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 400); - $search = reset ($search); - $this->db->update ($object, array ("groupid"=>$groupid)); - return TRUE; - } - - /** Change mode bits for an object - Need to be the owner of the object or the root administrator - @param string $object Object path to change - @param integer $mod Bits of authorization - @return boolean TRUE or an exception with the error message */ - public function chmod ($object, $mod) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - if (!in_array ("WRITE", $this->validate ($object))) - throw new \Exception (sprintf (dgettext ("domframework", - "%s is write protected"), $object), 405); - try + //////////////////// + // TREE CHECK // + //////////////////// + /** Check if all the parent objects are executable + @param string $object The object to test + @return boolean TRUE or an exception in case of error */ + private function treecheckExecute($object) { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); - } + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "Database to authorize is not connected" + ), 500); + } + // Search all the parents in an array + $parents = array(); + $par = $object; + while ($par !== "/") { + $par = dirname($par); + $parents[] = $par; + } - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 400); - $search = reset ($search); - // TODO : Don't update if the user is not the owner of the file - $this->db->update ($object, array ("modbits"=>$modbits)); - return TRUE; - } - - /** Return the mode bits for an object if all his parents are readable for - the user - @param string $object Object path to examine - @return int|float the modbits or an exception with the error message */ - public function lsmod ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); - } - - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 400); - $search = reset ($search); - return octdec ($search["modbits"]); - } - - /** Return the ownerid for an object if all his parents are readable for - the user - @param string $object Object path to examine - @return integer the ownerid or an exception with the error message */ - public function lsown ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); - } - - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 400); - $search = reset ($search); - return intval ($search["ownerid"]); - } - - /** Return the groupid for an object if all his parents are readable for - the user - @param string $object Object path to examine - @return integer the groupid or an exception with the error message */ - public function lsgrp ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - if (substr ($object, -1) === "/") - $object = substr ($object, 0, -1); - if (substr ($object, 0, 1) !== "/") - throw new \Exception (dgettext ("domframework", - "Object don't start by slash"), 406); - $object = preg_replace ("#//+#", "/", $object); - if ($this->authiduser === "") - throw new \Exception (dgettext ("domframework", - "Not authenticated"), 401); - try - { - $this->treecheckExecute ($object); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), 405); - } - - // All the folder structure is accessible. Check if the object already - // exists - $search = $this->db->read (array (array ("object", $object))); - if (count ($search) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Object %s doesn't exists"), $object), - 404); - $search = reset ($search); - return intval ($search["groupid"]); - } - - //////////////////// - // TREE CHECK // - //////////////////// - /** Check if all the parent objects are executable - @param string $object The object to test - @return boolean TRUE or an exception in case of error */ - private function treecheckExecute ($object) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "Database to authorize is not connected"), 500); - // Search all the parents in an array - $parents = array (); - $par = $object; - while ($par !== "/") - { - $par = dirname ($par); - $parents[] = $par; - } - - // For each parent (folder), check if there is the right to cross (Execute - // modbit). Look at the database in one read request for all the parents. - $parents = array_reverse ($parents); - $req = "SELECT object,ownerid,groupid,modbits + // For each parent (folder), check if there is the right to cross (Execute + // modbit). Look at the database in one read request for all the parents. + $parents = array_reverse($parents); + $req = "SELECT object,ownerid,groupid,modbits FROM domframework_authorization WHERE "; - foreach ($parents as $i=>$p) - { - if ($i > 0) - $req .= " OR "; - $req .= "object='".addslashes ($p)."'"; - } - $res = $this->db->directRead ($req); - - foreach ($parents as $i=>$p) - { - $found = false; - foreach ($res as $r) - { - if ($r["object"] === $p) - { - $found = true; - break; + foreach ($parents as $i => $p) { + if ($i > 0) { + $req .= " OR "; + } + $req .= "object='" . addslashes($p) . "'"; } - } - if (!$found) - throw new \Exception (sprintf (dgettext ("domframework", - "The path %s is not found in database"), - $p), 404); - else - { - $parentOwner = intval ($r["ownerid"]); - $parentGroup = intval ($r["groupid"]); - $parentModbits = octdec ($r["modbits"]); - if ($this->authiduser === 0) - continue; - if ((($parentModbits & 0100) === 64) && - $parentOwner === $this->authiduser) - continue; - if ((($parentModbits & 0010) === 8)) - { - foreach ($this->authgroups as $tmpgrp) - { - if ($parentGroup === $tmpgrp || $tmpgrp === 0) - continue 2; - } + $res = $this->db->directRead($req); + + foreach ($parents as $i => $p) { + $found = false; + foreach ($res as $r) { + if ($r["object"] === $p) { + $found = true; + break; + } + } + if (!$found) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "The path %s is not found in database" + ), + $p + ), 404); + } else { + $parentOwner = intval($r["ownerid"]); + $parentGroup = intval($r["groupid"]); + $parentModbits = octdec($r["modbits"]); + if ($this->authiduser === 0) { + continue; + } + if ( + (($parentModbits & 0100) === 64) && + $parentOwner === $this->authiduser + ) { + continue; + } + if ((($parentModbits & 0010) === 8)) { + foreach ($this->authgroups as $tmpgrp) { + if ($parentGroup === $tmpgrp || $tmpgrp === 0) { + continue 2; + } + } + } + + if (($parentModbits & 0001) === 1) { + continue; + } + + throw new \Exception(sprintf(dgettext( + "domframework", + "No execute rights on %s" + ), $p), 405); + } + } + return true; + } + + /** Check if the parent of object is writeable + @param string $object The object to found + @return boolean TRUE or an exception */ + private function treecheckWrite($object) + { + $parent = dirname($object); + $search = $this->db->read(array(array("object", $parent))); + $search = reset($search); + $parentOwner = intval($search["ownerid"]); + $parentGroup = intval($search["groupid"]); + $parentModbits = octdec($search["modbits"]); + if ((($parentModbits & 0200) === 128) && $parentOwner === $this->authiduser) { + return true; } - if (($parentModbits & 0001) === 1) - continue; + if ((($parentModbits & 0020) === 16)) { + if ( + in_array($parentGroup, $this->authgroups) || + in_array(0, $this->authgroups) + ) { + return true; + } + } - throw new \Exception (sprintf (dgettext ("domframework", - "No execute rights on %s"), $p), 405); - } + if (($parentModbits & 0002) === 2) { + return true; + } + + throw new \Exception(sprintf(dgettext( + "domframework", + "No write rights on %s" + ), $parent), 405); } - return TRUE; - } - - /** Check if the parent of object is writeable - @param string $object The object to found - @return boolean TRUE or an exception */ - private function treecheckWrite ($object) - { - $parent = dirname ($object); - $search = $this->db->read (array (array ("object", $parent))); - $search = reset ($search); - $parentOwner = intval ($search["ownerid"]); - $parentGroup = intval ($search["groupid"]); - $parentModbits = octdec ($search["modbits"]); - if ((($parentModbits & 0200) === 128) && $parentOwner === $this->authiduser) - return TRUE; - - if ((($parentModbits & 0020) === 16)) - { - if (in_array ($parentGroup, $this->authgroups) || - in_array (0, $this->authgroups)) - return TRUE; - } - - if (($parentModbits & 0002) === 2) - return TRUE; - - throw new \Exception (sprintf (dgettext ("domframework", - "No write rights on %s"), $parent), 405); - } } diff --git a/src/Authparams.php b/src/Authparams.php index 1fc537f..f83f2f6 100644 --- a/src/Authparams.php +++ b/src/Authparams.php @@ -1,4 +1,5 @@ @@ -10,125 +11,125 @@ namespace Domframework; /** Takes the email and the password of the user */ class Authparams { - /** The email of the user when provided */ - public $email = null; - /** The password of the user when provided */ - public $password = null; - /** The method used to get the authentication data */ - public $method = null; + /** The email of the user when provided */ + public $email = null; + /** The password of the user when provided */ + public $password = null; + /** The method used to get the authentication data */ + public $method = null; - /** Parse the different authentication processes to found the email/password - * of the user. - * If non is found, return "anonymous", "anonymous" - * @param array|null $authprocesses The authentication process to use - */ - public function __construct ($authprocesses = array ("session", "post")) - { - if (php_sapi_name () === "cli") + /** Parse the different authentication processes to found the email/password + * of the user. + * If non is found, return "anonymous", "anonymous" + * @param array|null $authprocesses The authentication process to use + */ + public function __construct($authprocesses = array("session", "post")) { - $this->email = "cli"; - $this->password = ""; - $this->method = null; - } - else - { - foreach ($authprocesses as $authprocess) - { - try - { - $res = $this->$authprocess(); - $this->email = $res["email"]; - $this->password = $res["password"]; - $this->method = $authprocess; - break; + if (php_sapi_name() === "cli") { + $this->email = "cli"; + $this->password = ""; + $this->method = null; + } else { + foreach ($authprocesses as $authprocess) { + try { + $res = $this->$authprocess(); + $this->email = $res["email"]; + $this->password = $res["password"]; + $this->method = $authprocess; + break; + } catch (\Exception $e) { + $this->email = "anonymous"; + $this->password = "anonymous"; + $this->method = null; + } + } } - catch (\Exception $e) - { - $this->email = "anonymous"; - $this->password = "anonymous"; - $this->method = null; - } - } } - } - /** Get information from $POST variables - */ - public function post () - { - if (!isset ($_POST["email"]) || !isset ($_POST["password"])) - throw new \Exception ("No POST provided", 403); - return array ("email" => trim ($_POST["email"]), + /** Get information from $POST variables + */ + public function post() + { + if (!isset($_POST["email"]) || !isset($_POST["password"])) { + throw new \Exception("No POST provided", 403); + } + return array("email" => trim($_POST["email"]), "password" => $_POST["password"]); - } + } - /** Get information from previous recorded session - */ - public function session () - { - if (!isset ($_SESSION) || session_id () === "") - throw new \Exception ("No session previously enabled", 403); - if (!isset ($_SESSION["domframework"]["auth"]["email"]) || - !isset ($_SESSION["domframework"]["auth"]["password"])) - throw new \Exception ("No previous email in session", 403); - return array ("email" => $_SESSION["domframework"]["auth"]["email"], - "password" => $_SESSION["domframework"]["auth"]["password"]); - } - - /** Get information from a HTTP authentication - */ - public function http () - { - $realm = dgettext ("domframework", "Restricted access"); - if (!isset ($_SERVER['PHP_AUTH_USER'])) + /** Get information from previous recorded session + */ + public function session() { - throw new \Exception ("No user defined in HTTP header", 401); - //header("WWW-Authenticate: Basic realm=\"$realm\""); + if (!isset($_SESSION) || session_id() === "") { + throw new \Exception("No session previously enabled", 403); + } + if ( + !isset($_SESSION["domframework"]["auth"]["email"]) || + !isset($_SESSION["domframework"]["auth"]["password"]) + ) { + throw new \Exception("No previous email in session", 403); + } + return array("email" => $_SESSION["domframework"]["auth"]["email"], + "password" => $_SESSION["domframework"]["auth"]["password"]); + } + + /** Get information from a HTTP authentication + */ + public function http() + { + $realm = dgettext("domframework", "Restricted access"); + if (!isset($_SERVER['PHP_AUTH_USER'])) { + throw new \Exception("No user defined in HTTP header", 401); + //header("WWW-Authenticate: Basic realm=\"$realm\""); //header("HTTP/1.0 401 Unauthorized"); //die ($realm); - } - else - { - if (! array_key_exists ("PHP_AUTH_PW", $_SERVER)) - $_SERVER["PHP_AUTH_PW"] = null; - return array ("email" => trim ($_SERVER["PHP_AUTH_USER"]), + } else { + if (! array_key_exists("PHP_AUTH_PW", $_SERVER)) { + $_SERVER["PHP_AUTH_PW"] = null; + } + return array("email" => trim($_SERVER["PHP_AUTH_USER"]), "password" => $_SERVER["PHP_AUTH_PW"]); + } } - } - /** Get the information from a shibboleth provider - */ - public function shibboleth () - { - if (! isset ($_SERVER["Shib-Session-ID"])) - throw new \Exception ("No Shibboleth information available", 403); - if (! isset ($_SERVER["mail"])) - throw new \Exception ("No Shibboleth email provided", 403); - return array ("email" => $_SERVER["mail"], + /** Get the information from a shibboleth provider + */ + public function shibboleth() + { + if (! isset($_SERVER["Shib-Session-ID"])) { + throw new \Exception("No Shibboleth information available", 403); + } + if (! isset($_SERVER["mail"])) { + throw new \Exception("No Shibboleth email provided", 403); + } + return array("email" => $_SERVER["mail"], "password" => "NONE IN SHIBBOLETH"); - } + } - /** Get the information from a Bearer Token - * The token MUST be set in HTTP Header : - * Authentication: Bearer - * Ex in curl : - * curl -s -u "login:password" -X POST \ - * http://localhost/rest/authentication/ | jq -r - * curl -s \ - * -H "Accept: application/json" \ - * -H "Authentication: Bearer ${BearerToken}" \ - * http://localhost/rest/api/ - * The real verification are done in authjwt, as we can not have the - * jwtServerKey defined in property : the execution is done in constructor - */ - public function bearer () - { - if (! isset ($_SERVER["HTTP_AUTHENTICATION"])) - throw new \Exception ("No Authentication available", 401); - if (substr ($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") - throw new \Exception ("No Bearer Authentication available", 401); - $token = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); - return array ("email" => "NOT YET VALID : TOKEN IN JWT", + /** Get the information from a Bearer Token + * The token MUST be set in HTTP Header : + * Authentication: Bearer + * Ex in curl : + * curl -s -u "login:password" -X POST \ + * http://localhost/rest/authentication/ | jq -r + * curl -s \ + * -H "Accept: application/json" \ + * -H "Authentication: Bearer ${BearerToken}" \ + * http://localhost/rest/api/ + * The real verification are done in authjwt, as we can not have the + * jwtServerKey defined in property : the execution is done in constructor + */ + public function bearer() + { + if (! isset($_SERVER["HTTP_AUTHENTICATION"])) { + throw new \Exception("No Authentication available", 401); + } + if (substr($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") { + throw new \Exception("No Bearer Authentication available", 401); + } + $token = substr($_SERVER["HTTP_AUTHENTICATION"], 7); + return array("email" => "NOT YET VALID : TOKEN IN JWT", "password" => "NONE IN JWT"); - } + } } diff --git a/src/Authsession.php b/src/Authsession.php index 9dd08ec..9e62888 100644 --- a/src/Authsession.php +++ b/src/Authsession.php @@ -1,4 +1,5 @@ @@ -10,107 +11,126 @@ namespace Domframework; /** User authentication against SESSION */ class Authsession extends Auth { - /** Check if there is already a session or the user can not be authenticated - */ - function __construct () - { - if (!isset ($_SESSION)) - throw new \Exception ("No session previously opened", 401); - } + /** Check if there is already a session or the user can not be authenticated + */ + public function __construct() + { + if (!isset($_SESSION)) { + throw new \Exception("No session previously opened", 401); + } + } - /** No connection to session */ - public function connect () - { - return TRUE; - } + /** No connection to session */ + public function connect() + { + return true; + } - /** Try to authenticate the email/password of the user - * @param string $email Email to authenticate - * @param string $password Password to authenticate - */ - public function authentication ($email, $password) - { - if (!isset ($_SESSION["domframework"]["auth"]["email"]) || - !isset ($_SESSION["domframework"]["auth"]["password"])) - throw new \Exception ("No previous email in session", 401); - if ($_SESSION["domframework"]["auth"]["email"] !== $email) - throw new \Exception ("Unable to authenticate user '$email'", 401); - if ($_SESSION["domframework"]["auth"]["password"] !== $password) - throw new \Exception ("Bad password for '$email'", 401); - } + /** Try to authenticate the email/password of the user + * @param string $email Email to authenticate + * @param string $password Password to authenticate + */ + public function authentication($email, $password) + { + if ( + !isset($_SESSION["domframework"]["auth"]["email"]) || + !isset($_SESSION["domframework"]["auth"]["password"]) + ) { + throw new \Exception("No previous email in session", 401); + } + if ($_SESSION["domframework"]["auth"]["email"] !== $email) { + throw new \Exception("Unable to authenticate user '$email'", 401); + } + if ($_SESSION["domframework"]["auth"]["password"] !== $password) { + throw new \Exception("Bad password for '$email'", 401); + } + } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - if (! isset ($_SESSION["domframework"]["auth"]["email"])) - return array ("lastname"=>"anonymous", - "firstname"=>"", - "email"=>"anonymous"); - return array ("lastname"=>$_SESSION["domframework"]["auth"]["lastname"], - "firstname"=>$_SESSION["domframework"]["auth"]["firstname"], - "email"=>$_SESSION["domframework"]["auth"]["email"]); - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + if (! isset($_SESSION["domframework"]["auth"]["email"])) { + return array("lastname" => "anonymous", + "firstname" => "", + "email" => "anonymous"); + } + return array("lastname" => $_SESSION["domframework"]["auth"]["lastname"], + "firstname" => $_SESSION["domframework"]["auth"]["firstname"], + "email" => $_SESSION["domframework"]["auth"]["email"]); + } - /** Method to change the password : unavailable in SESSION auth - * @param string $oldpassword The old password (to check if the user have the - * rights to change the password) - * @param string $newpassword The new password to be recorded - */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for SESSION users"), - 405); - } + /** Method to change the password : unavailable in SESSION auth + * @param string $oldpassword The old password (to check if the user have the + * rights to change the password) + * @param string $newpassword The new password to be recorded + */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be change for SESSION users" + ), + 405 + ); + } - /** Method to overwrite the password (without oldpassword check) - * Must be reserved to the administrators. For the users, use changepassword - * method - * @param string $email the user identifier to select - * @param string $newpassword The new password to be recorded - */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite for SESSION users"), - 405); - } + /** Method to overwrite the password (without oldpassword check) + * Must be reserved to the administrators. For the users, use changepassword + * method + * @param string $email the user identifier to select + * @param string $newpassword The new password to be recorded + */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be overwrite for SESSION users" + ), + 405 + ); + } - /** Save the data in session - * @param string $email The email to store in the session - * @param string $password The password to store in the session - * @param string $lastname The lastname to store in the session - * @param string $firstname The firstname to store in the session - * @deprecated 0.23 */ - public function savedatas ($email, $password, $lastname, $firstname) - { - return $this->savedata ($email, $password, $lastname, $firstname); - } + /** Save the data in session + * @param string $email The email to store in the session + * @param string $password The password to store in the session + * @param string $lastname The lastname to store in the session + * @param string $firstname The firstname to store in the session + * @deprecated 0.23 */ + public function savedatas($email, $password, $lastname, $firstname) + { + return $this->savedata($email, $password, $lastname, $firstname); + } - /** Save the data in session - * @param string $email The email to store in the session - * @param string $password The password to store in the session - * @param string $lastname The lastname to store in the session - * @param string $firstname The firstname to store in the session - */ - public function savedata ($email, $password, $lastname, $firstname) - { - $_SESSION["domframework"]["auth"]["lastname"] = $lastname; - $_SESSION["domframework"]["auth"]["firstname"] = $firstname; - $_SESSION["domframework"]["auth"]["email"] = $email; - $_SESSION["domframework"]["auth"]["password"] = $password; - } + /** Save the data in session + * @param string $email The email to store in the session + * @param string $password The password to store in the session + * @param string $lastname The lastname to store in the session + * @param string $firstname The firstname to store in the session + */ + public function savedata($email, $password, $lastname, $firstname) + { + $_SESSION["domframework"]["auth"]["lastname"] = $lastname; + $_SESSION["domframework"]["auth"]["firstname"] = $firstname; + $_SESSION["domframework"]["auth"]["email"] = $email; + $_SESSION["domframework"]["auth"]["password"] = $password; + } - /** Remove the information from the session */ - public function logout () - { - if (isset ($_SESSION["domframework"]["auth"]["lastname"])) - unset ($_SESSION["domframework"]["auth"]["lastname"]); - if (isset ($_SESSION["domframework"]["auth"]["firstname"])) - unset ($_SESSION["domframework"]["auth"]["firstname"]); - if (isset ($_SESSION["domframework"]["auth"]["email"])) - unset ($_SESSION["domframework"]["auth"]["email"]); - if (isset ($_SESSION["domframework"]["auth"]["password"])) - unset ($_SESSION["domframework"]["auth"]["password"]); - } + /** Remove the information from the session */ + public function logout() + { + if (isset($_SESSION["domframework"]["auth"]["lastname"])) { + unset($_SESSION["domframework"]["auth"]["lastname"]); + } + if (isset($_SESSION["domframework"]["auth"]["firstname"])) { + unset($_SESSION["domframework"]["auth"]["firstname"]); + } + if (isset($_SESSION["domframework"]["auth"]["email"])) { + unset($_SESSION["domframework"]["auth"]["email"]); + } + if (isset($_SESSION["domframework"]["auth"]["password"])) { + unset($_SESSION["domframework"]["auth"]["password"]); + } + } } diff --git a/src/Authshibboleth.php b/src/Authshibboleth.php index 56b9925..6aeed93 100644 --- a/src/Authshibboleth.php +++ b/src/Authshibboleth.php @@ -1,4 +1,5 @@ @@ -10,96 +11,107 @@ namespace Domframework; /** User authentication against Shibboleth */ class Authshibboleth extends Auth { - /** The Lastname parameter returned by Shibboleth server */ - public $lastnameParam = "sn"; - /** The Firstname parameter returned by Shibboleth server */ - public $firstnameParam = "givenName"; - /** The mail parameter returned by Shibboleth server */ - public $mailParam = "mail"; - /** The others parameters returned by Shibboleth server */ - public $otherFields = array ("ou", "o"); - /** The optional URL use to authenticate the users */ - public $urlAuthentificated = ""; - /** The optional URL to disconnect the users */ - public $urlLogout = ""; - /** The optional URL to change the user password */ - public $urlPasswd = ""; + /** The Lastname parameter returned by Shibboleth server */ + public $lastnameParam = "sn"; + /** The Firstname parameter returned by Shibboleth server */ + public $firstnameParam = "givenName"; + /** The mail parameter returned by Shibboleth server */ + public $mailParam = "mail"; + /** The others parameters returned by Shibboleth server */ + public $otherFields = array("ou", "o"); + /** The optional URL use to authenticate the users */ + public $urlAuthentificated = ""; + /** The optional URL to disconnect the users */ + public $urlLogout = ""; + /** The optional URL to change the user password */ + public $urlPasswd = ""; - /** No connection to shibboleth */ - public function connect () - { - return TRUE; - } - - /** Try to authenticate the email/password of the user - @param string $email Email to authenticate - @param string $password Password to authenticate */ - public function authentication ($email, $password) - { - if (!isset ($_SERVER["mail"])) + /** No connection to shibboleth */ + public function connect() { - if ($this->urlAuthentificated !== "") - { - $route = new Route (); - $route->redirect ($this->urlAuthentificated); - } - throw new \Exception ("Unable to authenticate user '$email'", 401); + return true; } - } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - if (! isset ($_SERVER[$this->mailParam])) - return array ("lastname"=>"anonymous", - "firstname"=>"", - "email"=>"anonymous"); - $res = array ("lastname"=>$_SERVER[$this->lastnameParam], - "firstname"=>$_SERVER[$this->firstnameParam], - "email"=>$_SERVER[$this->mailParam]); - foreach ($this->otherFields as $field) + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + public function authentication($email, $password) { - if (array_key_exists ($field, $_SERVER)) - $res[$field] = $_SERVER[$field]; + if (!isset($_SERVER["mail"])) { + if ($this->urlAuthentificated !== "") { + $route = new Route(); + $route->redirect($this->urlAuthentificated); + } + throw new \Exception("Unable to authenticate user '$email'", 401); + } } - return $res; - } - /** Method to change the password : unavailable in SESSION auth - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - // Redirect to Shibboleth IDP - if ($this->urlPasswdChange == "") - throw new \Exception (dgettext ("domframework", - "The password can't be change for Shibboleth users"), - 405); - $route = new Route (); - $route->redirect ($this->urlPasswdChange); - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + if (! isset($_SERVER[$this->mailParam])) { + return array("lastname" => "anonymous", + "firstname" => "", + "email" => "anonymous"); + } + $res = array("lastname" => $_SERVER[$this->lastnameParam], + "firstname" => $_SERVER[$this->firstnameParam], + "email" => $_SERVER[$this->mailParam]); + foreach ($this->otherFields as $field) { + if (array_key_exists($field, $_SERVER)) { + $res[$field] = $_SERVER[$field]; + } + } + return $res; + } - /** Method to overwrite the password (without oldpassword check) - Must be reserved to the administrators. For the users, use changepassword - method - @param string $email the user identifier to select - @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite for Shibboleth users"), - 405); - } + /** Method to change the password : unavailable in SESSION auth + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + // Redirect to Shibboleth IDP + if ($this->urlPasswdChange == "") { + throw new \Exception( + dgettext( + "domframework", + "The password can't be change for Shibboleth users" + ), + 405 + ); + } + $route = new Route(); + $route->redirect($this->urlPasswdChange); + } - /** Remove the information from the session */ - public function logout () - { - // Redirect to Shibboleth IDP - if ($this->urlLogout === "") - throw new \Exception (dgettext ("domframework", - "Shibboleth is not configured to allow logout"), 405); - $route = new Route (); - $route->redirect ($this->urlLogout); - } + /** Method to overwrite the password (without oldpassword check) + Must be reserved to the administrators. For the users, use changepassword + method + @param string $email the user identifier to select + @param string $newpassword The new password to be recorded */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be overwrite for Shibboleth users" + ), + 405 + ); + } + + /** Remove the information from the session */ + public function logout() + { + // Redirect to Shibboleth IDP + if ($this->urlLogout === "") { + throw new \Exception(dgettext( + "domframework", + "Shibboleth is not configured to allow logout" + ), 405); + } + $route = new Route(); + $route->redirect($this->urlLogout); + } } diff --git a/src/Authsql.php b/src/Authsql.php index 715a3ae..1630419 100644 --- a/src/Authsql.php +++ b/src/Authsql.php @@ -1,4 +1,5 @@ @@ -10,196 +11,284 @@ namespace Domframework; /** User authentication against SQL database */ class Authsql extends Auth { - /** The DSN to use to connect to SQL database */ - public $dsn = null; - /** The username to connect to the database */ - public $username = null; - /** The password to use to connecto to the database */ - public $password = null; - /** The driver options for the PDO driver */ - public $driver_options = null; - /** The table name to use */ - public $table = null; - /** The tableprefix text to prepend to table name (Should finish by _) - Just allow chars ! */ - public $tableprefix = ""; - /** The password field name */ - public $fieldPassword = "password"; - /** The identifier field name (maybe email) */ - public $fieldIdentifier = "email"; - /** The field name containing the lastname of the user */ - public $fieldLastname = null; - /** The field name containing the Firstname of the user */ - public $fieldFirstname = null; - /** The information fields (in an array) */ - public $fieldsInfo = array (); + public $dsn = null; + /** The username to connect to the database */ + public $username = null; + /** The password to use to connecto to the database */ + public $password = null; + /** The driver options for the PDO driver */ + public $driver_options = null; + /** The table name to use */ + public $table = null; + /** The tableprefix text to prepend to table name (Should finish by _) + Just allow chars ! */ + public $tableprefix = ""; + /** The password field name */ + public $fieldPassword = "password"; + /** The identifier field name (maybe email) */ + public $fieldIdentifier = "email"; + /** The field name containing the lastname of the user */ + public $fieldLastname = null; + /** The field name containing the Firstname of the user */ + public $fieldFirstname = null; + /** The information fields (in an array) */ + public $fieldsInfo = array(); - /** The DBLayer pointer */ - private $db = null; - /** The details of the authenticated user */ - private $details = null; + /** The DBLayer pointer */ + private $db = null; + /** The details of the authenticated user */ + private $details = null; - /** Establish a connection to a SQL server */ - public function connect () - { - if (! function_exists ("openssl_random_pseudo_bytes")) - throw new \Exception (dgettext ("domframework", - "No PHP support for openssl_random_pseudo_bytes"), - 500); - $this->db = new Dblayer ($this->dsn, $this->username, $this->password, - $this->driver_options); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", "No SQL table defined"), - 500); - if ($this->fieldIdentifier === null) - throw new \Exception (dgettext ("domframework", - "No fieldIdentifier defined"), 500); - if ($this->fieldPassword === null) - throw new \Exception (dgettext ("domframework", - "No fieldPassword defined"), 500); - if ($this->fieldLastname === null) - throw new \Exception (dgettext ("domframework", - "No fieldLastname defined"), 500); - if ($this->fieldFirstname === null) - throw new \Exception (dgettext ("domframework", - "No fieldFirstname defined"), 500); - $fields = array_merge (array ($this->fieldIdentifier, $this->fieldPassword, + /** Establish a connection to a SQL server */ + public function connect() + { + if (! function_exists("openssl_random_pseudo_bytes")) { + throw new \Exception( + dgettext( + "domframework", + "No PHP support for openssl_random_pseudo_bytes" + ), + 500 + ); + } + $this->db = new Dblayer( + $this->dsn, + $this->username, + $this->password, + $this->driver_options + ); + if ($this->table === null) { + throw new \Exception( + dgettext("domframework", "No SQL table defined"), + 500 + ); + } + if ($this->fieldIdentifier === null) { + throw new \Exception(dgettext( + "domframework", + "No fieldIdentifier defined" + ), 500); + } + if ($this->fieldPassword === null) { + throw new \Exception(dgettext( + "domframework", + "No fieldPassword defined" + ), 500); + } + if ($this->fieldLastname === null) { + throw new \Exception(dgettext( + "domframework", + "No fieldLastname defined" + ), 500); + } + if ($this->fieldFirstname === null) { + throw new \Exception(dgettext( + "domframework", + "No fieldFirstname defined" + ), 500); + } + $fields = array_merge( + array($this->fieldIdentifier, $this->fieldPassword, $this->fieldLastname, $this->fieldFirstname), - $this->fieldsInfo); - $fields = array_flip ($fields); - foreach ($fields as $key=>$val) - $fields[$key] = array ("varchar", "255"); - $this->db->table = $this->table; - $this->db->fields = $fields; - $this->db->primary = $this->fieldIdentifier; - } + $this->fieldsInfo + ); + $fields = array_flip($fields); + foreach ($fields as $key => $val) { + $fields[$key] = array("varchar", "255"); + } + $this->db->table = $this->table; + $this->db->fields = $fields; + $this->db->primary = $this->fieldIdentifier; + } - /** Try to authenticate the email/password of the user - @param string $email Email to authenticate - @param string $password Password to authenticate */ - public function authentication ($email, $password) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "The SQL database is not connected"), 500); - $data = $this->db->read (array (array ($this->fieldIdentifier, $email)), - array_merge (array ($this->fieldIdentifier, + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + public function authentication($email, $password) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "The SQL database is not connected" + ), 500); + } + $data = $this->db->read( + array(array($this->fieldIdentifier, $email)), + array_merge( + array($this->fieldIdentifier, $this->fieldFirstname, $this->fieldLastname, $this->fieldPassword), - $this->fieldsInfo)); - if (count ($data) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Unable to find the user : '%s'"), - $email), 401); - if (! isset ($data[0][$this->fieldPassword])) - throw new \Exception (dgettext ("domframework", - "Unable to get the user password from database"), - 500); - $cryptedPassword = $data[0][$this->fieldPassword]; - if (crypt ($password, $cryptedPassword) !== $cryptedPassword) - throw new \Exception (sprintf (dgettext ("domframework", - "Bad password for '%s'"), $email), - 401); - // The password should never be stored by this function - unset ($data[0][$this->fieldPassword]); - $content = $data[0]; - $content["email"] = $data[0][$this->fieldIdentifier]; - $content["lastname"] = $data[0][$this->fieldLastname]; - $content["firstname"] = $data[0][$this->fieldFirstname]; - $this->details = $content; - } + $this->fieldsInfo + ) + ); + if (count($data) === 0) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unable to find the user : '%s'" + ), + $email + ), 401); + } + if (! isset($data[0][$this->fieldPassword])) { + throw new \Exception( + dgettext( + "domframework", + "Unable to get the user password from database" + ), + 500 + ); + } + $cryptedPassword = $data[0][$this->fieldPassword]; + if (crypt($password, $cryptedPassword) !== $cryptedPassword) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Bad password for '%s'" + ), $email), + 401 + ); + } + // The password should never be stored by this function + unset($data[0][$this->fieldPassword]); + $content = $data[0]; + $content["email"] = $data[0][$this->fieldIdentifier]; + $content["lastname"] = $data[0][$this->fieldLastname]; + $content["firstname"] = $data[0][$this->fieldFirstname]; + $this->details = $content; + } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - return $this->details; - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + return $this->details; + } - /** Method to change the password - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "The SQL database is not connected"), 500); - if ($this->details === null || - ! isset ($this->details[$this->fieldIdentifier])) - throw new \Exception (dgettext ("domframework", - "Can't change the password if the user is not authenticated"), - 500); - $data = $this->db->read (array (array ($this->fieldIdentifier, + /** Method to change the password + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "The SQL database is not connected" + ), 500); + } + if ( + $this->details === null || + ! isset($this->details[$this->fieldIdentifier]) + ) { + throw new \Exception( + dgettext( + "domframework", + "Can't change the password if the user is not authenticated" + ), + 500 + ); + } + $data = $this->db->read( + array(array($this->fieldIdentifier, $this->details[$this->fieldIdentifier])), - array ($this->fieldIdentifier, - $this->fieldPassword)); - $cryptedPassword = $data[0][$this->fieldPassword]; - if (crypt ($oldpassword, $cryptedPassword) !== $cryptedPassword) - throw new \Exception (dgettext ("domframework", - "Bad old password provided"), 401); - $cost = 11; - $salt = substr (base64_encode (openssl_random_pseudo_bytes (17)), 0, 22); - $salt = str_replace ("+", ".", $salt); - $param = '$'.implode('$', array( + array($this->fieldIdentifier, + $this->fieldPassword) + ); + $cryptedPassword = $data[0][$this->fieldPassword]; + if (crypt($oldpassword, $cryptedPassword) !== $cryptedPassword) { + throw new \Exception(dgettext( + "domframework", + "Bad old password provided" + ), 401); + } + $cost = 11; + $salt = substr(base64_encode(openssl_random_pseudo_bytes(17)), 0, 22); + $salt = str_replace("+", ".", $salt); + $param = '$' . implode('$', array( "2y", //select the most secure version of blowfish (>=PHP 5.3.7) - str_pad ($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits + str_pad($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits $salt //add the salt - )); - //now do the actual hashing - $cryptpassword = crypt ($newpassword, $param); - $rc = $this->db->update ($this->details[$this->fieldIdentifier], - array ($this->fieldPassword => $cryptpassword)); - if ($rc !== 1) - throw new \Exception (dgettext ("domframework", - "Can't change the password"), 500); - } + )); + //now do the actual hashing + $cryptpassword = crypt($newpassword, $param); + $rc = $this->db->update( + $this->details[$this->fieldIdentifier], + array($this->fieldPassword => $cryptpassword) + ); + if ($rc !== 1) { + throw new \Exception(dgettext( + "domframework", + "Can't change the password" + ), 500); + } + } - /** Method to overwrite the password (without oldpassword check) - Must be reserved to the administrators. For the users, use changepassword - method - @param string $email the user identifier to select - @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "The SQL database is not connected"), 500); - $data = $this->db->read (array (array ($this->fieldIdentifier, $email)), - array ($this->fieldIdentifier, - $this->fieldPassword)); - if (count ($data) === 0) - throw new \Exception (sprintf (dgettext ("domframework", - "Unable to find the user : '%s'"), - $email), 401); - $cost = 11; - $salt = substr (base64_encode (openssl_random_pseudo_bytes (17)), 0, 22); - $salt = str_replace ("+", ".", $salt); - $param = '$'. implode ('$', array ( + /** Method to overwrite the password (without oldpassword check) + Must be reserved to the administrators. For the users, use changepassword + method + @param string $email the user identifier to select + @param string $newpassword The new password to be recorded */ + public function overwritepassword($email, $newpassword) + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "The SQL database is not connected" + ), 500); + } + $data = $this->db->read( + array(array($this->fieldIdentifier, $email)), + array($this->fieldIdentifier, + $this->fieldPassword) + ); + if (count($data) === 0) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unable to find the user : '%s'" + ), + $email + ), 401); + } + $cost = 11; + $salt = substr(base64_encode(openssl_random_pseudo_bytes(17)), 0, 22); + $salt = str_replace("+", ".", $salt); + $param = '$' . implode('$', array( "2y", //select the most secure version of blowfish (>=PHP 5.3.7) - str_pad ($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits + str_pad($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits $salt //add the salt - )); - //now do the actual hashing - $cryptpassword = crypt ($newpassword, $param); - $rc = $this->db->update ($email, - array ($this->fieldPassword => $cryptpassword)); - if ($rc !== 1) - throw new \Exception (dgettext ("domframework", - "Can't change the password"), 500); - } - /** List all the users available in the database - Return firstname, lastname, mail, with mail is an array */ - public function listusers () - { - if ($this->db === null) - throw new \Exception (dgettext ("domframework", - "The SQL database is not connected"), 500); - $data = $this->db->read (null, array_merge (array ($this->fieldIdentifier, + )); + //now do the actual hashing + $cryptpassword = crypt($newpassword, $param); + $rc = $this->db->update( + $email, + array($this->fieldPassword => $cryptpassword) + ); + if ($rc !== 1) { + throw new \Exception(dgettext( + "domframework", + "Can't change the password" + ), 500); + } + } + /** List all the users available in the database + Return firstname, lastname, mail, with mail is an array */ + public function listusers() + { + if ($this->db === null) { + throw new \Exception(dgettext( + "domframework", + "The SQL database is not connected" + ), 500); + } + $data = $this->db->read(null, array_merge( + array($this->fieldIdentifier, $this->fieldFirstname, $this->fieldLastname), - $this->fieldsInfo)); - return $data; - } + $this->fieldsInfo + )); + return $data; + } } diff --git a/src/Authsympa.php b/src/Authsympa.php index 1abd039..4a945ed 100644 --- a/src/Authsympa.php +++ b/src/Authsympa.php @@ -1,4 +1,5 @@ @@ -25,89 +26,121 @@ var_dump ($auth->authentication ("user@domain.tld", "Pa$$word!")); */ class Authsympa extends Auth { - /** URL of the WSDL Sympa server */ - public $wsdl = null; - /** Mailling list to be checked if user is present */ - public $list = null; - /** Function of the user in the mailling list - can be subscriber, owner, editor */ - public $function = "subscriber"; + /** URL of the WSDL Sympa server */ + public $wsdl = null; + /** Mailling list to be checked if user is present */ + public $list = null; + /** Function of the user in the mailling list + can be subscriber, owner, editor */ + public $function = "subscriber"; - /** Soap Client identifier */ - private $client = null; - /** Temporary auth key used betwwen commands */ - private $authkey = null; - /** Email of the user if the authentication is correct */ - private $details = null; + /** Soap Client identifier */ + private $client = null; + /** Temporary auth key used betwwen commands */ + private $authkey = null; + /** Email of the user if the authentication is correct */ + private $details = null; - /** Check if the SOAP module is available in PHP */ - public function __construct () - { - if (! class_exists ("SoapClient")) - throw new \Exception (dgettext ("domframework", - "No SOAP PHP library available"), 500); - } + /** Check if the SOAP module is available in PHP */ + public function __construct() + { + if (! class_exists("SoapClient")) { + throw new \Exception(dgettext( + "domframework", + "No SOAP PHP library available" + ), 500); + } + } - /** Connect to the Sympa server */ - public function connect () - { - if ($this->wsdl === null) - throw new \Exception (dgettext ("domframework", - "No WSDL provided to Sympa auth"), 401); - $this->client = new \SoapClient($this->wsdl); - } + /** Connect to the Sympa server */ + public function connect() + { + if ($this->wsdl === null) { + throw new \Exception(dgettext( + "domframework", + "No WSDL provided to Sympa auth" + ), 401); + } + $this->client = new \SoapClient($this->wsdl); + } - /** Try to authenticate the email/password of the user - @param string $email Email to authenticate - @param string $password Password to authenticate */ - public function authentication ($email, $password) - { - if ($this->client === null) - throw new \Exception (dgettext ("domframework", - "The SOAP connection is not opened"), 401); - if ($this->list === null) - throw new \Exception (dgettext ("domframework", - "The list to check is not defined"), 401); - $this->authkey = $this->client->login ($email, $password); - if ($this->authkey === null) - throw new \Exception (dgettext ("domframework", - "Can't connect with provided email/password to sympa"), - 401); - $rc = $this->client->authenticateAndRun ($email, $this->authkey, - 'amI', array ($this->list, $this->function, $email)); - if ($rc === null || $rc === false) - throw new \Exception (dgettext ("domframework", - "User not in Sympa list or bad password"), 401); - $this->details = array ("email"=>$email); - return $rc; - } + /** Try to authenticate the email/password of the user + @param string $email Email to authenticate + @param string $password Password to authenticate */ + public function authentication($email, $password) + { + if ($this->client === null) { + throw new \Exception(dgettext( + "domframework", + "The SOAP connection is not opened" + ), 401); + } + if ($this->list === null) { + throw new \Exception(dgettext( + "domframework", + "The list to check is not defined" + ), 401); + } + $this->authkey = $this->client->login($email, $password); + if ($this->authkey === null) { + throw new \Exception( + dgettext( + "domframework", + "Can't connect with provided email/password to sympa" + ), + 401 + ); + } + $rc = $this->client->authenticateAndRun( + $email, + $this->authkey, + 'amI', + array($this->list, $this->function, $email) + ); + if ($rc === null || $rc === false) { + throw new \Exception(dgettext( + "domframework", + "User not in Sympa list or bad password" + ), 401); + } + $this->details = array("email" => $email); + return $rc; + } - /** Return all the parameters recorded for the authenticate user */ - public function getdetails () - { - return $this->details; - } + /** Return all the parameters recorded for the authenticate user */ + public function getdetails() + { + return $this->details; + } - /** Method to change the password - @param string $oldpassword The old password (to check if the user have the - rights to change the password) - @param string $newpassword The new password to be recorded */ - public function changepassword ($oldpassword, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be change for SYMPA users"), - 405); - } + /** Method to change the password + @param string $oldpassword The old password (to check if the user have the + rights to change the password) + @param string $newpassword The new password to be recorded */ + public function changepassword($oldpassword, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be change for SYMPA users" + ), + 405 + ); + } - /** Method to overwrite the password (without oldpassword check) - Must be reserved to the administrators. For the users, use changepassword - method - @param string $email the user identifier to select - @param string $newpassword The new password to be recorded */ - public function overwritepassword ($email, $newpassword) - { - throw new \Exception (dgettext ("domframework", - "The password can't be overwrite for Sympa users"), - 405); - } + /** Method to overwrite the password (without oldpassword check) + Must be reserved to the administrators. For the users, use changepassword + method + @param string $email the user identifier to select + @param string $newpassword The new password to be recorded */ + public function overwritepassword($email, $newpassword) + { + throw new \Exception( + dgettext( + "domframework", + "The password can't be overwrite for Sympa users" + ), + 405 + ); + } } diff --git a/src/Authzgroups.php b/src/Authzgroups.php index 65b3556..ad0a6bf 100644 --- a/src/Authzgroups.php +++ b/src/Authzgroups.php @@ -1,4 +1,5 @@ @@ -11,1211 +12,1558 @@ namespace Domframework; user by its groups membership */ class Authzgroups { - /** The table prefix to use */ - public $tableprefix = ""; - /** The dblayer object use to manage the Object table */ - private $dbObject = null; - /** The dblayer object use to manage the Group table */ - private $dbGroup = null; - /** The dblayer object use to manage the GroupMember table */ - private $dbGroupMember = null; - /** The dblayer object use to manage the Right table */ - private $dbRight = null; - /** Set the debug level */ - public $debug = 0; - /** A local cache of the rights if multiple tests are needed */ - private $rightCache = null; + /** The table prefix to use */ + public $tableprefix = ""; + /** The dblayer object use to manage the Object table */ + private $dbObject = null; + /** The dblayer object use to manage the Group table */ + private $dbGroup = null; + /** The dblayer object use to manage the GroupMember table */ + private $dbGroupMember = null; + /** The dblayer object use to manage the Right table */ + private $dbRight = null; + /** Set the debug level */ + public $debug = 0; + /** A local cache of the rights if multiple tests are needed */ + private $rightCache = null; - ///////////////////// - // USER RIGHTS // - ///////////////////// - /** Return an array with all the rights of the user in the module. - * Cache this information to be quicker with next requests - * Remove the entries where path is not at least readable - * @param string $module The module to use - * @param string $user The user to get the rights - */ - public function userrightsget ($module, $user) - { + ///////////////////// + // USER RIGHTS // + ///////////////////// + /** Return an array with all the rights of the user in the module. + * Cache this information to be quicker with next requests + * Remove the entries where path is not at least readable + * @param string $module The module to use + * @param string $user The user to get the rights + */ + public function userrightsget($module, $user) + { // if (isset ($_SESSION["domframework"]["authzgroups"][$module][$user])) // return $_SESSION["domframework"]["authzgroups"][$module][$user]; - if ($this->rightCache !== null) - return $this->rightCache; - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - // Do the SQL request in hard to be more performant on jointures - if ($user === "cli" || $user === "root") - { - $req = "SELECT o.object,'2' AS right - FROM ".$this->tableprefix."authzobject AS o + if ($this->rightCache !== null) { + return $this->rightCache; + } + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + // Do the SQL request in hard to be more performant on jointures + if ($user === "cli" || $user === "root") { + $req = "SELECT o.object,'2' AS right + FROM " . $this->tableprefix . "authzobject AS o WHERE o.module=:module"; - } - else - { - $req = "SELECT o.object,MAX(r.right) AS \"right\" - FROM ".$this->tableprefix."authzright AS r, - ".$this->tableprefix."authzobject AS o, - ".$this->tableprefix."authzgroup AS g, - ".$this->tableprefix."authzgroupmember AS gm + } else { + $req = "SELECT o.object,MAX(r.right) AS \"right\" + FROM " . $this->tableprefix . "authzright AS r, + " . $this->tableprefix . "authzobject AS o, + " . $this->tableprefix . "authzgroup AS g, + " . $this->tableprefix . "authzgroupmember AS gm WHERE r.idgroup=g.idgroup AND r.idobject=o.idobject AND gm.idgroup=g.idgroup AND gm.user=:user AND g.module=:module GROUP BY o.object ORDER BY o.object"; + } + + if ($this->debug) { + echo "$req\n"; + } + try { + $st = $this->dbObject->prepare($req); + } catch (\Exception $e) { + if ($this->dbObject->debug) { + echo "DEBUG : PREPARE ERROR ! Return FALSE" . + $e->getMessage() . "\n"; + } + throw new \Exception($e->getMessage(), 500); + } + + if ($user !== "cli" && $user !== "root") { + $st->bindValue(":user", $user); + } + $st->bindValue(":module", $module); + try { + $rc = $st->execute(); + if ($rc === false) { + throw new \Exception("Can't execute SQL request", 500); + } + } catch (\Exception $e) { + if ($this->dbObject->debug) { + echo "DEBUG : EXECUTE ERROR ! Return FALSE" . + $e->getMessage() . "\n"; + } + throw new \Exception($e->getMessage(), 500); + } + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[$d["object"]] = $d["right"]; + } + // Transform the numerical rights to RO/RW + foreach ($res as $k => $r) { + switch ($r) { + case "2": + $res[$k] = "RW"; + break; + case "1": + $res[$k] = "RO"; + break; + default: + throw new \Exception(dgettext( + "domframework", + "Unknown right stored" + ), 500); + } + } + if (isset($_SESSION)) { + $_SESSION["domframework"]["authzgroups"][$module][$user] = $res; + } + $this->rightCache = $res; + return $res; } - if ($this->debug) echo "$req\n"; - try + /** Return the right defined for this user in the module for one object + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to return the rights for the user + */ + public function allow($module, $user, $object) { - $st = $this->dbObject->prepare ($req); - } - catch (\Exception $e) - { - if ($this->dbObject->debug) echo "DEBUG : PREPARE ERROR ! Return FALSE". - $e->getMessage()."\n"; - throw new \Exception ($e->getMessage(), 500); + $ressource = $this->userrightsget($module, $user); + // The complete tree should not be readable for the user : it can have + // access to a card, but not to all the cards (group -> reject, + // group/XXX->allow) + /*// Limit to allowed trees : if a member of the path is not recorded (is + // unreadable), return NO. + // Can be the last entry (the complete object) too + $path = explode ("/", $object); + $completePath = "/"; + foreach ($path as $k=>$p) + { + if ($k>1) + $completePath .= "/"; + $completePath .= "$p"; + if (! isset ($ressource[$completePath])) + { + if ($this->debug) + echo "DEBUG allow : REJECT because $completePath is not found\n"; + return "NO"; + } + }*/ + if (! isset($ressource[$object])) { + return "NO"; + } + return $ressource[$object]; } - if ($user !== "cli" && $user !== "root") - $st->bindValue (":user", $user); - $st->bindValue (":module", $module); - try + /** Return TRUE if the user right allow to see the object (RO or RW) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessRight($module, $user, $object) { - $rc = $st->execute (); - if ($rc === false) - throw new \Exception ("Can't execute SQL request", 500); - } - catch (\Exception $e) - { - if ($this->dbObject->debug) echo "DEBUG : EXECUTE ERROR ! Return FALSE". - $e->getMessage()."\n"; - throw new \Exception ($e->getMessage(), 500); - } - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[$d["object"]] = $d["right"]; - // Transform the numerical rights to RO/RW - foreach ($res as $k=>$r) - { - switch ($r) - { - case "2": $res[$k] = "RW"; break; - case "1": $res[$k] = "RO"; break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right stored"), 500); - } - } - if (isset ($_SESSION)) - $_SESSION["domframework"]["authzgroups"][$module][$user] = $res; - $this->rightCache = $res; - return $res; - } - - /** Return the right defined for this user in the module for one object - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to return the rights for the user - */ - public function allow ($module, $user, $object) - { - $ressource = $this->userrightsget ($module, $user); - // The complete tree should not be readable for the user : it can have - // access to a card, but not to all the cards (group -> reject, - // group/XXX->allow) - /*// Limit to allowed trees : if a member of the path is not recorded (is - // unreadable), return NO. - // Can be the last entry (the complete object) too - $path = explode ("/", $object); - $completePath = "/"; - foreach ($path as $k=>$p) - { - if ($k>1) - $completePath .= "/"; - $completePath .= "$p"; - if (! isset ($ressource[$completePath])) - { - if ($this->debug) - echo "DEBUG allow : REJECT because $completePath is not found\n"; - return "NO"; - } - }*/ - if (! isset ($ressource[$object])) - return "NO"; - return $ressource[$object]; - } - - /** Return TRUE if the user right allow to see the object (RO or RW) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessRight ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessRight without ". + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessRight without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ("Module not provided to authzgroups\\accessRight", - 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessright", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ("Object not provided to authzgroups\\accessRight", - 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, "$object"); - if ($this->debug) - trigger_error ("authzgroups : accessRight ('$module', '$user', ". - "'$object')=$rc", E_USER_NOTICE); - if ($rc !== "NO") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Access forbidden"), 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessRight", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessright", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessRight", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, "$object"); + if ($this->debug) { + trigger_error("authzgroups : accessRight ('$module', '$user', " . + "'$object')=$rc", E_USER_NOTICE); + } + if ($rc !== "NO") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception(dgettext("domframework", "Access forbidden"), 403); + } - /** Return TRUE if the user right allow to edit the object (RW only) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessWrite ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessWrite without ". + /** Return TRUE if the user right allow to edit the object (RW only) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessWrite($module, $user, $object) + { + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessWrite without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ("Module not provided to authzgroups\\accessWrite", - 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessWrite", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ("Object not provided to authzgroups\\accessWrite", - 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, $object); - if ($this->debug) - trigger_error ("authzgroups : accessWrite ('$module', '$user', ". - "'$object')=$rc", E_USER_NOTICE); - if ($rc === "RW") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Modification forbidden"), - 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, $object); + if ($this->debug) { + trigger_error("authzgroups : accessWrite ('$module', '$user', " . + "'$object')=$rc", E_USER_NOTICE); + } + if ($rc === "RW") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception( + dgettext("domframework", "Modification forbidden"), + 403 + ); + } - /** Return TRUE if the user right allow to see but without modification - * the object (RO only) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessReadOnly ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessReadOnly without ". + /** Return TRUE if the user right allow to see but without modification + * the object (RO only) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessReadOnly($module, $user, $object) + { + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessReadOnly without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ("Module not provided to authzgroups\\accessReadOnly", - 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessReadOnly", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ("Object not provided to authzgroups\\accessReadOnly", - 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, $object); - if ($this->debug) - trigger_error ("authzgroups : accessReadOnly ('$module', '$user', ". - "'$object')" ."=$rc", E_USER_NOTICE); - if ($rc === "RO") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Access forbidden"), 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, $object); + if ($this->debug) { + trigger_error("authzgroups : accessReadOnly ('$module', '$user', " . + "'$object')" . "=$rc", E_USER_NOTICE); + } + if ($rc === "RO") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception(dgettext("domframework", "Access forbidden"), 403); + } - ///////////////////////// - // DATABASE STORAGE // - ///////////////////////// - /** Connect to the database before using it - * @param string $dsn The DSN to use to connect to the database - * @param string|null $username The username to use to connect to the - * database - * @param string|null $password The password to use to connect to the - * database - * @param array|null $driver_options The options to pass to PDO driver - */ - public function connect ($dsn, $username=null, $password=null, - $driver_options=null) - { - $this->dbObject = new Dblayer ($dsn, $username, $password, $driver_options); - $this->dbObject->debug = $this->debug; - $this->dbObject->table = "authzobject"; - $this->dbObject->prefix = $this->tableprefix; - $this->dbObject->fields = array ( - "idobject" => array ("integer", "not null", "autoincrement"), - "module" => array ("varchar", "255", "not null"), - "object" => array ("varchar", "255", "not null"), - "comment" => array ("varchar", "255")); - $this->dbObject->primary = "idobject"; - $this->dbObject->unique = array ("idobject", array ("object", "module")); - $this->dbObject->titles = array ( - "idobject" => dgettext ("domframework", "idobject"), - "module" => dgettext ("domframework", "Module"), - "object" => dgettext ("domframework", "Object"), - "comment" => dgettext ("domframework", "Comment")); + ///////////////////////// + // DATABASE STORAGE // + ///////////////////////// + /** Connect to the database before using it + * @param string $dsn The DSN to use to connect to the database + * @param string|null $username The username to use to connect to the + * database + * @param string|null $password The password to use to connect to the + * database + * @param array|null $driver_options The options to pass to PDO driver + */ + public function connect( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + $this->dbObject = new Dblayer($dsn, $username, $password, $driver_options); + $this->dbObject->debug = $this->debug; + $this->dbObject->table = "authzobject"; + $this->dbObject->prefix = $this->tableprefix; + $this->dbObject->fields = array( + "idobject" => array("integer", "not null", "autoincrement"), + "module" => array("varchar", "255", "not null"), + "object" => array("varchar", "255", "not null"), + "comment" => array("varchar", "255")); + $this->dbObject->primary = "idobject"; + $this->dbObject->unique = array("idobject", array("object", "module")); + $this->dbObject->titles = array( + "idobject" => dgettext("domframework", "idobject"), + "module" => dgettext("domframework", "Module"), + "object" => dgettext("domframework", "Object"), + "comment" => dgettext("domframework", "Comment")); - $this->dbGroup = new Dblayer ($dsn, $username, $password, $driver_options); - $this->dbGroup->debug = $this->debug; - $this->dbGroup->table = "authzgroup"; - $this->dbGroup->prefix = $this->tableprefix; - $this->dbGroup->fields = array ( - "idgroup" => array ("integer", "not null", "autoincrement"), - "module" => array ("varchar", "255", "not null"), - "group" => array ("varchar", "255", "not null"), - "comment" => array ("varchar", "255")); - $this->dbGroup->primary = "idgroup"; - $this->dbGroup->unique = array ("idgroup", array ("module", "group")); - $this->dbGroup->titles = array ( - "idgroup" => dgettext ("domframework", "idgroup"), - "module" => dgettext ("domframework", "Module"), - "group" => dgettext ("domframework", "Group"), - "comment" => dgettext ("domframework", "Comment")); + $this->dbGroup = new Dblayer($dsn, $username, $password, $driver_options); + $this->dbGroup->debug = $this->debug; + $this->dbGroup->table = "authzgroup"; + $this->dbGroup->prefix = $this->tableprefix; + $this->dbGroup->fields = array( + "idgroup" => array("integer", "not null", "autoincrement"), + "module" => array("varchar", "255", "not null"), + "group" => array("varchar", "255", "not null"), + "comment" => array("varchar", "255")); + $this->dbGroup->primary = "idgroup"; + $this->dbGroup->unique = array("idgroup", array("module", "group")); + $this->dbGroup->titles = array( + "idgroup" => dgettext("domframework", "idgroup"), + "module" => dgettext("domframework", "Module"), + "group" => dgettext("domframework", "Group"), + "comment" => dgettext("domframework", "Comment")); - $this->dbGroupMember = new Dblayer ($dsn, $username, $password, - $driver_options); - $this->dbGroupMember->debug = $this->debug; - $this->dbGroupMember->table = "authzgroupmember"; - $this->dbGroupMember->prefix = $this->tableprefix; - $this->dbGroupMember->fields = array ( - "idgroupmember" => array ("integer", "not null", "autoincrement"), - "user" => array ("varchar", "255", "not null"), - "idgroup" => array ("integer", "not null"), - "comment" => array ("varchar", "255")); - $this->dbGroupMember->primary = "idgroupmember"; - $this->dbGroupMember->unique = array ("idgroupmember", - array ("user", "idgroup")); - $this->dbGroupMember->foreign = array ( - "idgroup" => array ("authzgroup", "idgroup", + $this->dbGroupMember = new Dblayer( + $dsn, + $username, + $password, + $driver_options + ); + $this->dbGroupMember->debug = $this->debug; + $this->dbGroupMember->table = "authzgroupmember"; + $this->dbGroupMember->prefix = $this->tableprefix; + $this->dbGroupMember->fields = array( + "idgroupmember" => array("integer", "not null", "autoincrement"), + "user" => array("varchar", "255", "not null"), + "idgroup" => array("integer", "not null"), + "comment" => array("varchar", "255")); + $this->dbGroupMember->primary = "idgroupmember"; + $this->dbGroupMember->unique = array("idgroupmember", + array("user", "idgroup")); + $this->dbGroupMember->foreign = array( + "idgroup" => array("authzgroup", "idgroup", "ON UPDATE CASCADE ON DELETE CASCADE")); - $this->dbGroupMember->titles = array ( - "idgroupmember"=> dgettext ("domframework", "idgroupmember"), - "user"=>dgettext ("domframework", "User"), - "idgroup"=>dgettext ("domframework", "idgroup"), - "comment"=>dgettext ("domframework", "Comment")); + $this->dbGroupMember->titles = array( + "idgroupmember" => dgettext("domframework", "idgroupmember"), + "user" => dgettext("domframework", "User"), + "idgroup" => dgettext("domframework", "idgroup"), + "comment" => dgettext("domframework", "Comment")); - $this->dbRight = new Dblayer ($dsn, $username, $password, $driver_options); - $this->dbRight->debug = $this->debug; - $this->dbRight->table = "authzright"; - $this->dbRight->prefix = $this->tableprefix; - $this->dbRight->fields = array ( - "idright"=> array ("integer", "not null", "autoincrement"), - "idgroup"=> array ("integer", "not null"), - "idobject"=>array ("integer", "not null"), - "right"=> array ("varchar", "2", "not null"), // RO, RW - "comment"=> array ("varchar", "255")); - $this->dbRight->primary = "idright"; - $this->dbRight->unique = array ("idright", array ("idgroup", "idobject")); - $this->dbRight->foreign = array ( - "idgroup" => array ("authzgroup", "idgroup", + $this->dbRight = new Dblayer($dsn, $username, $password, $driver_options); + $this->dbRight->debug = $this->debug; + $this->dbRight->table = "authzright"; + $this->dbRight->prefix = $this->tableprefix; + $this->dbRight->fields = array( + "idright" => array("integer", "not null", "autoincrement"), + "idgroup" => array("integer", "not null"), + "idobject" => array("integer", "not null"), + "right" => array("varchar", "2", "not null"), // RO, RW + "comment" => array("varchar", "255")); + $this->dbRight->primary = "idright"; + $this->dbRight->unique = array("idright", array("idgroup", "idobject")); + $this->dbRight->foreign = array( + "idgroup" => array("authzgroup", "idgroup", "ON UPDATE CASCADE ON DELETE CASCADE"), - "idobject" => array ("authzobject", "idobject", + "idobject" => array("authzobject", "idobject", "ON UPDATE CASCADE ON DELETE CASCADE"), - ); - $this->dbRight->titles = array ( - "idright" => dgettext ("domframework", "idright"), - "idgroup" => dgettext ("domframework", "idgroup"), - "idobject" => dgettext ("domframework", "idobject"), - "right" => dgettext ("domframework", "Right"), - "comment" => dgettext ("domframework", "Comment")); - return TRUE; - } - - /** Disconnect from the database. Should be only used in the unit tests - */ - public function disconnect () - { - $this->dbObject->disconnect (); - } - - /** Create the tables in the database to store the data - */ - public function createTables () - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $tables = array ("Object", "Group", "GroupMember", "Right"); - foreach ($tables as $table) - { - try - { - $class= "db$table"; - $this->$class->createTable (); - } - catch (\Exception $e) - { - echo $e->getMessage()."\n"; - } + ); + $this->dbRight->titles = array( + "idright" => dgettext("domframework", "idright"), + "idgroup" => dgettext("domframework", "idgroup"), + "idobject" => dgettext("domframework", "idobject"), + "right" => dgettext("domframework", "Right"), + "comment" => dgettext("domframework", "Comment")); + return true; } - return TRUE; - } - ///////////////// - // OBJECTS // - ///////////////// - /** Add a new object to object list - * Return the idobject created - * @param string $module The module to use - * @param string $object The object to create - * @param string|null $comment The comment to save - */ - public function objectAdd ($module, $object, $comment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - // TODO : Check parameters before saving them - $this->rightCache = null; - return $this->dbObject->insert (array ("module"=>$module, - "object"=>$object, - "comment"=>$comment)); - } - - /** Remove an object from database and all the rights using it - * @param string $module The module to use - * @param string $object The object to delete - */ - public function objectDel ($module, $object) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectRead ($module, $object); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbObject->delete ($idobjects[0]["idobject"]); - } - - /** Remove an object from database and all the rights using it - * @param string $module The module to use - * @param integer $idobject The object to delete - */ - public function objectDelByID ($module, $idobject) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectReadByID ($module, $idobject); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbObject->delete ($idobjects[0]["idobject"]); - } - - /** Update an object in the database - * @param string $module The module to use - * @param string $object The object to update - * @param string $newobject The new name of the object - * @param string|null $newcomment The new comment of the object - */ - public function objectUpdate ($module, $object, $newobject, $newcomment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectRead ($module, $object); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbObject->update ($idobjects[0]["idobject"], - array ("object"=>$newobject, - "comment"=>$newcomment)); - } - - /** Update an object in the database - * @param string $module The module to use - * @param integer $idobject The object to update - * @param string $newobject The new name of the object - * @param string|null $newcomment The new comment of the object - */ - public function objectUpdateByID ($module, $idobject, $newobject, - $newcomment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectReadByID ($module, $idobject); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbObject->update ($idobjects[0]["idobject"], - array ("object"=>$newobject, - "comment"=>$newcomment)); - } - - /** Return an array with all the available objects in the module, or only - * one object if $object is provided - * @param string $module The module to use - * @param string $object The name of the object to get - */ - public function objectRead ($module, $object=null) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $select[] = array ("module", $module); - if ($object !== null) - $select[] = array ("object", $object); - return $this->dbObject->read ($select, null, - array (array ("object", "ASC"))); - } - - /** Return an array with all the available objects in the module, or only - * one object if $object is provided - * @param string $module The module to use - * @param integer $idobject The name of the object to get - */ - public function objectReadByID ($module, $idobject=null) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $select[] = array ("module", $module); - if ($idobject !== null) - $select[] = array ("idobject", $idobject); - return $this->dbObject->read ($select); - } - - /** Return an array containing the titles of the table translating in the user - * language - */ - public function objectTitles () - { - return $this->dbObject->titles; - } - - /** Check if the provided data are compliant with the object specification - * @param array $data The name of the object to get - * @param integer|null $idobject The object to check - * @return array The errors found in the data - */ - public function objectVerify ($data, $idobject=false) - { - return $this->dbObject->verify ($data, $idobject); - } - - //////////////// - // GROUPS // - //////////////// - /** Add a new group to group list - * Return the idgroup created - * @param string $module The module to use - * @param string $group The group to create - * @param string|null $comment The comment to add with the group - */ - public function groupAdd ($module, $group, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - // TODO : Check parameters before saving them - return $this->dbGroup->insert (array ("module"=>$module, - "group"=>$group, - "comment"=>$comment)); - } - - /** Remove an group from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to delete - */ - public function groupDel ($module, $group) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupRead ($module, $group); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->dbGroup->delete ($idgroups[0]["idgroup"]); - } - - /** Remove an group from database and all the rights using it - * @param string $module The module to use - * @param integer $idgroup The group to delete - */ - public function groupDelByID ($module, $idgroup) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupReadByID ($module, $idgroup); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->dbGroup->delete ($idgroups[0]["idgroup"]); - } - - /** Update an group in the database - * @param string $module The module to use - * @param string $group The group to update - * @param string $newgroup The new group name - * @param string|null $comment The comment for the group - */ - public function groupUpdate ($module, $group, $newgroup, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupRead ($module, $group); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->dbGroup->update ($idgroups[0]["idgroup"], - array ("group"=>$newgroup, - "comment"=>$comment)); - } - - /** Update an group in the database - * @param string $module The module to use - * @param integer $idgroup The group to update - * @param string $newgroup The new group name - * @param string|null $comment The comment for the group - */ - public function groupUpdateByID ($module, $idgroup, $newgroup, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupReadByID ($module, $idgroup); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->dbGroup->update ($idgroups[0]["idgroup"], - array ("group"=>$newgroup, - "comment"=>$comment)); - } - - /** Return an array with all the available groups in the module - * @param string $module The module to use - * @param string|null $group The group to check if exists - */ - public function groupRead ($module, $group=null) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $select[] = array ("module", $module); - if ($group !== null) - $select[] = array ("group", $group); - return $this->dbGroup->read ($select, null, array (array ("group", "ASC"))); - } - - - /** Return an array with all the available groups in the module - * @param string $module The module to use - * @param integer $idgroup The group to check if exists - */ - public function groupReadByID ($module, $idgroup) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $select[] = array ("module", $module); - $select[] = array ("idgroup", $idgroup); - return $this->dbGroup->read ($select); - } - - /** Return an array containing the titles of the table translating in the user - * language - */ - public function groupTitles () - { - return $this->dbGroup->titles; - } - - /** Check if the provided data are compilant with the group specification - * @param array $data The data to check - * @param integer|null $idgroup The idgroup to check - * @return array The errors found in the data - */ - public function groupVerify ($data, $idgroup=false) - { - return $this->dbGroup->verify ($data, $idgroup); - } - - ////////////////////// - // GROUP MEMBER // - ////////////////////// - /** Add a new groupmember to groupmember list - * Return the idgroupmember created - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to add in group - * @param string|null $comment The comment to save - */ - public function groupmemberAdd ($module, $group, $user, $comment="") - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->rightCache = null; - return $this->dbGroupMember->insert (array ( - "user"=>$user, - "idgroup"=>$groups[0]["idgroup"], - "comment"=>$comment)); - } - - /** Remove an groupmember from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to remove - */ - public function groupmemberDel ($module, $group, $user) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $groupsMembers = $this->dbGroupMember->read (array ( - array ("user", $user), - array ("idgroup", $groups[0]["idgroup"]))); - if (! isset ($groupsMembers[0]["idgroupmember"])) - throw new \Exception (dgettext ("domframework", - "Wanted GroupMember not found"), 404); - $this->rightCache = null; - return $this->dbGroupMember->delete ($groupsMembers[0]["idgroupmember"]); - } - - /** Remove an groupmember from database and all the rights using it - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $idgroupmember The user to remove - */ - public function groupmemberDelByID ($module, $idgroup, $idgroupmember) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $groupsMembers = $this->dbGroupMember->read (array ( - array ("idgroupmember", $idgroupmember), - array ("idgroup", $idgroup))); - if (! isset ($groupsMembers[0]["idgroupmember"])) - throw new \Exception (dgettext ("domframework", - "Wanted GroupMember not found"), 404); - $this->rightCache = null; - return $this->dbGroupMember->delete ($groupsMembers[0]["idgroupmember"]); - } - - /** Update an groupmember in the database - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to update - * @param string|null $comment The comment to update - */ - public function groupmemberUpdate ($module, $group, $user, $comment="") - { - $this->rightCache = null; - die ("This function is not available : contact us if you need it\n"); - } - - /** Update an groupmember in the database - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $iduser The user to update - * @param string $user The new user name - * @param string|null $comment The comment to update - */ - public function groupmemberUpdateByID ($module, $idgroup, $iduser, $user, - $comment="") - { - $data = $this->groupmemberReadUserDataByID ($module, $idgroup, $iduser); - if (count ($data) === 0) - throw new \Exception (dgettext ("domframework", - "IDUser in IDGroup not found"), 404); - $this->rightCache = null; - return $this->dbGroupMember->update ($iduser, - array ("user"=>$user, - "comment"=>$comment)); - } - - - /** Return an array with all the groups where the user is in and in the module - * @param string $module The module to use - * @param string $user The user to search - */ - public function groupmemberReadUser ($module, $user) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $idgrouptmps = $this->groupRead ($module); - // Create an array with idgroup=>group - $idgroups = array (); - foreach ($idgrouptmps as $val) - $idgroups[$val["idgroup"]] = $val["group"]; - $select = array (); - $select[] = array ("user", $user); - $idgroupmembers = $this->dbGroupMember->read ($select); - $res = array (); - foreach ($idgroupmembers as $idmembers) + /** Disconnect from the database. Should be only used in the unit tests + */ + public function disconnect() { - $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + $this->dbObject->disconnect(); } - return $res; - } - /** Return an array with all the groups where the user is in and in the module - * @param string $module The module to use - * @param integer $idgroupmember The user to search - */ - public function groupmemberReadUserByID ($module, $idgroupmember) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $idgrouptmps = $this->groupRead ($module); - // Create an array with idgroup=>group - $idgroups = array (); - foreach ($idgrouptmps as $val) - $idgroups[$val["idgroup"]] = $val["group"]; - $select = array (); - $select[] = array ("idgroupmember", $idgroupmember); - $idgroupmembers = $this->dbGroupMember->read ($select); - $res = array (); - foreach ($idgroupmembers as $idmembers) + /** Create the tables in the database to store the data + */ + public function createTables() { - $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $tables = array("Object", "Group", "GroupMember", "Right"); + foreach ($tables as $table) { + try { + $class = "db$table"; + $this->$class->createTable(); + } catch (\Exception $e) { + echo $e->getMessage() . "\n"; + } + } + return true; } - return $res; - } - /** Return an array with all the available users in the group and in the - * module - * @param string $module The module to use - * @param string $group The group to search - */ - public function groupmemberReadGroup ($module, $group) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $select[] = array ("idgroup", $groups[0]["idgroup"]); - return $this->dbGroupMember->read ($select, array ("user")); - } - - /** Return an array with all the available users in the group and in the - * module - * @param string $module The module to use - * @param integer $idgroup The group to search - */ - public function groupmemberReadGroupByID ($module, $idgroup) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $select[] = array ("idgroup", $groups[0]["idgroup"]); - return $this->dbGroupMember->read ($select); - } - - /** Return an array containing the information of a user in a specific group - * @param string $module The module to use - * @param integer $idgroup The group to search - * @param integer $iduser The user to search - */ - public function groupmemberReadUserDataByID ($module, $idgroup, $iduser) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $select[] = array ("idgroup", $groups[0]["idgroup"]); - $select[] = array ("idgroupmember", $iduser); - return $this->dbGroupMember->read ($select); - } - - /** Return an array containing the titles of the table translating in the user - * language - */ - public function groupmembersTitles () - { - return $this->dbGroupMember->titles; - } - - /** Check if the provided data are compilant with the group specification - * @param array $data The data to check - * @param integer|null $idgroupmember The group member associated to verify - * @return array The errors found in the data - */ - public function groupmembersVerify ($data, $idgroupmember=false) - { - return $this->dbGroupMember->verify ($data, $idgroupmember); - } - - //////////////// - // RIGHTS // - //////////////// - /** Add a new right to right list - * Return the idright created - * @param string $module The module to use - * @param string $group The group to use - * @param string $object The object to use - * @param string $right The right to add - * @param string|null $comment The comment to add - */ - public function rightAdd ($module, $group, $object, $right, $comment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($right) + ///////////////// + // OBJECTS // + ///////////////// + /** Add a new object to object list + * Return the idobject created + * @param string $module The module to use + * @param string $object The object to create + * @param string|null $comment The comment to save + */ + public function objectAdd($module, $object, $comment = "") { - case "RW": $right=2;break; - case "RO": $right=1;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (RO/RW only)"), - 500); + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + // TODO : Check parameters before saving them + $this->rightCache = null; + return $this->dbObject->insert(array("module" => $module, + "object" => $object, + "comment" => $comment)); } - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbRight->insert (array ("idgroup"=>$groups[0]["idgroup"], - "idobject"=>$objects[0]["idobject"], - "right"=>$right, - "comment"=>$comment)); - } - /** Add a new right to right list by ID - * Return the idright created - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $idobject The object to use - * @param integer $idright The right to add - * @param string|null $comment The comment to add - */ - public function rightAddByID ($module, $idgroup, $idobject, $idright, - $comment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($idright) + /** Remove an object from database and all the rights using it + * @param string $module The module to use + * @param string $object The object to delete + */ + public function objectDel($module, $object) { - case "2": $right=2;break; - case "1": $right=1;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (RO/RW only)"), - 500); + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectRead($module, $object); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbObject->delete($idobjects[0]["idobject"]); } - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectReadByID ($module, $idobject); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - return $this->dbRight->insert (array ("idgroup"=>$groups[0]["idgroup"], - "idobject"=>$objects[0]["idobject"], - "right"=>$right, - "comment"=>$comment)); - } - /** Remove an right from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to use - * @param string $object The object to remove the rights - */ - public function rightDel ($module, $group, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $idrights = $this->rightRead ($module, $group, $object); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - return $this->dbRight->delete ($idrights[0]["idright"]); - } - - /** Remove an right from database by ID and all the rights using it - * @param string $module The module to use - * @param integer $idright The idright to be deleted - */ - public function rightDelByID ($module, $idright) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $idrights = $this->rightReadByID ($module, $idright); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - return $this->dbRight->delete ($idrights[0]["idright"]); - } - - /** Update a right in the database - * @param string $module The module to use - * @param string $group The group to update the right - * @param string $object The object ot update the right - * @param string $newright The new right to save - * @param string|null $newcomment The new comment to save - */ - public function rightUpdate ($module, $group, $object, $newright, - $newcomment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($newright) + /** Remove an object from database and all the rights using it + * @param string $module The module to use + * @param integer $idobject The object to delete + */ + public function objectDelByID($module, $idobject) { - case "RW": $newright=2;break; - case "RO": $newright=1;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (RO/RW only)"), - 500); + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectReadByID($module, $idobject); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbObject->delete($idobjects[0]["idobject"]); } - $idrights = $this->rightRead ($module, $group, $object); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - return $this->dbRight->update ($idrights[0]["idright"], - array ("right"=>$newright, - "comment"=>$newcomment)); - } - /** Update a right by ID in the database - * @param string $module The module to use - * @param integer $idright The idright to update the right - * @param integer $newidobject The object ot update the right - * @param integer $newright The new right to save - * @param string|null $newcomment The new comment to save - */ - public function rightUpdateByID ($module, $idright, $newidobject, $newright, - $newcomment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($newright) + /** Update an object in the database + * @param string $module The module to use + * @param string $object The object to update + * @param string $newobject The new name of the object + * @param string|null $newcomment The new comment of the object + */ + public function objectUpdate($module, $object, $newobject, $newcomment = "") { - case "2": $newright=2;break; - case "1": $newright=1;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (RO/RW only)"), - 500); + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectRead($module, $object); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbObject->update( + $idobjects[0]["idobject"], + array("object" => $newobject, + "comment" => $newcomment) + ); + } + + /** Update an object in the database + * @param string $module The module to use + * @param integer $idobject The object to update + * @param string $newobject The new name of the object + * @param string|null $newcomment The new comment of the object + */ + public function objectUpdateByID( + $module, + $idobject, + $newobject, + $newcomment = "" + ) { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectReadByID($module, $idobject); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbObject->update( + $idobjects[0]["idobject"], + array("object" => $newobject, + "comment" => $newcomment) + ); + } + + /** Return an array with all the available objects in the module, or only + * one object if $object is provided + * @param string $module The module to use + * @param string $object The name of the object to get + */ + public function objectRead($module, $object = null) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $select[] = array("module", $module); + if ($object !== null) { + $select[] = array("object", $object); + } + return $this->dbObject->read( + $select, + null, + array(array("object", "ASC")) + ); + } + + /** Return an array with all the available objects in the module, or only + * one object if $object is provided + * @param string $module The module to use + * @param integer $idobject The name of the object to get + */ + public function objectReadByID($module, $idobject = null) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $select[] = array("module", $module); + if ($idobject !== null) { + $select[] = array("idobject", $idobject); + } + return $this->dbObject->read($select); + } + + /** Return an array containing the titles of the table translating in the user + * language + */ + public function objectTitles() + { + return $this->dbObject->titles; + } + + /** Check if the provided data are compliant with the object specification + * @param array $data The name of the object to get + * @param integer|null $idobject The object to check + * @return array The errors found in the data + */ + public function objectVerify($data, $idobject = false) + { + return $this->dbObject->verify($data, $idobject); + } + + //////////////// + // GROUPS // + //////////////// + /** Add a new group to group list + * Return the idgroup created + * @param string $module The module to use + * @param string $group The group to create + * @param string|null $comment The comment to add with the group + */ + public function groupAdd($module, $group, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + // TODO : Check parameters before saving them + return $this->dbGroup->insert(array("module" => $module, + "group" => $group, + "comment" => $comment)); + } + + /** Remove an group from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to delete + */ + public function groupDel($module, $group) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupRead($module, $group); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->dbGroup->delete($idgroups[0]["idgroup"]); + } + + /** Remove an group from database and all the rights using it + * @param string $module The module to use + * @param integer $idgroup The group to delete + */ + public function groupDelByID($module, $idgroup) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupReadByID($module, $idgroup); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->dbGroup->delete($idgroups[0]["idgroup"]); + } + + /** Update an group in the database + * @param string $module The module to use + * @param string $group The group to update + * @param string $newgroup The new group name + * @param string|null $comment The comment for the group + */ + public function groupUpdate($module, $group, $newgroup, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupRead($module, $group); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->dbGroup->update( + $idgroups[0]["idgroup"], + array("group" => $newgroup, + "comment" => $comment) + ); + } + + /** Update an group in the database + * @param string $module The module to use + * @param integer $idgroup The group to update + * @param string $newgroup The new group name + * @param string|null $comment The comment for the group + */ + public function groupUpdateByID($module, $idgroup, $newgroup, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupReadByID($module, $idgroup); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->dbGroup->update( + $idgroups[0]["idgroup"], + array("group" => $newgroup, + "comment" => $comment) + ); + } + + /** Return an array with all the available groups in the module + * @param string $module The module to use + * @param string|null $group The group to check if exists + */ + public function groupRead($module, $group = null) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $select[] = array("module", $module); + if ($group !== null) { + $select[] = array("group", $group); + } + return $this->dbGroup->read($select, null, array(array("group", "ASC"))); } - $idrights = $this->rightReadByID ($module, $idright); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - return $this->dbRight->update ($idrights[0]["idright"], - array ("idobject"=>$newidobject, - "right"=>$newright, - "comment"=>$newcomment)); - } - /** Return an array with all the available rights in the module, for a group, - * and concerning an object - * @param string $module The module to use - * @param string $group The group to get the rights - * @param string $object The object to get the rights - */ - public function rightRead ($module, $group, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $select[] = array ("idgroup", $groups[0]["idgroup"]); - $select[] = array ("idobject", $objects[0]["idobject"]); - return $this->dbRight->read ($select); - } + /** Return an array with all the available groups in the module + * @param string $module The module to use + * @param integer $idgroup The group to check if exists + */ + public function groupReadByID($module, $idgroup) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $select[] = array("module", $module); + $select[] = array("idgroup", $idgroup); + return $this->dbGroup->read($select); + } - /** Return an array with all the available rights for a module and a group - * @param string $module The module to use - * @param string $group The group to get the rights - */ - public function rightReadByGroup ($module, $group) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->rightReadByGroupByID ($module, $objects[0]["idgroup"]); - } + /** Return an array containing the titles of the table translating in the user + * language + */ + public function groupTitles() + { + return $this->dbGroup->titles; + } - /** Return an array with all the available rights for a module and a group - * @param string $module The module to use - * @param integer $idgroup The group to get the rights - */ - public function rightReadByGroupByID ($module, $idgroup) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $select[] = array ("idgroup", $idgroup); - return $this->dbRight->read ($select); - } + /** Check if the provided data are compilant with the group specification + * @param array $data The data to check + * @param integer|null $idgroup The idgroup to check + * @return array The errors found in the data + */ + public function groupVerify($data, $idgroup = false) + { + return $this->dbGroup->verify($data, $idgroup); + } - /** Return an array with all the information concerning a right selected by - * @param string $module The module to use - * @param integer $idright The right to search - * ID - */ - public function rightReadByID ($module, $idright) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $select[] = array ("idright", $idright); - return $this->dbRight->read ($select); - } + ////////////////////// + // GROUP MEMBER // + ////////////////////// + /** Add a new groupmember to groupmember list + * Return the idgroupmember created + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to add in group + * @param string|null $comment The comment to save + */ + public function groupmemberAdd($module, $group, $user, $comment = "") + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->rightCache = null; + return $this->dbGroupMember->insert(array( + "user" => $user, + "idgroup" => $groups[0]["idgroup"], + "comment" => $comment)); + } - /** Return an array with all the available rights for a module and an object - * @param string $module The module to use - * @param string $object The object to search - */ - public function rightReadByObject ($module, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $select[] = array ("idobject", $objects[0]["idobject"]); - return $this->dbRight->read ($select); - } + /** Remove an groupmember from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to remove + */ + public function groupmemberDel($module, $group, $user) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $groupsMembers = $this->dbGroupMember->read(array( + array("user", $user), + array("idgroup", $groups[0]["idgroup"]))); + if (! isset($groupsMembers[0]["idgroupmember"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted GroupMember not found" + ), 404); + } + $this->rightCache = null; + return $this->dbGroupMember->delete($groupsMembers[0]["idgroupmember"]); + } - /** Return an array with all the available rights for a module and an idobject - * @param string $module The module to use - * @param integer $idobject The object to search - */ - public function rightReadByObjectByID ($module, $idobject) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - // FIXME : Do not use $module ? - $select[] = array ("idobject", $idobject); - return $this->dbRight->read ($select); - } + /** Remove an groupmember from database and all the rights using it + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $idgroupmember The user to remove + */ + public function groupmemberDelByID($module, $idgroup, $idgroupmember) + { + if ($this->dbGroupMember == null) { + throw new \Exception(dgettext( + "domframework", + "DB for GroupMember is not connected" + ), 500); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $groupsMembers = $this->dbGroupMember->read(array( + array("idgroupmember", $idgroupmember), + array("idgroup", $idgroup))); + if (! isset($groupsMembers[0]["idgroupmember"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted GroupMember not found" + ), 404); + } + $this->rightCache = null; + return $this->dbGroupMember->delete($groupsMembers[0]["idgroupmember"]); + } + + /** Update an groupmember in the database + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to update + * @param string|null $comment The comment to update + */ + public function groupmemberUpdate($module, $group, $user, $comment = "") + { + $this->rightCache = null; + die("This function is not available : contact us if you need it\n"); + } + + /** Update an groupmember in the database + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $iduser The user to update + * @param string $user The new user name + * @param string|null $comment The comment to update + */ + public function groupmemberUpdateByID( + $module, + $idgroup, + $iduser, + $user, + $comment = "" + ) { + $data = $this->groupmemberReadUserDataByID($module, $idgroup, $iduser); + if (count($data) === 0) { + throw new \Exception(dgettext( + "domframework", + "IDUser in IDGroup not found" + ), 404); + } + $this->rightCache = null; + return $this->dbGroupMember->update( + $iduser, + array("user" => $user, + "comment" => $comment) + ); + } - /** Return an array containing the titles of the table translating in the user - * language - */ - public function rightTitles () - { - return $this->dbRight->titles; - } + /** Return an array with all the groups where the user is in and in the module + * @param string $module The module to use + * @param string $user The user to search + */ + public function groupmemberReadUser($module, $user) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $idgrouptmps = $this->groupRead($module); + // Create an array with idgroup=>group + $idgroups = array(); + foreach ($idgrouptmps as $val) { + $idgroups[$val["idgroup"]] = $val["group"]; + } + $select = array(); + $select[] = array("user", $user); + $idgroupmembers = $this->dbGroupMember->read($select); + $res = array(); + foreach ($idgroupmembers as $idmembers) { + $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + } + return $res; + } - /** Return all the types of rights available (RO and RW) - */ - public function rightTypes () - { - return array ("1"=>"RO", "2"=>"RW"); - } + /** Return an array with all the groups where the user is in and in the module + * @param string $module The module to use + * @param integer $idgroupmember The user to search + */ + public function groupmemberReadUserByID($module, $idgroupmember) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $idgrouptmps = $this->groupRead($module); + // Create an array with idgroup=>group + $idgroups = array(); + foreach ($idgrouptmps as $val) { + $idgroups[$val["idgroup"]] = $val["group"]; + } + $select = array(); + $select[] = array("idgroupmember", $idgroupmember); + $idgroupmembers = $this->dbGroupMember->read($select); + $res = array(); + foreach ($idgroupmembers as $idmembers) { + $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + } + return $res; + } - /** Check if the provided data are compilant with the group specification - * @param array $data The data of the right to check - * @param integer $idright The right to search - * @return array The errors found in the data - */ - public function rightVerify ($data, $idright=false) - { - return $this->dbRight->verify ($data, $idright); - } + /** Return an array with all the available users in the group and in the + * module + * @param string $module The module to use + * @param string $group The group to search + */ + public function groupmemberReadGroup($module, $group) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $select[] = array("idgroup", $groups[0]["idgroup"]); + return $this->dbGroupMember->read($select, array("user")); + } + + /** Return an array with all the available users in the group and in the + * module + * @param string $module The module to use + * @param integer $idgroup The group to search + */ + public function groupmemberReadGroupByID($module, $idgroup) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $select[] = array("idgroup", $groups[0]["idgroup"]); + return $this->dbGroupMember->read($select); + } + + /** Return an array containing the information of a user in a specific group + * @param string $module The module to use + * @param integer $idgroup The group to search + * @param integer $iduser The user to search + */ + public function groupmemberReadUserDataByID($module, $idgroup, $iduser) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $select[] = array("idgroup", $groups[0]["idgroup"]); + $select[] = array("idgroupmember", $iduser); + return $this->dbGroupMember->read($select); + } + + /** Return an array containing the titles of the table translating in the user + * language + */ + public function groupmembersTitles() + { + return $this->dbGroupMember->titles; + } + + /** Check if the provided data are compilant with the group specification + * @param array $data The data to check + * @param integer|null $idgroupmember The group member associated to verify + * @return array The errors found in the data + */ + public function groupmembersVerify($data, $idgroupmember = false) + { + return $this->dbGroupMember->verify($data, $idgroupmember); + } + + //////////////// + // RIGHTS // + //////////////// + /** Add a new right to right list + * Return the idright created + * @param string $module The module to use + * @param string $group The group to use + * @param string $object The object to use + * @param string $right The right to add + * @param string|null $comment The comment to add + */ + public function rightAdd($module, $group, $object, $right, $comment = "") + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($right) { + case "RW": + $right = 2; + break; + case "RO": + $right = 1; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (RO/RW only)" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->insert(array("idgroup" => $groups[0]["idgroup"], + "idobject" => $objects[0]["idobject"], + "right" => $right, + "comment" => $comment)); + } + + /** Add a new right to right list by ID + * Return the idright created + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $idobject The object to use + * @param integer $idright The right to add + * @param string|null $comment The comment to add + */ + public function rightAddByID( + $module, + $idgroup, + $idobject, + $idright, + $comment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($idright) { + case "2": + $right = 2; + break; + case "1": + $right = 1; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (RO/RW only)" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectReadByID($module, $idobject); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->insert(array("idgroup" => $groups[0]["idgroup"], + "idobject" => $objects[0]["idobject"], + "right" => $right, + "comment" => $comment)); + } + + /** Remove an right from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to use + * @param string $object The object to remove the rights + */ + public function rightDel($module, $group, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $idrights = $this->rightRead($module, $group, $object); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->delete($idrights[0]["idright"]); + } + + /** Remove an right from database by ID and all the rights using it + * @param string $module The module to use + * @param integer $idright The idright to be deleted + */ + public function rightDelByID($module, $idright) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $idrights = $this->rightReadByID($module, $idright); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->delete($idrights[0]["idright"]); + } + + /** Update a right in the database + * @param string $module The module to use + * @param string $group The group to update the right + * @param string $object The object ot update the right + * @param string $newright The new right to save + * @param string|null $newcomment The new comment to save + */ + public function rightUpdate( + $module, + $group, + $object, + $newright, + $newcomment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($newright) { + case "RW": + $newright = 2; + break; + case "RO": + $newright = 1; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (RO/RW only)" + ), + 500 + ); + } + $idrights = $this->rightRead($module, $group, $object); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->update( + $idrights[0]["idright"], + array("right" => $newright, + "comment" => $newcomment) + ); + } + + /** Update a right by ID in the database + * @param string $module The module to use + * @param integer $idright The idright to update the right + * @param integer $newidobject The object ot update the right + * @param integer $newright The new right to save + * @param string|null $newcomment The new comment to save + */ + public function rightUpdateByID( + $module, + $idright, + $newidobject, + $newright, + $newcomment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($newright) { + case "2": + $newright = 2; + break; + case "1": + $newright = 1; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (RO/RW only)" + ), + 500 + ); + } + $idrights = $this->rightReadByID($module, $idright); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + return $this->dbRight->update( + $idrights[0]["idright"], + array("idobject" => $newidobject, + "right" => $newright, + "comment" => $newcomment) + ); + } + + + /** Return an array with all the available rights in the module, for a group, + * and concerning an object + * @param string $module The module to use + * @param string $group The group to get the rights + * @param string $object The object to get the rights + */ + public function rightRead($module, $group, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $select[] = array("idgroup", $groups[0]["idgroup"]); + $select[] = array("idobject", $objects[0]["idobject"]); + return $this->dbRight->read($select); + } + + /** Return an array with all the available rights for a module and a group + * @param string $module The module to use + * @param string $group The group to get the rights + */ + public function rightReadByGroup($module, $group) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->rightReadByGroupByID($module, $objects[0]["idgroup"]); + } + + /** Return an array with all the available rights for a module and a group + * @param string $module The module to use + * @param integer $idgroup The group to get the rights + */ + public function rightReadByGroupByID($module, $idgroup) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $select[] = array("idgroup", $idgroup); + return $this->dbRight->read($select); + } + + /** Return an array with all the information concerning a right selected by + * @param string $module The module to use + * @param integer $idright The right to search + * ID + */ + public function rightReadByID($module, $idright) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $select[] = array("idright", $idright); + return $this->dbRight->read($select); + } + + /** Return an array with all the available rights for a module and an object + * @param string $module The module to use + * @param string $object The object to search + */ + public function rightReadByObject($module, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $select[] = array("idobject", $objects[0]["idobject"]); + return $this->dbRight->read($select); + } + + /** Return an array with all the available rights for a module and an idobject + * @param string $module The module to use + * @param integer $idobject The object to search + */ + public function rightReadByObjectByID($module, $idobject) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + // FIXME : Do not use $module ? + $select[] = array("idobject", $idobject); + return $this->dbRight->read($select); + } + + + /** Return an array containing the titles of the table translating in the user + * language + */ + public function rightTitles() + { + return $this->dbRight->titles; + } + + /** Return all the types of rights available (RO and RW) + */ + public function rightTypes() + { + return array("1" => "RO", "2" => "RW"); + } + + /** Check if the provided data are compilant with the group specification + * @param array $data The data of the right to check + * @param integer $idright The right to search + * @return array The errors found in the data + */ + public function rightVerify($data, $idright = false) + { + return $this->dbRight->verify($data, $idright); + } } diff --git a/src/Authzgroupsoo.php b/src/Authzgroupsoo.php index 7e6bd04..2b1fe28 100644 --- a/src/Authzgroupsoo.php +++ b/src/Authzgroupsoo.php @@ -1,4 +1,5 @@ @@ -13,1375 +14,1774 @@ namespace Domframework; */ class Authzgroupsoo { - /** The table prefix to use */ - public $tableprefix = ""; - /** The dblayeroo object use to manage the Object table */ - private $dbObject = null; - /** The dblayeroo object use to manage the Group table */ - private $dbGroup = null; - /** The dblayeroo object use to manage the GroupMember table */ - private $dbGroupMember = null; - /** The dblayeroo object use to manage the Right table */ - private $dbRight = null; - /** Set the debug level */ - public $debug = 0; - /** A local cache of the rights if multiple tests are needed */ - private $rightCache = null; + /** The table prefix to use */ + public $tableprefix = ""; + /** The dblayeroo object use to manage the Object table */ + private $dbObject = null; + /** The dblayeroo object use to manage the Group table */ + private $dbGroup = null; + /** The dblayeroo object use to manage the GroupMember table */ + private $dbGroupMember = null; + /** The dblayeroo object use to manage the Right table */ + private $dbRight = null; + /** Set the debug level */ + public $debug = 0; + /** A local cache of the rights if multiple tests are needed */ + private $rightCache = null; - /** Get the dbObject - */ - public function dbObject () - { - return $this->dbObject; - } + /** Get the dbObject + */ + public function dbObject() + { + return $this->dbObject; + } - /** Get the dbGroup - */ - public function dbGroup () - { - return $this->dbGroup; - } + /** Get the dbGroup + */ + public function dbGroup() + { + return $this->dbGroup; + } - /** Get the dbGroupMember - */ - public function dbGroupMember () - { - return $this->dbGroupMember; - } + /** Get the dbGroupMember + */ + public function dbGroupMember() + { + return $this->dbGroupMember; + } - /** Get the dbRight - */ - public function dbRight () - { - return $this->dbRight; - } + /** Get the dbRight + */ + public function dbRight() + { + return $this->dbRight; + } - ///////////////////// - // USER RIGHTS // - ///////////////////// - /** Return an array with all the rights of the user in the module. - * Cache this information to be quicker with next requests - * Remove the entries where path is not at least readable - * @param string $module The module to use - * @param string $user The user to get the rights - */ - public function userrightsget ($module, $user) - { + ///////////////////// + // USER RIGHTS // + ///////////////////// + /** Return an array with all the rights of the user in the module. + * Cache this information to be quicker with next requests + * Remove the entries where path is not at least readable + * @param string $module The module to use + * @param string $user The user to get the rights + */ + public function userrightsget($module, $user) + { // if (isset ($_SESSION["domframework"]["authzgroups"][$module][$user])) // return $_SESSION["domframework"]["authzgroups"][$module][$user]; - if ($this->rightCache !== null) - return $this->rightCache; - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - // Do the SQL request in hard to be more performant on jointures - if ($user === "cli" || $user === "root") - { - $this->dbObject->clearRequest (); - $resTmp = $this->dbObject->select () - ->displayAdd ("object", "object") - ->displayAdd ("2", "right") - ->whereAdd ("module", "=", $module) - ->execute (); - } - else - { - $this->dbObject->clearRequest (); - $this->dbGroupMember->clearRequest (); - $this->dbGroup->clearRequest (); - $this->dbGroupMember->whereAdd ("user", "=", $user); - $this->dbGroup->joinInner ($this->dbGroupMember, - array ("idgroup" => "idgroup")) - ->whereAdd ("module", "=", $module); - $this->dbRight->displayAdd ("MAX(right)", "right") - ->joinInner ($this->dbGroup, - array ("idgroup" => "idgroup")); - $resTmp = $this->dbObject->select () - ->displayAdd ("object", "object") - ->orderAdd ("object", "ASC") - ->joinInner ($this->dbRight, - array ("idobject" => "idobject")) - ->execute (); + if ($this->rightCache !== null) { + return $this->rightCache; + } + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + // Do the SQL request in hard to be more performant on jointures + if ($user === "cli" || $user === "root") { + $this->dbObject->clearRequest(); + $resTmp = $this->dbObject->select() + ->displayAdd("object", "object") + ->displayAdd("2", "right") + ->whereAdd("module", "=", $module) + ->execute(); + } else { + $this->dbObject->clearRequest(); + $this->dbGroupMember->clearRequest(); + $this->dbGroup->clearRequest(); + $this->dbGroupMember->whereAdd("user", "=", $user); + $this->dbGroup->joinInner( + $this->dbGroupMember, + array("idgroup" => "idgroup") + ) + ->whereAdd("module", "=", $module); + $this->dbRight->displayAdd("MAX(right)", "right") + ->joinInner( + $this->dbGroup, + array("idgroup" => "idgroup") + ); + $resTmp = $this->dbObject->select() + ->displayAdd("object", "object") + ->orderAdd("object", "ASC") + ->joinInner( + $this->dbRight, + array("idobject" => "idobject") + ) + ->execute(); + } + + $res = array(); + foreach ($resTmp as $row) { + $res[$row["object"]] = $row["right"]; + } + // Transform the numerical rights to RO/RW + foreach ($res as $k => $r) { + switch ($r) { + case "2": + $res[$k] = "RW"; + break; + case "1": + $res[$k] = "RO"; + break; + case "0": + $res[$k] = "NO"; + break; + default: + throw new \Exception(dgettext( + "domframework", + "Unknown right stored" + ), 500); + } + } + if (isset($_SESSION)) { + $_SESSION["domframework"]["authzgroups"][$module][$user] = $res; + } + $this->rightCache = $res; + return $res; } - $res = array (); - foreach ($resTmp as $row) - $res[$row["object"]] = $row["right"]; - // Transform the numerical rights to RO/RW - foreach ($res as $k => $r) + /** Return the right defined for this user in the module for one object + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to return the rights for the user + */ + public function allow($module, $user, $object) { - switch ($r) - { - case "2": $res[$k] = "RW"; break; - case "1": $res[$k] = "RO"; break; - case "0": $res[$k] = "NO"; break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right stored"), 500); - } + $ressource = $this->userrightsget($module, $user); + // The complete tree should not be readable for the user : it can have + // access to a card, but not to all the cards (group -> reject, + // group/XXX->allow) + /*// Limit to allowed trees : if a member of the path is not recorded (is + // unreadable), return NO. + // Can be the last entry (the complete object) too + $path = explode ("/", $object); + $completePath = "/"; + foreach ($path as $k => $p) + { + if ($k>1) + $completePath .= "/"; + $completePath .= "$p"; + if (! isset ($ressource[$completePath])) + { + if ($this->debug) + echo "DEBUG allow : REJECT because $completePath is not found\n"; + return "NO"; + } + }*/ + if (! isset($ressource[$object])) { + return "NO"; + } + return $ressource[$object]; } - if (isset ($_SESSION)) - $_SESSION["domframework"]["authzgroups"][$module][$user] = $res; - $this->rightCache = $res; - return $res; - } - /** Return the right defined for this user in the module for one object - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to return the rights for the user - */ - public function allow ($module, $user, $object) - { - $ressource = $this->userrightsget ($module, $user); - // The complete tree should not be readable for the user : it can have - // access to a card, but not to all the cards (group -> reject, - // group/XXX->allow) - /*// Limit to allowed trees : if a member of the path is not recorded (is - // unreadable), return NO. - // Can be the last entry (the complete object) too - $path = explode ("/", $object); - $completePath = "/"; - foreach ($path as $k => $p) + /** Return TRUE if the user right allow to see the object (RO or RW) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessRight($module, $user, $object) { - if ($k>1) - $completePath .= "/"; - $completePath .= "$p"; - if (! isset ($ressource[$completePath])) - { - if ($this->debug) - echo "DEBUG allow : REJECT because $completePath is not found\n"; - return "NO"; - } - }*/ - if (! isset ($ressource[$object])) - return "NO"; - return $ressource[$object]; - } - - /** Return TRUE if the user right allow to see the object (RO or RW) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessRight ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessRight without ". + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessRight without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ("Module not provided to authzgroups\\accessRight", - 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessright", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ("Object not provided to authzgroups\\accessRight", - 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, "$object"); - if ($this->debug) - trigger_error ("authzgroups : accessRight ('$module', '$user', ". - "'$object')=$rc", E_USER_NOTICE); - if ($rc !== "NO") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Access forbidden"), 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessRight", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessright", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessRight", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, "$object"); + if ($this->debug) { + trigger_error("authzgroups : accessRight ('$module', '$user', " . + "'$object')=$rc", E_USER_NOTICE); + } + if ($rc !== "NO") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception(dgettext("domframework", "Access forbidden"), 403); + } - /** Return TRUE if the user right allow to edit the object (RW only) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessWrite ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessWrite without ". + /** Return TRUE if the user right allow to edit the object (RW only) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessWrite($module, $user, $object) + { + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessWrite without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ("Module not provided to authzgroups\\accessWrite", - 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessWrite", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ("Object not provided to authzgroups\\accessWrite", - 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, $object); - if ($this->debug) - trigger_error ("authzgroups : accessWrite ('$module', '$user', ". - "'$object')=$rc", E_USER_NOTICE); - if ($rc === "RW") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Modification forbidden"), - 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessWrite", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, $object); + if ($this->debug) { + trigger_error("authzgroups : accessWrite ('$module', '$user', " . + "'$object')=$rc", E_USER_NOTICE); + } + if ($rc === "RW") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception( + dgettext("domframework", "Modification forbidden"), + 403 + ); + } - /** Return TRUE if the user right allow to see but without modification - * the object (RO only) - * Return a 403 Exception if the user don't have the right - * Return a 401 Exception if the user is not connected - * @param string $module The module to use - * @param string $user The user to get the rights - * @param string $object The object to check the rights for the user - */ - public function accessReadOnly ($module, $user, $object) - { - if ($this->dbObject === null) - throw new \Exception ("Can't use authzgroups\\accessReadOnly without ". + /** Return TRUE if the user right allow to see but without modification + * the object (RO only) + * Return a 403 Exception if the user don't have the right + * Return a 401 Exception if the user is not connected + * @param string $module The module to use + * @param string $user The user to get the rights + * @param string $object The object to check the rights for the user + */ + public function accessReadOnly($module, $user, $object) + { + if ($this->dbObject === null) { + throw new \Exception("Can't use authzgroups\\accessReadOnly without " . "connected database", 500); - if ($module === null || ! is_string ($module) || trim ($module) === "") - throw new \Exception ( - "Module not provided to authzgroups\\accessReadOnly", 500); - if ($user === null || ! is_string ($user) || trim ($user) === "") - throw new \Exception ("User not provided to authzgroups\\accessReadOnly", - 500); - if ($object === null || ! is_string ($object)) - throw new \Exception ( - "Object not provided to authzgroups\\accessReadOnly", 500); - if ($object[0] !== "/") - $object = "/$object"; - $rc = $this->allow ($module, $user, $object); - if ($this->debug) - trigger_error ("authzgroups : accessReadOnly ('$module', '$user', ". - "'$object')" ."=$rc", E_USER_NOTICE); - if ($rc === "RO") - return TRUE; - if ($user === "anonymous") - throw new \Exception (dgettext ("domframework", "Anonymous not allowed"), - 401); - throw new \Exception (dgettext ("domframework", "Access forbidden"), 403); - } + } + if ($module === null || ! is_string($module) || trim($module) === "") { + throw new \Exception( + "Module not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($user === null || ! is_string($user) || trim($user) === "") { + throw new \Exception( + "User not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($object === null || ! is_string($object)) { + throw new \Exception( + "Object not provided to authzgroups\\accessReadOnly", + 500 + ); + } + if ($object[0] !== "/") { + $object = "/$object"; + } + $rc = $this->allow($module, $user, $object); + if ($this->debug) { + trigger_error("authzgroups : accessReadOnly ('$module', '$user', " . + "'$object')" . "=$rc", E_USER_NOTICE); + } + if ($rc === "RO") { + return true; + } + if ($user === "anonymous") { + throw new \Exception( + dgettext("domframework", "Anonymous not allowed"), + 401 + ); + } + throw new \Exception(dgettext("domframework", "Access forbidden"), 403); + } - ///////////////////////// - // DATABASE STORAGE // - ///////////////////////// - /** Connect to the database before using it - * @param string $dsn The DSN to use to connect to the database - * @param string|null $username The username to use to connect to the - * database - * @param string|null $password The password to use to connect to the - * database - * @param array|null $driver_options The options to pass to PDO driver - */ - public function connect ($dsn, $username=null, $password=null, - $driver_options=null) - { - $this->dbObject = new Dblayeroo ($dsn, $username, $password, - $driver_options); - $this->dbObject->debug ($this->debug); - $this->dbObject->table ("authzobject"); - $this->dbObject->tableprefix ($this->tableprefix); - $this->dbObject->fields (array ( - "idobject" => array ("integer", "not null", "autoincrement"), - "module" => array ("varchar(255)", "not null"), - "object" => array ("varchar(255)", "not null"), - "comment" => array ("varchar(255)"))); - $this->dbObject->primary ("idobject"); - $this->dbObject->unique (array ("idobject", array ("object", "module"))); - $this->dbObject->titles (array ( - "idobject" => dgettext ("domframework", "idobject"), - "module" => dgettext ("domframework", "Module"), - "object" => dgettext ("domframework", "Object"), - "comment" => dgettext ("domframework", "Comment"))); + ///////////////////////// + // DATABASE STORAGE // + ///////////////////////// + /** Connect to the database before using it + * @param string $dsn The DSN to use to connect to the database + * @param string|null $username The username to use to connect to the + * database + * @param string|null $password The password to use to connect to the + * database + * @param array|null $driver_options The options to pass to PDO driver + */ + public function connect( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + $this->dbObject = new Dblayeroo( + $dsn, + $username, + $password, + $driver_options + ); + $this->dbObject->debug($this->debug); + $this->dbObject->table("authzobject"); + $this->dbObject->tableprefix($this->tableprefix); + $this->dbObject->fields(array( + "idobject" => array("integer", "not null", "autoincrement"), + "module" => array("varchar(255)", "not null"), + "object" => array("varchar(255)", "not null"), + "comment" => array("varchar(255)"))); + $this->dbObject->primary("idobject"); + $this->dbObject->unique(array("idobject", array("object", "module"))); + $this->dbObject->titles(array( + "idobject" => dgettext("domframework", "idobject"), + "module" => dgettext("domframework", "Module"), + "object" => dgettext("domframework", "Object"), + "comment" => dgettext("domframework", "Comment"))); - $this->dbGroup = new Dblayeroo ($dsn, $username, $password, - $driver_options); - $this->dbGroup->debug ($this->debug); - $this->dbGroup->table ("authzgroup"); - $this->dbGroup->tableprefix ($this->tableprefix); - $this->dbGroup->fields (array ( - "idgroup" => array ("integer", "not null", "autoincrement"), - "module" => array ("varchar(255)", "not null"), - "group" => array ("varchar(255)", "not null"), - "comment" => array ("varchar(255)"))); - $this->dbGroup->primary ("idgroup"); - $this->dbGroup->unique (array ("idgroup", array ("module", "group"))); - $this->dbGroup->titles (array ( - "idgroup" => dgettext ("domframework", "idgroup"), - "module" => dgettext ("domframework", "Module"), - "group" => dgettext ("domframework", "Group"), - "comment" => dgettext ("domframework", "Comment"))); + $this->dbGroup = new Dblayeroo( + $dsn, + $username, + $password, + $driver_options + ); + $this->dbGroup->debug($this->debug); + $this->dbGroup->table("authzgroup"); + $this->dbGroup->tableprefix($this->tableprefix); + $this->dbGroup->fields(array( + "idgroup" => array("integer", "not null", "autoincrement"), + "module" => array("varchar(255)", "not null"), + "group" => array("varchar(255)", "not null"), + "comment" => array("varchar(255)"))); + $this->dbGroup->primary("idgroup"); + $this->dbGroup->unique(array("idgroup", array("module", "group"))); + $this->dbGroup->titles(array( + "idgroup" => dgettext("domframework", "idgroup"), + "module" => dgettext("domframework", "Module"), + "group" => dgettext("domframework", "Group"), + "comment" => dgettext("domframework", "Comment"))); - $this->dbGroupMember = new Dblayeroo ($dsn, $username, $password, - $driver_options); - $this->dbGroupMember->debug ($this->debug); - $this->dbGroupMember->table ("authzgroupmember"); - $this->dbGroupMember->tableprefix ($this->tableprefix); - $this->dbGroupMember->fields (array ( - "idgroupmember" => array ("integer", "not null", "autoincrement"), - "user" => array ("varchar(255)", "not null"), - "idgroup" => array ("integer", "not null"), - "comment" => array ("varchar(255)"))); - $this->dbGroupMember->primary ("idgroupmember"); - $this->dbGroupMember->unique (array ("idgroupmember", - array ("user", "idgroup"))); - $this->dbGroupMember->foreign (array ( - "idgroup" => array ($this->tableprefix."authzgroup", "idgroup", + $this->dbGroupMember = new Dblayeroo( + $dsn, + $username, + $password, + $driver_options + ); + $this->dbGroupMember->debug($this->debug); + $this->dbGroupMember->table("authzgroupmember"); + $this->dbGroupMember->tableprefix($this->tableprefix); + $this->dbGroupMember->fields(array( + "idgroupmember" => array("integer", "not null", "autoincrement"), + "user" => array("varchar(255)", "not null"), + "idgroup" => array("integer", "not null"), + "comment" => array("varchar(255)"))); + $this->dbGroupMember->primary("idgroupmember"); + $this->dbGroupMember->unique(array("idgroupmember", + array("user", "idgroup"))); + $this->dbGroupMember->foreign(array( + "idgroup" => array($this->tableprefix . "authzgroup", "idgroup", "ON UPDATE CASCADE ON DELETE CASCADE"))); - $this->dbGroupMember->setForeignObj ($this->dbGroup); - $this->dbGroupMember->titles (array ( - "idgroupmember" => dgettext ("domframework", "idgroupmember"), - "user" => dgettext ("domframework", "User"), - "idgroup" => dgettext ("domframework", "idgroup"), - "comment" => dgettext ("domframework", "Comment"))); + $this->dbGroupMember->setForeignObj($this->dbGroup); + $this->dbGroupMember->titles(array( + "idgroupmember" => dgettext("domframework", "idgroupmember"), + "user" => dgettext("domframework", "User"), + "idgroup" => dgettext("domframework", "idgroup"), + "comment" => dgettext("domframework", "Comment"))); - $this->dbRight = new Dblayeroo ($dsn, $username, $password, - $driver_options); - $this->dbRight->debug ($this->debug); - $this->dbRight->table ("authzright"); - $this->dbRight->tableprefix ($this->tableprefix); - $this->dbRight->fields (array ( - "idright" => array ("integer", "not null", "autoincrement"), - "idgroup" => array ("integer", "not null"), - "idobject" => array ("integer", "not null"), - "right" => array ("varchar(2)", "not null"), // NO, RO, RW - "comment" => array ("varchar(255)"))); - $this->dbRight->primary ("idright"); - $this->dbRight->unique (array ("idright", array ("idgroup", "idobject"))); - $this->dbRight->foreign (array ( - "idgroup" => array ($this->tableprefix."authzgroup", "idgroup", + $this->dbRight = new Dblayeroo( + $dsn, + $username, + $password, + $driver_options + ); + $this->dbRight->debug($this->debug); + $this->dbRight->table("authzright"); + $this->dbRight->tableprefix($this->tableprefix); + $this->dbRight->fields(array( + "idright" => array("integer", "not null", "autoincrement"), + "idgroup" => array("integer", "not null"), + "idobject" => array("integer", "not null"), + "right" => array("varchar(2)", "not null"), // NO, RO, RW + "comment" => array("varchar(255)"))); + $this->dbRight->primary("idright"); + $this->dbRight->unique(array("idright", array("idgroup", "idobject"))); + $this->dbRight->foreign(array( + "idgroup" => array($this->tableprefix . "authzgroup", "idgroup", "ON UPDATE CASCADE ON DELETE CASCADE"), - "idobject" => array ($this->tableprefix."authzobject", "idobject", + "idobject" => array($this->tableprefix . "authzobject", "idobject", "ON UPDATE CASCADE ON DELETE CASCADE"), - )); - $this->dbRight->setForeignObj ($this->dbGroup); - $this->dbRight->setForeignObj ($this->dbObject); - $this->dbRight->titles (array ( - "idright" => dgettext ("domframework", "idright"), - "idgroup" => dgettext ("domframework", "idgroup"), - "idobject" => dgettext ("domframework", "idobject"), - "right" => dgettext ("domframework", "Right"), - "comment" => dgettext ("domframework", "Comment"))); - return TRUE; - } - - /** Disconnect from the database. Should be only used in the unit tests - */ - public function disconnect () - { - $this->dbObject->disconnect (); - } - - /** Create the tables in the database to store the data - */ - public function createTables () - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $tables = array ("Object", "Group", "GroupMember", "Right"); - foreach ($tables as $table) - { - try - { - $class= "db$table"; - $this->$class->createTable (); - } - catch (\Exception $e) - { - echo $e->getMessage()."\n"; - } + )); + $this->dbRight->setForeignObj($this->dbGroup); + $this->dbRight->setForeignObj($this->dbObject); + $this->dbRight->titles(array( + "idright" => dgettext("domframework", "idright"), + "idgroup" => dgettext("domframework", "idgroup"), + "idobject" => dgettext("domframework", "idobject"), + "right" => dgettext("domframework", "Right"), + "comment" => dgettext("domframework", "Comment"))); + return true; } - return TRUE; - } - /** Return true if all the tables are created, false otherwise - */ - public function stateTables () - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $tables = $this->dbObject->listTables (); - $needed = array ("authzobject", "authzgroup", "authzgroupmember", + /** Disconnect from the database. Should be only used in the unit tests + */ + public function disconnect() + { + $this->dbObject->disconnect(); + } + + /** Create the tables in the database to store the data + */ + public function createTables() + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $tables = array("Object", "Group", "GroupMember", "Right"); + foreach ($tables as $table) { + try { + $class = "db$table"; + $this->$class->createTable(); + } catch (\Exception $e) { + echo $e->getMessage() . "\n"; + } + } + return true; + } + + /** Return true if all the tables are created, false otherwise + */ + public function stateTables() + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $tables = $this->dbObject->listTables(); + $needed = array("authzobject", "authzgroup", "authzgroupmember", "authzright"); - foreach ($needed as $table) - { - if (! in_array ($this->tableprefix.$table, $tables)) - return false; + foreach ($needed as $table) { + if (! in_array($this->tableprefix . $table, $tables)) { + return false; + } + } + return true; } - return true; - } - /** Return true if all the tables are deleted, false otherwise - */ - public function deleteTables () - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $tables = $this->dbObject->listTables (); - $needed = array ("Object", "Group", "GroupMember", "Right"); - $needed = array_reverse ($needed); - foreach ($needed as $table) + /** Return true if all the tables are deleted, false otherwise + */ + public function deleteTables() { - $class= "db$table"; - $this->$class->dropTable (); + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $tables = $this->dbObject->listTables(); + $needed = array("Object", "Group", "GroupMember", "Right"); + $needed = array_reverse($needed); + foreach ($needed as $table) { + $class = "db$table"; + $this->$class->dropTable(); + } + return true; } - return true; - } - ///////////////// - // OBJECTS // - ///////////////// - /** Add a new object to object list - * Return the idobject created - * @param string $module The module to use - * @param string $object The object to create - * @param string|null $comment The comment to save - */ - public function objectAdd ($module, $object, $comment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - // TODO : Check parameters before saving them - $this->rightCache = null; - $this->dbObject->clearRequest (); - return $this->dbObject->insert () - ->setValues (array ("module" => $module, + ///////////////// + // OBJECTS // + ///////////////// + /** Add a new object to object list + * Return the idobject created + * @param string $module The module to use + * @param string $object The object to create + * @param string|null $comment The comment to save + */ + public function objectAdd($module, $object, $comment = "") + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + // TODO : Check parameters before saving them + $this->rightCache = null; + $this->dbObject->clearRequest(); + return $this->dbObject->insert() + ->setValues(array("module" => $module, "object" => $object, "comment" => $comment)) - ->execute (); - } + ->execute(); + } - /** Remove an object from database and all the rights using it - * @param string $module The module to use - * @param string $object The object to delete - */ - public function objectDel ($module, $object) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectRead ($module, $object); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbObject->clearRequest (); - return $this->dbObject->delete () - ->whereAdd ("idobject", "=", - $idobjects[0]["idobject"]) - ->execute (); - } + /** Remove an object from database and all the rights using it + * @param string $module The module to use + * @param string $object The object to delete + */ + public function objectDel($module, $object) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectRead($module, $object); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbObject->clearRequest(); + return $this->dbObject->delete() + ->whereAdd( + "idobject", + "=", + $idobjects[0]["idobject"] + ) + ->execute(); + } - /** Remove an object from database and all the rights using it - * @param string $module The module to use - * @param integer $idobject The object to delete - */ - public function objectDelByID ($module, $idobject) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectReadByID ($module, $idobject); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbObject->clearRequest (); - return $this->dbObject->delete () - ->whereAdd ("idobject", "=", - $idobjects[0]["idobject"]) - ->execute (); - } + /** Remove an object from database and all the rights using it + * @param string $module The module to use + * @param integer $idobject The object to delete + */ + public function objectDelByID($module, $idobject) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectReadByID($module, $idobject); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbObject->clearRequest(); + return $this->dbObject->delete() + ->whereAdd( + "idobject", + "=", + $idobjects[0]["idobject"] + ) + ->execute(); + } - /** Update an object in the database - * @param string $module The module to use - * @param string $object The object to update - * @param string $newobject The new name of the object - * @param string|null $newcomment The new comment of the object - */ - public function objectUpdate ($module, $object, $newobject, $newcomment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectRead ($module, $object); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbObject->clearRequest (); - return $this->dbObject->update () - ->whereAdd ("idobject", "=", - $idobjects[0]["idobject"]) - ->setValues (array ("object" => $newobject, + /** Update an object in the database + * @param string $module The module to use + * @param string $object The object to update + * @param string $newobject The new name of the object + * @param string|null $newcomment The new comment of the object + */ + public function objectUpdate($module, $object, $newobject, $newcomment = "") + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectRead($module, $object); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbObject->clearRequest(); + return $this->dbObject->update() + ->whereAdd( + "idobject", + "=", + $idobjects[0]["idobject"] + ) + ->setValues(array("object" => $newobject, "comment" => $newcomment)) - ->execute (); - } + ->execute(); + } - /** Update an object in the database - * @param string $module The module to use - * @param integer $idobject The object to update - * @param string $newobject The new name of the object - * @param string|null $newcomment The new comment of the object - */ - public function objectUpdateByID ($module, $idobject, $newobject, - $newcomment="") - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $idobjects = $this->objectReadByID ($module, $idobject); - if (! isset ($idobjects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbObject->clearRequest (); - return $this->dbObject->update () - ->whereAdd ("idobject", "=", - $idobjects[0]["idobject"]) - ->setValues (array ("object" => $newobject, + /** Update an object in the database + * @param string $module The module to use + * @param integer $idobject The object to update + * @param string $newobject The new name of the object + * @param string|null $newcomment The new comment of the object + */ + public function objectUpdateByID( + $module, + $idobject, + $newobject, + $newcomment = "" + ) { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $idobjects = $this->objectReadByID($module, $idobject); + if (! isset($idobjects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbObject->clearRequest(); + return $this->dbObject->update() + ->whereAdd( + "idobject", + "=", + $idobjects[0]["idobject"] + ) + ->setValues(array("object" => $newobject, "comment" => $newcomment)) - ->execute (); - } + ->execute(); + } - /** Return an array with all the available objects in the module, or only - * one object if $object is provided - * @param string $module The module to use - * @param string $object The name of the object to get - */ - public function objectRead ($module, $object=null) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $this->dbObject->clearRequest (); - if ($object !== null) - $this->dbObject->whereAdd ("object", "=", $object); - return $this->dbObject->select () - ->whereAdd ("module", "=", $module) - ->orderAdd ("object", "ASC") - ->execute (); - } + /** Return an array with all the available objects in the module, or only + * one object if $object is provided + * @param string $module The module to use + * @param string $object The name of the object to get + */ + public function objectRead($module, $object = null) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $this->dbObject->clearRequest(); + if ($object !== null) { + $this->dbObject->whereAdd("object", "=", $object); + } + return $this->dbObject->select() + ->whereAdd("module", "=", $module) + ->orderAdd("object", "ASC") + ->execute(); + } - /** Return an array with all the available objects in the module, or only - * one object if $object is provided - * @param string $module The module to use - * @param integer $idobject The name of the object to get - */ - public function objectReadByID ($module, $idobject=null) - { - if ($this->dbObject == null) - throw new \Exception (dgettext ("domframework", - "DB for Object is not connected"), 500); - $this->dbObject->clearRequest (); - if ($idobject !== null) - $this->dbObject->whereAdd ("idobject", "=", $idobject); - return $this->dbObject->select () - ->whereAdd ("module", "=", $module) - ->execute (); - } + /** Return an array with all the available objects in the module, or only + * one object if $object is provided + * @param string $module The module to use + * @param integer $idobject The name of the object to get + */ + public function objectReadByID($module, $idobject = null) + { + if ($this->dbObject == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Object is not connected" + ), 500); + } + $this->dbObject->clearRequest(); + if ($idobject !== null) { + $this->dbObject->whereAdd("idobject", "=", $idobject); + } + return $this->dbObject->select() + ->whereAdd("module", "=", $module) + ->execute(); + } - /** Return an array containing the titles of the table translating in the user - * language - */ - public function objectTitles () - { - return $this->dbObject->titles (); - } + /** Return an array containing the titles of the table translating in the user + * language + */ + public function objectTitles() + { + return $this->dbObject->titles(); + } - /** Check if the provided data are compliant with the object specification - * @param array $data The name of the object to get - * @param integer|null $idobject The object to check - * @return array The errors found in the data - */ - public function objectVerify ($data, $idobject=false) - { - return $this->dbObject->verify ($data, $idobject); - } + /** Check if the provided data are compliant with the object specification + * @param array $data The name of the object to get + * @param integer|null $idobject The object to check + * @return array The errors found in the data + */ + public function objectVerify($data, $idobject = false) + { + return $this->dbObject->verify($data, $idobject); + } - //////////////// - // GROUPS // - //////////////// - /** Add a new group to group list - * Return the idgroup created - * @param string $module The module to use - * @param string $group The group to create - * @param string|null $comment The comment to add with the group - */ - public function groupAdd ($module, $group, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $this->dbGroup->clearRequest (); - // TODO : Check parameters before saving them - return $this->dbGroup->insert () - ->setValues (array ("module" => $module, + //////////////// + // GROUPS // + //////////////// + /** Add a new group to group list + * Return the idgroup created + * @param string $module The module to use + * @param string $group The group to create + * @param string|null $comment The comment to add with the group + */ + public function groupAdd($module, $group, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $this->dbGroup->clearRequest(); + // TODO : Check parameters before saving them + return $this->dbGroup->insert() + ->setValues(array("module" => $module, "group" => $group, "comment" => $comment)) - ->execute (); - } + ->execute(); + } - /** Remove an group from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to delete - */ - public function groupDel ($module, $group) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupRead ($module, $group); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroup->clearRequest (); - return $this->dbGroup->delete () - ->whereAdd ("idgroup", "=", $idgroups[0]["idgroup"]) - ->execute (); - } + /** Remove an group from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to delete + */ + public function groupDel($module, $group) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupRead($module, $group); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroup->clearRequest(); + return $this->dbGroup->delete() + ->whereAdd("idgroup", "=", $idgroups[0]["idgroup"]) + ->execute(); + } - /** Remove an group from database and all the rights using it - * @param string $module The module to use - * @param integer $idgroup The group to delete - */ - public function groupDelByID ($module, $idgroup) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupReadByID ($module, $idgroup); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroup->clearRequest (); - return $this->dbGroup->delete () - ->whereAdd ("idgroup", "=", $idgroups[0]["idgroup"]) - ->execute (); - } + /** Remove an group from database and all the rights using it + * @param string $module The module to use + * @param integer $idgroup The group to delete + */ + public function groupDelByID($module, $idgroup) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupReadByID($module, $idgroup); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroup->clearRequest(); + return $this->dbGroup->delete() + ->whereAdd("idgroup", "=", $idgroups[0]["idgroup"]) + ->execute(); + } - /** Update an group in the database - * @param string $module The module to use - * @param string $group The group to update - * @param string $newgroup The new group name - * @param string|null $comment The comment for the group - */ - public function groupUpdate ($module, $group, $newgroup, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupRead ($module, $group); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroup->clearRequest (); - return $this->dbGroup->update () - ->whereAdd ("idgroup", "=", $idgroups[0]["idgroup"]) - ->setValues (array ("group" => $newgroup, + /** Update an group in the database + * @param string $module The module to use + * @param string $group The group to update + * @param string $newgroup The new group name + * @param string|null $comment The comment for the group + */ + public function groupUpdate($module, $group, $newgroup, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupRead($module, $group); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroup->clearRequest(); + return $this->dbGroup->update() + ->whereAdd("idgroup", "=", $idgroups[0]["idgroup"]) + ->setValues(array("group" => $newgroup, "comment" => $comment)) - ->execute (); - } + ->execute(); + } - /** Update an group in the database - * @param string $module The module to use - * @param integer $idgroup The group to update - * @param string $newgroup The new group name - * @param string|null $comment The comment for the group - */ - public function groupUpdateByID ($module, $idgroup, $newgroup, $comment="") - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $idgroups = $this->groupReadByID ($module, $idgroup); - if (! isset ($idgroups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroup->clearRequest (); - return $this->dbGroup->update () - ->whereAdd ("idgroup", "=", $idgroups[0]["idgroup"]) - ->setValues (array ("group" => $newgroup, + /** Update an group in the database + * @param string $module The module to use + * @param integer $idgroup The group to update + * @param string $newgroup The new group name + * @param string|null $comment The comment for the group + */ + public function groupUpdateByID($module, $idgroup, $newgroup, $comment = "") + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $idgroups = $this->groupReadByID($module, $idgroup); + if (! isset($idgroups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroup->clearRequest(); + return $this->dbGroup->update() + ->whereAdd("idgroup", "=", $idgroups[0]["idgroup"]) + ->setValues(array("group" => $newgroup, "comment" => $comment)) - ->execute (); - } + ->execute(); + } - /** Return an array with all the available groups in the module - * @param string $module The module to use - * @param string|null $group The group to check if exists - */ - public function groupRead ($module, $group=null) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $this->dbGroup->clearRequest (); - if ($group !== null) - $this->dbGroup->whereAdd ("group", "=", $group); - return $this->dbGroup->select () - ->whereAdd ("module", "=", $module) - ->orderAdd ("group", "ASC") - ->execute (); - } + /** Return an array with all the available groups in the module + * @param string $module The module to use + * @param string|null $group The group to check if exists + */ + public function groupRead($module, $group = null) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $this->dbGroup->clearRequest(); + if ($group !== null) { + $this->dbGroup->whereAdd("group", "=", $group); + } + return $this->dbGroup->select() + ->whereAdd("module", "=", $module) + ->orderAdd("group", "ASC") + ->execute(); + } - /** Return an array with all the available groups in the module - * @param string $module The module to use - * @param integer $idgroup The group to check if exists - */ - public function groupReadByID ($module, $idgroup) - { - if ($this->dbGroup == null) - throw new \Exception (dgettext ("domframework", - "DB for Group is not connected"), 500); - $this->dbGroup->clearRequest (); - return $this->dbGroup->select () - ->whereAdd ("module", "=", $module) - ->whereAdd ("idgroup", "=", $idgroup) - ->execute (); - } + /** Return an array with all the available groups in the module + * @param string $module The module to use + * @param integer $idgroup The group to check if exists + */ + public function groupReadByID($module, $idgroup) + { + if ($this->dbGroup == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Group is not connected" + ), 500); + } + $this->dbGroup->clearRequest(); + return $this->dbGroup->select() + ->whereAdd("module", "=", $module) + ->whereAdd("idgroup", "=", $idgroup) + ->execute(); + } - /** Return an array containing the titles of the table translating in the user - * language - */ - public function groupTitles () - { - return $this->dbGroup->titles (); - } + /** Return an array containing the titles of the table translating in the user + * language + */ + public function groupTitles() + { + return $this->dbGroup->titles(); + } - /** Check if the provided data are compilant with the group specification - * @param array $data The data to check - * @param integer|null $idgroup The idgroup to check - * @return array The errors found in the data - */ - public function groupVerify ($data, $idgroup=false) - { - return $this->dbGroup->verify ($data, $idgroup); - } + /** Check if the provided data are compilant with the group specification + * @param array $data The data to check + * @param integer|null $idgroup The idgroup to check + * @return array The errors found in the data + */ + public function groupVerify($data, $idgroup = false) + { + return $this->dbGroup->verify($data, $idgroup); + } - ////////////////////// - // GROUP MEMBER // - ////////////////////// - /** Add a new groupmember to groupmember list - * Return the idgroupmember created - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to add in group - * @param string|null $comment The comment to save - */ - public function groupmemberAdd ($module, $group, $user, $comment="") - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->rightCache = null; - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->insert () - ->setValues (array ( + ////////////////////// + // GROUP MEMBER // + ////////////////////// + /** Add a new groupmember to groupmember list + * Return the idgroupmember created + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to add in group + * @param string|null $comment The comment to save + */ + public function groupmemberAdd($module, $group, $user, $comment = "") + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->rightCache = null; + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->insert() + ->setValues(array( "user" => $user, "idgroup" => $groups[0]["idgroup"], "comment" => $comment)) - ->execute (); - } + ->execute(); + } - /** Remove an groupmember from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to remove - */ - public function groupmemberDel ($module, $group, $user) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroupMember->clearRequest (); - $groupsMembers = $this->dbGroupMember->select () - ->whereAdd ("user", "=", $user) - ->whereAdd ("idgroup", "=", - $groups[0]["idgroup"]) - ->execute (); - if (! isset ($groupsMembers[0]["idgroupmember"])) - throw new \Exception (dgettext ("domframework", - "Wanted GroupMember not found"), 404); - $this->rightCache = null; - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->delete () - ->whereAdd ("idgroupmember", "=", - $groupsMembers[0]["idgroupmember"]) - ->execute (); - } + /** Remove an groupmember from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to remove + */ + public function groupmemberDel($module, $group, $user) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroupMember->clearRequest(); + $groupsMembers = $this->dbGroupMember->select() + ->whereAdd("user", "=", $user) + ->whereAdd( + "idgroup", + "=", + $groups[0]["idgroup"] + ) + ->execute(); + if (! isset($groupsMembers[0]["idgroupmember"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted GroupMember not found" + ), 404); + } + $this->rightCache = null; + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->delete() + ->whereAdd( + "idgroupmember", + "=", + $groupsMembers[0]["idgroupmember"] + ) + ->execute(); + } - /** Remove an groupmember from database and all the rights using it - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $idgroupmember The user to remove - */ - public function groupmemberDelByID ($module, $idgroup, $idgroupmember) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroupMember->clearRequest (); - $groupsMembers = $this->dbGroupMember->select () - ->whereAdd ("idgroupmember", "=", - $idgroupmember) - ->whereAdd ("idgroup", "=", $idgroup) - ->execute (); - if (! isset ($groupsMembers[0]["idgroupmember"])) - throw new \Exception (dgettext ("domframework", - "Wanted GroupMember not found"), 404); - $this->rightCache = null; - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->delete () - ->whereAdd ("idgroupmember", "=", - $groupsMembers[0]["idgroupmember"]) - ->execute (); - } + /** Remove an groupmember from database and all the rights using it + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $idgroupmember The user to remove + */ + public function groupmemberDelByID($module, $idgroup, $idgroupmember) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroupMember->clearRequest(); + $groupsMembers = $this->dbGroupMember->select() + ->whereAdd( + "idgroupmember", + "=", + $idgroupmember + ) + ->whereAdd("idgroup", "=", $idgroup) + ->execute(); + if (! isset($groupsMembers[0]["idgroupmember"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted GroupMember not found" + ), 404); + } + $this->rightCache = null; + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->delete() + ->whereAdd( + "idgroupmember", + "=", + $groupsMembers[0]["idgroupmember"] + ) + ->execute(); + } - /** Update an groupmember in the database - * @param string $module The module to use - * @param string $group The group to use - * @param string $user The user to update - * @param string|null $comment The comment to update - */ - public function groupmemberUpdate ($module, $group, $user, $comment="") - { - $this->rightCache = null; - die ("This function is not available : contact us if you need it\n"); - } + /** Update an groupmember in the database + * @param string $module The module to use + * @param string $group The group to use + * @param string $user The user to update + * @param string|null $comment The comment to update + */ + public function groupmemberUpdate($module, $group, $user, $comment = "") + { + $this->rightCache = null; + die("This function is not available : contact us if you need it\n"); + } - /** Update an groupmember in the database - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $iduser The user to update - * @param string $user The new user name - * @param string|null $comment The comment to update - */ - public function groupmemberUpdateByID ($module, $idgroup, $iduser, $user, - $comment="") - { - $data = $this->groupmemberReadUserDataByID ($module, $idgroup, $iduser); - if (count ($data) === 0) - throw new \Exception (dgettext ("domframework", - "IDUser in IDGroup not found"), 404); - $this->rightCache = null; - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->update () - ->whereAdd ("idgroupmember", "=", - $data[0]["idgroupmember"]) - ->setValues (array ("user" => $user, + /** Update an groupmember in the database + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $iduser The user to update + * @param string $user The new user name + * @param string|null $comment The comment to update + */ + public function groupmemberUpdateByID( + $module, + $idgroup, + $iduser, + $user, + $comment = "" + ) { + $data = $this->groupmemberReadUserDataByID($module, $idgroup, $iduser); + if (count($data) === 0) { + throw new \Exception(dgettext( + "domframework", + "IDUser in IDGroup not found" + ), 404); + } + $this->rightCache = null; + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->update() + ->whereAdd( + "idgroupmember", + "=", + $data[0]["idgroupmember"] + ) + ->setValues(array("user" => $user, "comment" => $comment)) - ->execute (); - } - - - /** Return an array with all the groups where the user is in and in the module - * @param string $module The module to use - * @param string $user The user to search - */ - public function groupmemberReadUser ($module, $user) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $idgrouptmps = $this->groupRead ($module); - // Create an array with idgroup=>group - $idgroups = array (); - foreach ($idgrouptmps as $val) - $idgroups[$val["idgroup"]] = $val["group"]; - $this->dbGroupMember->clearRequest (); - $idgroupmembers = $this->dbGroupMember->select () - ->whereAdd ("user", "=", $user) - ->execute (); - $res = array (); - foreach ($idgroupmembers as $idmembers) - { - $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + ->execute(); } - return $res; - } - /** Return an array with all the groups where the user is in and in the module - * @param string $module The module to use - * @param integer $idgroupmember The user to search - */ - public function groupmemberReadUserByID ($module, $idgroupmember) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $idgrouptmps = $this->groupRead ($module); - // Create an array with idgroup=>group - $idgroups = array (); - foreach ($idgrouptmps as $val) - $idgroups[$val["idgroup"]] = $val["group"]; - $this->dbGroupMember->clearRequest (); - $this->dbGroupMember->whereAdd ("idgroupmember", "=", $idgroupmember); - $idgroupmembers = $this->dbGroupMember->select ()->execute (); - $res = array (); - foreach ($idgroupmembers as $idmembers) + + /** Return an array with all the groups where the user is in and in the module + * @param string $module The module to use + * @param string $user The user to search + */ + public function groupmemberReadUser($module, $user) { - $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $idgrouptmps = $this->groupRead($module); + // Create an array with idgroup=>group + $idgroups = array(); + foreach ($idgrouptmps as $val) { + $idgroups[$val["idgroup"]] = $val["group"]; + } + $this->dbGroupMember->clearRequest(); + $idgroupmembers = $this->dbGroupMember->select() + ->whereAdd("user", "=", $user) + ->execute(); + $res = array(); + foreach ($idgroupmembers as $idmembers) { + $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + } + return $res; } - return $res; - } - /** Return an array with all the available users in the group and in the - * module - * @param string $module The module to use - * @param string $group The group to search - */ - public function groupmemberReadGroup ($module, $group) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->select () - ->whereAdd ("idgroup", "=", - $groups[0]["idgroup"]) - ->displayAdd ("user") - ->execute (); - } - - /** Return an array with all the available users in the group and in the - * module - * @param string $module The module to use - * @param integer $idgroup The group to search - */ - public function groupmemberReadGroupByID ($module, $idgroup) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->select () - ->whereAdd ("idgroup", "=", - $groups[0]["idgroup"]) - ->execute (); - } - - /** Return an array containing the information of a user in a specific group - * @param string $module The module to use - * @param integer $idgroup The group to search - * @param integer $iduser The user to search - */ - public function groupmemberReadUserDataByID ($module, $idgroup, $iduser) - { - if ($this->dbGroupMember == null) - throw new \Exception (dgettext ("domframework", - "DB for GroupMember is not connected"), - 500); - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $this->dbGroupMember->clearRequest (); - return $this->dbGroupMember->select () - ->whereAdd ("idgroup", "=", - $groups[0]["idgroup"]) - ->whereAdd ("idgroupmember", "=", $iduser) - ->execute (); - } - - /** Return an array containing the titles of the table translating in the user - * language - */ - public function groupmembersTitles () - { - return $this->dbGroupMember->titles (); - } - - /** Check if the provided data are compilant with the group specification - * @param array $data The data to check - * @param integer|null $idgroupmember The group member associated to verify - * @return array The errors found in the data - */ - public function groupmembersVerify ($data, $idgroupmember=false) - { - return $this->dbGroupMember->verify ($data, $idgroupmember); - } - - //////////////// - // RIGHTS // - //////////////// - /** Add a new right to right list - * Return the idright created - * @param string $module The module to use - * @param string $group The group to use - * @param string $object The object to use - * @param string $right The right to add - * @param string|null $comment The comment to add - */ - public function rightAdd ($module, $group, $object, $right, $comment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($right) + /** Return an array with all the groups where the user is in and in the module + * @param string $module The module to use + * @param integer $idgroupmember The user to search + */ + public function groupmemberReadUserByID($module, $idgroupmember) { - case "RW": $right=2;break; - case "RO": $right=1;break; + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $idgrouptmps = $this->groupRead($module); + // Create an array with idgroup=>group + $idgroups = array(); + foreach ($idgrouptmps as $val) { + $idgroups[$val["idgroup"]] = $val["group"]; + } + $this->dbGroupMember->clearRequest(); + $this->dbGroupMember->whereAdd("idgroupmember", "=", $idgroupmember); + $idgroupmembers = $this->dbGroupMember->select()->execute(); + $res = array(); + foreach ($idgroupmembers as $idmembers) { + $res[$idmembers["idgroup"]] = $idgroups[$idmembers["idgroup"]]; + } + return $res; + } + + /** Return an array with all the available users in the group and in the + * module + * @param string $module The module to use + * @param string $group The group to search + */ + public function groupmemberReadGroup($module, $group) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->select() + ->whereAdd( + "idgroup", + "=", + $groups[0]["idgroup"] + ) + ->displayAdd("user") + ->execute(); + } + + /** Return an array with all the available users in the group and in the + * module + * @param string $module The module to use + * @param integer $idgroup The group to search + */ + public function groupmemberReadGroupByID($module, $idgroup) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->select() + ->whereAdd( + "idgroup", + "=", + $groups[0]["idgroup"] + ) + ->execute(); + } + + /** Return an array containing the information of a user in a specific group + * @param string $module The module to use + * @param integer $idgroup The group to search + * @param integer $iduser The user to search + */ + public function groupmemberReadUserDataByID($module, $idgroup, $iduser) + { + if ($this->dbGroupMember == null) { + throw new \Exception( + dgettext( + "domframework", + "DB for GroupMember is not connected" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $this->dbGroupMember->clearRequest(); + return $this->dbGroupMember->select() + ->whereAdd( + "idgroup", + "=", + $groups[0]["idgroup"] + ) + ->whereAdd("idgroupmember", "=", $iduser) + ->execute(); + } + + /** Return an array containing the titles of the table translating in the user + * language + */ + public function groupmembersTitles() + { + return $this->dbGroupMember->titles(); + } + + /** Check if the provided data are compilant with the group specification + * @param array $data The data to check + * @param integer|null $idgroupmember The group member associated to verify + * @return array The errors found in the data + */ + public function groupmembersVerify($data, $idgroupmember = false) + { + return $this->dbGroupMember->verify($data, $idgroupmember); + } + + //////////////// + // RIGHTS // + //////////////// + /** Add a new right to right list + * Return the idright created + * @param string $module The module to use + * @param string $group The group to use + * @param string $object The object to use + * @param string $right The right to add + * @param string|null $comment The comment to add + */ + public function rightAdd($module, $group, $object, $right, $comment = "") + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($right) { + case "RW": + $right = 2; + break; + case "RO": + $right = 1; + break; // Normally, the NO is not used as the entry should be removed and the user // will have the same result. The NO allow to force the value. - case "NO": $right=0;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (NO/RO/RW only)"), - 500); - } - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->insert () - ->setValues (array ( + case "NO": + $right = 0; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (NO/RO/RW only)" + ), + 500 + ); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->insert() + ->setValues(array( "idgroup" => $groups[0]["idgroup"], "idobject" => $objects[0]["idobject"], "right" => $right, "comment" => $comment)) - ->execute (); - } - - /** Add a new right to right list by ID - * Return the idright created - * @param string $module The module to use - * @param integer $idgroup The group to use - * @param integer $idobject The object to use - * @param integer $idright The right to add - * @param string|null $comment The comment to add - */ - public function rightAddByID ($module, $idgroup, $idobject, $idright, - $comment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($idright) - { - case "2": $right=2;break; - case "1": $right=1;break; - case "0": $right=0;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (0/1/2 only)"), - 500); + ->execute(); } - $groups = $this->groupReadByID ($module, $idgroup); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectReadByID ($module, $idobject); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->insert () - ->setValues (array ( + + /** Add a new right to right list by ID + * Return the idright created + * @param string $module The module to use + * @param integer $idgroup The group to use + * @param integer $idobject The object to use + * @param integer $idright The right to add + * @param string|null $comment The comment to add + */ + public function rightAddByID( + $module, + $idgroup, + $idobject, + $idright, + $comment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($idright) { + case "2": + $right = 2; + break; + case "1": + $right = 1; + break; + case "0": + $right = 0; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (0/1/2 only)" + ), + 500 + ); + } + $groups = $this->groupReadByID($module, $idgroup); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectReadByID($module, $idobject); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->insert() + ->setValues(array( "idgroup" => $groups[0]["idgroup"], "idobject" => $objects[0]["idobject"], "right" => $right, "comment" => $comment)) - ->execute (); - } - - /** Remove an right from database and all the rights using it - * @param string $module The module to use - * @param string $group The group to use - * @param string $object The object to remove the rights - */ - public function rightDel ($module, $group, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $idrights = $this->rightRead ($module, $group, $object); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->delete () - ->whereAdd ("idright", "=", $idrights[0]["idright"]) - ->execute (); - } - - /** Remove an right from database by ID and all the rights using it - * @param string $module The module to use - * @param integer $idright The idright to be deleted - */ - public function rightDelByID ($module, $idright) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $idrights = $this->rightReadByID ($module, $idright); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->delete () - ->whereAdd ("idright", "=", $idrights[0]["idright"]) - ->execute (); - } - - /** Update a right in the database - * @param string $module The module to use - * @param string $group The group to update the right - * @param string $object The object ot update the right - * @param string $newright The new right to save - * @param string|null $newcomment The new comment to save - */ - public function rightUpdate ($module, $group, $object, $newright, - $newcomment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($newright) - { - case "RW": $newright=2;break; - case "RO": $newright=1;break; - case "NO": $newright=0;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (NO/RO/RW only)"), - 500); + ->execute(); } - $idrights = $this->rightRead ($module, $group, $object); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->update () - ->whereAdd ("idright", "=", $idrights[0]["idright"]) - ->setValues (array ("right" => $newright, + + /** Remove an right from database and all the rights using it + * @param string $module The module to use + * @param string $group The group to use + * @param string $object The object to remove the rights + */ + public function rightDel($module, $group, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $idrights = $this->rightRead($module, $group, $object); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->delete() + ->whereAdd("idright", "=", $idrights[0]["idright"]) + ->execute(); + } + + /** Remove an right from database by ID and all the rights using it + * @param string $module The module to use + * @param integer $idright The idright to be deleted + */ + public function rightDelByID($module, $idright) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $idrights = $this->rightReadByID($module, $idright); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->delete() + ->whereAdd("idright", "=", $idrights[0]["idright"]) + ->execute(); + } + + /** Update a right in the database + * @param string $module The module to use + * @param string $group The group to update the right + * @param string $object The object ot update the right + * @param string $newright The new right to save + * @param string|null $newcomment The new comment to save + */ + public function rightUpdate( + $module, + $group, + $object, + $newright, + $newcomment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($newright) { + case "RW": + $newright = 2; + break; + case "RO": + $newright = 1; + break; + case "NO": + $newright = 0; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (NO/RO/RW only)" + ), + 500 + ); + } + $idrights = $this->rightRead($module, $group, $object); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->update() + ->whereAdd("idright", "=", $idrights[0]["idright"]) + ->setValues(array("right" => $newright, "comment" => $newcomment)) - ->execute (); - } - - /** Update a right by ID in the database - * @param string $module The module to use - * @param integer $idright The idright to update the right - * @param integer $newidobject The object ot update the right - * @param integer $newright The new right to save - * @param string|null $newcomment The new comment to save - */ - public function rightUpdateByID ($module, $idright, $newidobject, $newright, - $newcomment="") - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - switch ($newright) - { - case "2": $newright=2;break; - case "1": $newright=1;break; - case "0": $newright=0;break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown right provided (0/1/2 only)"), - 500); + ->execute(); } - $idrights = $this->rightReadByID ($module, $idright); - if (!isset ($idrights[0]["idright"])) - throw new \Exception (dgettext ("domframework", - "Wanted right not found"), 404); - $this->rightCache = null; - $this->dbRight->clearRequest (); - return $this->dbRight->update () - ->whereAdd ("idright", "=", $idrights[0]["idright"]) - ->setValues (array ("idobject" => $newidobject, + + /** Update a right by ID in the database + * @param string $module The module to use + * @param integer $idright The idright to update the right + * @param integer $newidobject The object ot update the right + * @param integer $newright The new right to save + * @param string|null $newcomment The new comment to save + */ + public function rightUpdateByID( + $module, + $idright, + $newidobject, + $newright, + $newcomment = "" + ) { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + switch ($newright) { + case "2": + $newright = 2; + break; + case "1": + $newright = 1; + break; + case "0": + $newright = 0; + break; + default: + throw new \Exception( + dgettext( + "domframework", + "Unknown right provided (0/1/2 only)" + ), + 500 + ); + } + $idrights = $this->rightReadByID($module, $idright); + if (!isset($idrights[0]["idright"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted right not found" + ), 404); + } + $this->rightCache = null; + $this->dbRight->clearRequest(); + return $this->dbRight->update() + ->whereAdd("idright", "=", $idrights[0]["idright"]) + ->setValues(array("idobject" => $newidobject, "right" => $newright, "comment" => $newcomment)) - ->execute (); - } + ->execute(); + } - /** Return an array with all the available rights in the module, for a group, - * and concerning an object - * @param string $module The module to use - * @param string $group The group to get the rights - * @param string $object The object to get the rights - */ - public function rightRead ($module, $group, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->dbRight->clearRequest (); - return $this->dbRight->select () - ->whereAdd ("idgroup", "=", $groups[0]["idgroup"]) - ->whereAdd ("idobject", "=", $objects[0]["idobject"]) - ->execute (); - } + /** Return an array with all the available rights in the module, for a group, + * and concerning an object + * @param string $module The module to use + * @param string $group The group to get the rights + * @param string $object The object to get the rights + */ + public function rightRead($module, $group, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->dbRight->clearRequest(); + return $this->dbRight->select() + ->whereAdd("idgroup", "=", $groups[0]["idgroup"]) + ->whereAdd("idobject", "=", $objects[0]["idobject"]) + ->execute(); + } - /** Return an array with all the available rights for a module and a group - * @param string $module The module to use - * @param string $group The group to get the rights - */ - public function rightReadByGroup ($module, $group) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $groups = $this->groupRead ($module, $group); - if (! isset ($groups[0]["idgroup"])) - throw new \Exception (dgettext ("domframework", - "Wanted group not found"), 404); - return $this->rightReadByGroupByID ($module, $objects[0]["idgroup"]); - } + /** Return an array with all the available rights for a module and a group + * @param string $module The module to use + * @param string $group The group to get the rights + */ + public function rightReadByGroup($module, $group) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $groups = $this->groupRead($module, $group); + if (! isset($groups[0]["idgroup"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted group not found" + ), 404); + } + return $this->rightReadByGroupByID($module, $objects[0]["idgroup"]); + } - /** Return an array with all the available rights for a module and a group - * @param string $module The module to use - * @param integer $idgroup The group to get the rights - */ - public function rightReadByGroupByID ($module, $idgroup) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $this->dbRight->clearRequest (); - return $this->dbRight->select () - ->whereAdd ("idgroup", "=", $idgroup) - ->execute (); - } + /** Return an array with all the available rights for a module and a group + * @param string $module The module to use + * @param integer $idgroup The group to get the rights + */ + public function rightReadByGroupByID($module, $idgroup) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $this->dbRight->clearRequest(); + return $this->dbRight->select() + ->whereAdd("idgroup", "=", $idgroup) + ->execute(); + } - /** Return an array with all the information concerning a right selected by - * @param string $module The module to use - * @param integer $idright The right to search - * ID - */ - public function rightReadByID ($module, $idright) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $this->dbRight->clearRequest (); - return $this->dbRight->select () - ->whereAdd ("idright", "=", $idright) - ->execute (); - } + /** Return an array with all the information concerning a right selected by + * @param string $module The module to use + * @param integer $idright The right to search + * ID + */ + public function rightReadByID($module, $idright) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $this->dbRight->clearRequest(); + return $this->dbRight->select() + ->whereAdd("idright", "=", $idright) + ->execute(); + } - /** Return an array with all the available rights for a module and an object - * @param string $module The module to use - * @param string $object The object to search - */ - public function rightReadByObject ($module, $object) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $objects = $this->objectRead ($module, $object); - if (! isset ($objects[0]["idobject"])) - throw new \Exception (dgettext ("domframework", - "Wanted object not found"), 404); - $this->dbRight->clearRequest (); - return $this->dbRight->select () - ->whereAdd ("idobject", "=", $objects[0]["idobject"]) - ->execute (); - } + /** Return an array with all the available rights for a module and an object + * @param string $module The module to use + * @param string $object The object to search + */ + public function rightReadByObject($module, $object) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $objects = $this->objectRead($module, $object); + if (! isset($objects[0]["idobject"])) { + throw new \Exception(dgettext( + "domframework", + "Wanted object not found" + ), 404); + } + $this->dbRight->clearRequest(); + return $this->dbRight->select() + ->whereAdd("idobject", "=", $objects[0]["idobject"]) + ->execute(); + } - /** Return an array with all the available rights for a module and an idobject - * @param string $module The module to use - * @param integer $idobject The object to search - */ - public function rightReadByObjectByID ($module, $idobject) - { - if ($this->dbRight == null) - throw new \Exception (dgettext ("domframework", - "DB for Right is not connected"), 500); - $this->dbRight->clearRequest (); - return $this->dbRight->select () - ->whereAdd ("idobject", "=", $idobject) - ->execute (); - } + /** Return an array with all the available rights for a module and an idobject + * @param string $module The module to use + * @param integer $idobject The object to search + */ + public function rightReadByObjectByID($module, $idobject) + { + if ($this->dbRight == null) { + throw new \Exception(dgettext( + "domframework", + "DB for Right is not connected" + ), 500); + } + $this->dbRight->clearRequest(); + return $this->dbRight->select() + ->whereAdd("idobject", "=", $idobject) + ->execute(); + } - /** Return an array containing the titles of the table translating in the user - * language - */ - public function rightTitles () - { - return $this->dbRight->titles (); - } + /** Return an array containing the titles of the table translating in the user + * language + */ + public function rightTitles() + { + return $this->dbRight->titles(); + } - /** Return all the types of rights available (RO and RW) - */ - public function rightTypes () - { - return array ("0" => "NO", "1" => "RO", "2" => "RW"); - } + /** Return all the types of rights available (RO and RW) + */ + public function rightTypes() + { + return array("0" => "NO", "1" => "RO", "2" => "RW"); + } - /** Check if the provided data are compilant with the group specification - * @param array $data The data of the right to check - * @param integer $idright The right to search - * @return array The errors found in the data - */ - public function rightVerify ($data, $idright=false) - { - return $this->dbRight->verify ($data, $idright); - } + /** Check if the provided data are compilant with the group specification + * @param array $data The data of the right to check + * @param integer $idright The right to search + * @return array The errors found in the data + */ + public function rightVerify($data, $idright = false) + { + return $this->dbRight->verify($data, $idright); + } } diff --git a/src/Backtrace.php b/src/Backtrace.php index e062dc6..ead4f42 100644 --- a/src/Backtrace.php +++ b/src/Backtrace.php @@ -1,4 +1,5 @@ @@ -11,51 +12,53 @@ namespace Domframework; */ class Backtrace { - /** Display the backtrace in the browser - * use: \backtrace::show (debug_backtrace ()); - * @param array $backtrace The backtrace to display - */ - public static function show ($backtrace) - { - if (! is_array ($backtrace)) - throw new \Exception ("Backtrace invalid: not an array", 500); - echo "
                Debug BackTrace:\n";
                -    foreach ($backtrace as $key=>$back)
                +    /** Display the backtrace in the browser
                +      * use: \backtrace::show (debug_backtrace ());
                +      * @param array $backtrace The backtrace to display
                +      */
                +    public static function show($backtrace)
                     {
                -      echo "";
                -      echo "$key => ";
                -      if (array_key_exists ("file", $back))
                -        echo $back["file"]."[".$back["line"]."] : ";
                -      if (array_key_exists ("class", $back))
                -        echo $back["class"];
                -      echo "::".$back["function"]. "(";
                -      if (array_key_exists ("args", $back))
                -      {
                -        foreach ($back["args"] as $k=>$arg)
                -        {
                -          if ($k > 0)
                -            echo ", ";
                -          if (is_array ($arg))
                -            echo "ARRAY";
                -          elseif (is_object ($arg))
                -            echo "OBJECT ".get_class ($arg);
                -          elseif (is_bool ($arg))
                -            echo ($arg === true) ? "true" : "false";
                -          elseif (is_string ($arg))
                -            echo "\"$arg\"";
                -          elseif (is_int ($arg) || is_float ($arg))
                -            echo $arg;
                -          else
                -            var_dump ($arg);
                +        if (! is_array($backtrace)) {
                +            throw new \Exception("Backtrace invalid: not an array", 500);
                         }
                -      }
                -      echo ")";
                -      echo "";
                -      echo "\n";
                +        echo "
                Debug BackTrace:\n";
                +        foreach ($backtrace as $key => $back) {
                +            echo "";
                +            echo "$key => ";
                +            if (array_key_exists("file", $back)) {
                +                echo $back["file"] . "[" . $back["line"] . "] : ";
                +            }
                +            if (array_key_exists("class", $back)) {
                +                echo $back["class"];
                +            }
                +            echo "::" . $back["function"] . "(";
                +            if (array_key_exists("args", $back)) {
                +                foreach ($back["args"] as $k => $arg) {
                +                    if ($k > 0) {
                +                        echo ", ";
                +                    }
                +                    if (is_array($arg)) {
                +                        echo "ARRAY";
                +                    } elseif (is_object($arg)) {
                +                        echo "OBJECT " . get_class($arg);
                +                    } elseif (is_bool($arg)) {
                +                        echo ($arg === true) ? "true" : "false";
                +                    } elseif (is_string($arg)) {
                +                        echo "\"$arg\"";
                +                    } elseif (is_int($arg) || is_float($arg)) {
                +                        echo $arg;
                +                    } else {
                +                        var_dump($arg);
                +                    }
                +                }
                +            }
                +            echo ")";
                +            echo "";
                +            echo "\n";
                +        }
                +        echo "
                \n"; } - echo "
                \n"; - } } diff --git a/src/Cachefile.php b/src/Cachefile.php index 8fbeb64..e67d9c2 100644 --- a/src/Cachefile.php +++ b/src/Cachefile.php @@ -1,4 +1,5 @@ @@ -11,246 +12,280 @@ namespace Domframework; */ class Cachefile { - /** Where to store the cached information - */ - public $directory = "./cache"; + /** Where to store the cached information + */ + public $directory = "./cache"; - /** If TRUE : no information is cached - */ - public $nocache = false; + /** If TRUE : no information is cached + */ + public $nocache = false; - /** Getter/setter for $directory cache - * @param string|null $val The directory to use - * @return $this or $this->directory value - */ - public function directory ($val = null) - { - if ($val === null) - return $this->directory; - if (! is_string ($val) || trim ($val) === "") - throw new \Exception ("CacheFile directory not a string or empty", 500); - $this->directory = $val; - return $this; - } - - /** Check if there is some garbage to clean - */ - public function garbage () - { - try + /** Getter/setter for $directory cache + * @param string|null $val The directory to use + * @return $this or $this->directory value + */ + public function directory($val = null) { - $this->cachedir (); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), $e->getCode()); + if ($val === null) { + return $this->directory; + } + if (! is_string($val) || trim($val) === "") { + throw new \Exception("CacheFile directory not a string or empty", 500); + } + $this->directory = $val; + return $this; } - $fileCache = $this->directory."/".sha1 ("Garbage-Lock"); - $res = false; - if (file_exists ($fileCache)) + /** Check if there is some garbage to clean + */ + public function garbage() { - $data = file_get_contents ($fileCache); - $data = unserialize ($data); - if (($data["createTime"] + $data["ttl"]) >= time ()) - { - $res = $data["data"]; - } - } + try { + $this->cachedir(); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), $e->getCode()); + } - if ($res === false) - { - $data = array ("ttl" => 24*60*60, + $fileCache = $this->directory . "/" . sha1("Garbage-Lock"); + $res = false; + if (file_exists($fileCache)) { + $data = file_get_contents($fileCache); + $data = unserialize($data); + if (($data["createTime"] + $data["ttl"]) >= time()) { + $res = $data["data"]; + } + } + + if ($res === false) { + $data = array("ttl" => 24 * 60 * 60, "createTime" => time(), "data" => "CACHE-Garbage"); - file_put_contents ($fileCache, serialize ($data)); - chmod ($fileCache, 0666); - $files = glob ($this->directory."/*", GLOB_NOSORT); - foreach ($files as $fileCache) - { - $data = file_get_contents ($fileCache); - if ($data === false) - { - unlink ($fileCache); - continue; + file_put_contents($fileCache, serialize($data)); + chmod($fileCache, 0666); + $files = glob($this->directory . "/*", GLOB_NOSORT); + foreach ($files as $fileCache) { + $data = file_get_contents($fileCache); + if ($data === false) { + unlink($fileCache); + continue; + } + + $data = unserialize($data); + if ( + ! isset($data["ttl"]) || ! isset($data["data"]) || + ! isset($data["createTime"]) + ) { + unlink($fileCache); + continue; + } + + if (($data["createTime"] + $data["ttl"]) <= time()) { + unlink($fileCache); + } + } + } + } + + /** This function check if the cachedir exists and create it if it is not the + * case. + * Check if the cache dir is writable and readable + * @return true if OK + * @throw Exception if an error occured + */ + public function cachedir() + { + if (! isset($this->directory) || $this->directory === "") { + throw new \Exception(dgettext( + "domframework", + "No cache directory defined" + ), 500); + } + if (! file_exists($this->directory)) { + // Need to create the cache dir + $parent = realpath(dirname($this->directory)); + if (! is_writeable(dirname($this->directory))) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory %s is not writable : can not create cache directory" + ), + $parent + ), 500); + } + if (!mkdir($this->directory)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Can not create cache directory %s" + ), + $this->directory + ), 500); + } + chmod($this->directory, 0777); + } + if (! is_writable($this->directory)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Cache directory %s is not writable" + ), + $this->directory + ), 500); + } + if (! is_readable($this->directory)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Cache directory %s is not readable" + ), + $this->directory + ), 500); + } + if (!file_exists($this->directory . "/.htaccess")) { + file_put_contents($this->directory . "/.htaccess", "deny from all\n"); + } + return true; + } + + /** This function write data in cache + * @param string $id Cache identifier (add the authentication, the METHOD...) + * @param mixed $data The data to save + * @param integer|null $ttl The cache Time to Leave in seconds (3600s by + * default) + * @return true + * @throw if an error occured + */ + public function write($id, $data, $ttl = 3600) + { + if ($this->nocache !== false) { + return false; + } + try { + $this->cachedir(); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), $e->getCode()); + } + if (! is_integer($ttl) || $ttl <= 0) { + throw new \Exception( + "CacheFile TTL invalid : not integer or negative" . + " : '$ttl'", + 500 + ); + } + if (! is_string($id) && ! is_integer($id)) { + throw new \Exception( + "CacheFile write ID not a string : " . gettype($id), + 500 + ); } - $data = unserialize ($data); - if (! isset ($data["ttl"]) || ! isset ($data["data"]) || - ! isset ($data["createTime"])) - { - unlink ($fileCache); - continue; - } - - if (($data["createTime"] + $data["ttl"]) <= time ()) - { - unlink ($fileCache); - } - } - } - } - - /** This function check if the cachedir exists and create it if it is not the - * case. - * Check if the cache dir is writable and readable - * @return true if OK - * @throw Exception if an error occured - */ - public function cachedir () - { - if (! isset ($this->directory) || $this->directory === "") - throw new \Exception (dgettext ("domframework", - "No cache directory defined"), 500); - if (! file_exists ($this->directory)) - { - // Need to create the cache dir - $parent = realpath (dirname ($this->directory)); - if (! is_writeable (dirname ($this->directory))) - throw new \Exception (sprintf (dgettext ("domframework", - "Directory %s is not writable : can not create cache directory"), - $parent), 500); - if (!mkdir ($this->directory)) - throw new \Exception (sprintf (dgettext ("domframework", - "Can not create cache directory %s"), - $this->directory), 500); - chmod ($this->directory, 0777); - } - if (! is_writable ($this->directory)) - throw new \Exception (sprintf (dgettext ("domframework", - "Cache directory %s is not writable"), - $this->directory), 500); - if (! is_readable ($this->directory)) - throw new \Exception (sprintf (dgettext ("domframework", - "Cache directory %s is not readable"), - $this->directory), 500); - if (!file_exists ($this->directory."/.htaccess")) - file_put_contents ($this->directory."/.htaccess", "deny from all\n"); - return true; - } - - /** This function write data in cache - * @param string $id Cache identifier (add the authentication, the METHOD...) - * @param mixed $data The data to save - * @param integer|null $ttl The cache Time to Leave in seconds (3600s by - * default) - * @return true - * @throw if an error occured - */ - public function write ($id, $data, $ttl = 3600) - { - if ($this->nocache !== false) - return false; - try - { - $this->cachedir (); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), $e->getCode()); - } - if (! is_integer ($ttl) || $ttl <= 0) - throw new \Exception ("CacheFile TTL invalid : not integer or negative". - " : '$ttl'", - 500); - if (! is_string ($id) && ! is_integer ($id)) - throw new \Exception ("CacheFile write ID not a string : ".gettype ($id), - 500); - - $this->garbage (); - $fileCache = $this->directory."/".sha1 ($id); - touch ($fileCache.".lock"); - $data = array ("ttl" => $ttl, + $this->garbage(); + $fileCache = $this->directory . "/" . sha1($id); + touch($fileCache . ".lock"); + $data = array("ttl" => $ttl, "createTime" => time(), "data" => $data); - file_put_contents ($fileCache, serialize ($data)); - unlink ($fileCache.".lock"); - chmod ($fileCache, 0666); - return true; - } - - /** This function read data from cache. Return FALSE in case of empty or too - * older cache - * @param string $id Cache identifier (add the authentication, the METHOD) - * @return false if the cache is empty or too old - * @return mixed The data stored in cache - */ - public function read ($id) - { - if ($this->nocache !== false) - return false; - try - { - $this->cachedir (); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage(), $e->getCode()); + file_put_contents($fileCache, serialize($data)); + unlink($fileCache . ".lock"); + chmod($fileCache, 0666); + return true; } - $this->garbage (); - if (! is_string ($id) && ! is_integer ($id)) - throw new \Exception ("CacheFile read ID not a string : ".gettype ($id), - 500); - $fileCache = $this->directory."/".sha1 ($id); - if (!file_exists ($fileCache)) - return false; - if (!is_readable ($fileCache)) - throw new \Exception (sprintf (dgettext ("domframework", - "File cache %s is not readable"), - $fileCache), 500); - if (!is_writable ($fileCache)) - throw new \Exception (sprintf (dgettext ("domframework", - "File cache %s is not writable"), - $fileCache), 500); - // Lock : waiting the reconstruction of the cache by another process - // Waiting 10s maximum to re-create the cache file - $startTime = time (); - while (file_exists ($fileCache.".lock") && time () < $startTime + 10) + /** This function read data from cache. Return FALSE in case of empty or too + * older cache + * @param string $id Cache identifier (add the authentication, the METHOD) + * @return false if the cache is empty or too old + * @return mixed The data stored in cache + */ + public function read($id) { - usleep (100000); + if ($this->nocache !== false) { + return false; + } + try { + $this->cachedir(); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), $e->getCode()); + } + + $this->garbage(); + if (! is_string($id) && ! is_integer($id)) { + throw new \Exception( + "CacheFile read ID not a string : " . gettype($id), + 500 + ); + } + $fileCache = $this->directory . "/" . sha1($id); + if (!file_exists($fileCache)) { + return false; + } + if (!is_readable($fileCache)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File cache %s is not readable" + ), + $fileCache + ), 500); + } + if (!is_writable($fileCache)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File cache %s is not writable" + ), + $fileCache + ), 500); + } + // Lock : waiting the reconstruction of the cache by another process + // Waiting 10s maximum to re-create the cache file + $startTime = time(); + while (file_exists($fileCache . ".lock") && time() < $startTime + 10) { + usleep(100000); + } + + // The lock is pending 10s (stale) : removing it to read the data quicker + // next time + if (file_exists($fileCache . ".lock")) { + unlink($fileCache . ".lock"); + } + + $data = file_get_contents($fileCache); + if ($data === false) { + unlink($fileCache); + return false; + } + + $data = unserialize($data); + if ( + ! isset($data["ttl"]) || ! isset($data["data"]) || + ! isset($data["createTime"]) + ) { + unlink($fileCache); + return false; + } + + if (($data["createTime"] + $data["ttl"]) >= time()) { + if (file_exists($fileCache . ".lock")) { + unlink($fileCache . ".lock"); + } + return $data["data"]; + } + + return false; } - // The lock is pending 10s (stale) : removing it to read the data quicker - // next time - if (file_exists ($fileCache.".lock")) - unlink ($fileCache.".lock"); - - $data = file_get_contents ($fileCache); - if ($data === false) + /** This function delete an id in cache + * @param string $id Cache identifier (add the authentication, the METHOD...) + * @return boolean The cache is well deleted + */ + public function delete($id) { - unlink ($fileCache); - return false; + $fileCache = $this->directory . "/" . sha1($id); + if (!file_exists($fileCache)) { + return false; + } + unlink($fileCache); + return true; } - - $data = unserialize ($data); - if (! isset ($data["ttl"]) || ! isset ($data["data"]) || - ! isset ($data["createTime"])) - { - unlink ($fileCache); - return false; - } - - if (($data["createTime"] + $data["ttl"]) >= time ()) - { - if (file_exists ($fileCache.".lock")) - unlink ($fileCache.".lock"); - return $data["data"]; - } - - return false; - } - - /** This function delete an id in cache - * @param string $id Cache identifier (add the authentication, the METHOD...) - * @return boolean The cache is well deleted - */ - public function delete ($id) - { - $fileCache = $this->directory."/".sha1 ($id); - if (!file_exists ($fileCache)) - return false; - unlink ($fileCache); - return true; - } } diff --git a/src/Cacheoutput.php b/src/Cacheoutput.php index bab0b49..43e9c50 100644 --- a/src/Cacheoutput.php +++ b/src/Cacheoutput.php @@ -1,4 +1,5 @@ @@ -16,62 +17,67 @@ namespace Domframework; */ class Cacheoutput { - /** Record if the saving of pages is on going */ - private $saving = false; - /** The called id */ - private $id = null; - /** The called ttl */ - private $ttl = null; - /** The cache object */ - private $cache = null; - /** Current path at start due to lack of information in __destruct*/ - private $cacheCWD = null; + /** Record if the saving of pages is on going */ + private $saving = false; + /** The called id */ + private $id = null; + /** The called ttl */ + private $ttl = null; + /** The cache object */ + private $cache = null; + /** Current path at start due to lack of information in __destruct*/ + private $cacheCWD = null; - /** - @param string $id The cache identifier - @param integer|null $ttl The cache Time to Leave in seconds (60s by - default) - @param string|null $method The cache method to use */ - public function __construct ($id, $ttl=60, $method="file") - { - $res = @include ("domframework/cache$method.php"); - if ($res === false) - throw new \Exception (sprintf (dgettext ("domframework", - "Unkwnown cache method : "), $method), - 500); - $this->id = $id; - $this->ttl = $ttl; - $this->cacheCWD = getcwd(); - $cachemethod = "Cache$method"; - $this->cache = new $cachemethod (); - if ($ttl === 0) - $this->cache->nocache = 1; - $res = $this->cache->read ($id); - // If there is a cache : display it - if ($res !== false) + /** + @param string $id The cache identifier + @param integer|null $ttl The cache Time to Leave in seconds (60s by + default) + @param string|null $method The cache method to use */ + public function __construct($id, $ttl = 60, $method = "file") { - foreach ($res["headers"] as $header) - @header ($header); - echo $res["content"]; - exit; + $res = @include("domframework/cache$method.php"); + if ($res === false) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "Unkwnown cache method : " + ), $method), + 500 + ); + } + $this->id = $id; + $this->ttl = $ttl; + $this->cacheCWD = getcwd(); + $cachemethod = "Cache$method"; + $this->cache = new $cachemethod(); + if ($ttl === 0) { + $this->cache->nocache = 1; + } + $res = $this->cache->read($id); + // If there is a cache : display it + if ($res !== false) { + foreach ($res["headers"] as $header) { + @header($header); + } + echo $res["content"]; + exit; + } + + ob_start(); + $this->saving = true; + // The data are sent automatically } - ob_start (); - $this->saving = true; - // The data are sent automatically - } - - /** End of saving the data in cache */ - public function __destruct () - { - // Force the path because it return to / in the destructor - chdir ($this->cacheCWD); - if ($this->saving === true) + /** End of saving the data in cache */ + public function __destruct() { - // Do the saving of the data - $data = array ("content"=>ob_get_contents (), - "headers"=>headers_list ()); - $this->cache->write ($this->id, $data, $this->ttl); + // Force the path because it return to / in the destructor + chdir($this->cacheCWD); + if ($this->saving === true) { + // Do the saving of the data + $data = array("content" => ob_get_contents(), + "headers" => headers_list()); + $this->cache->write($this->id, $data, $this->ttl); + } } - } } diff --git a/src/Certificationauthority.php b/src/Certificationauthority.php index 8594c8e..e585afd 100644 --- a/src/Certificationauthority.php +++ b/src/Certificationauthority.php @@ -1,4 +1,5 @@ @@ -11,29 +12,29 @@ namespace Domframework; */ class Certificationauthority { - // PROPERTIES - /** The opensslCnfPath file - */ - private $opensslCnfPath; + // PROPERTIES + /** The opensslCnfPath file + */ + private $opensslCnfPath; - /** The CA public cert - */ - private $caCert = ""; - /** The CA private key - */ - private $caKey = ""; + /** The CA public cert + */ + private $caCert = ""; + /** The CA private key + */ + private $caKey = ""; - /** The user private key resource - */ - private $privateKey; + /** The user private key resource + */ + private $privateKey; - /** The configuration arguments - */ - private $configargs = array (); + /** The configuration arguments + */ + private $configargs = array(); - /** The basic openssl.cnf configuration - */ - private $opensslConf = 'HOME = . + /** The basic openssl.cnf configuration + */ + private $opensslConf = 'HOME = . RANDFILE = $ENV::HOME/.rnd [ req ] @@ -53,188 +54,219 @@ keyUsage = nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth, clientAuth '; - /** Check if openssl support is available in PHP - */ - public function __construct () - { - if (! function_exists ("openssl_csr_new")) - throw new \Exception (dgettext ("domframework", - "No openssl support in PHP"), 500); - $this->opensslCnfPath = tempnam ("/tmp", "openssl-"); - file_put_contents ($this->opensslCnfPath, $this->opensslConf); - $this->configargs = array ( - "config" => $this->opensslCnfPath, - "digest_alg" => "sha256WithRSAEncryption", - "private_key_bits" => 4096, - ); - } + /** Check if openssl support is available in PHP + */ + public function __construct() + { + if (! function_exists("openssl_csr_new")) { + throw new \Exception(dgettext( + "domframework", + "No openssl support in PHP" + ), 500); + } + $this->opensslCnfPath = tempnam("/tmp", "openssl-"); + file_put_contents($this->opensslCnfPath, $this->opensslConf); + $this->configargs = array( + "config" => $this->opensslCnfPath, + "digest_alg" => "sha256WithRSAEncryption", + "private_key_bits" => 4096, + ); + } - /** Remove the temporary files when destroying the object - */ - public function __destruct () - { - if (file_exists ($this->opensslCnfPath)) - unlink ($this->opensslCnfPath); - } + /** Remove the temporary files when destroying the object + */ + public function __destruct() + { + if (file_exists($this->opensslCnfPath)) { + unlink($this->opensslCnfPath); + } + } - /** Create the pair key/cert for authority - * @param string $countryName Country name (like FR) - * @param string $organizationName Name of organization - * @param string $commonName Common name of authority - * @param integer|null $days The number of days of validity of the CA (3650 - * by default) - * @return $this - */ - public function createCA ($countryName, $organizationName, $commonName, - $days = 3650) - { - $req_key = openssl_pkey_new (array ( + /** Create the pair key/cert for authority + * @param string $countryName Country name (like FR) + * @param string $organizationName Name of organization + * @param string $commonName Common name of authority + * @param integer|null $days The number of days of validity of the CA (3650 + * by default) + * @return $this + */ + public function createCA( + $countryName, + $organizationName, + $commonName, + $days = 3650 + ) { + $req_key = openssl_pkey_new(array( "config" => $this->opensslCnfPath, "private_key_bits" => 4096, "private_key_type" => OPENSSL_KEYTYPE_RSA, - )); - $dn = array ( + )); + $dn = array( "countryName" => $countryName, "organizationName" => $organizationName, "commonName" => $commonName, - ); - $this->configargs["x509_extensions"] = "v3_ca"; - // x509_extensions must be defined in /etc/ssl/openssl.cnf - $req_csr = openssl_csr_new ($dn, $req_key, $this->configargs); - $req_cert = openssl_csr_sign ($req_csr, NULL, $req_key, $days, - $this->configargs); - if ($req_cert === false) - throw new \Exception ("Can not create CA certificate : " . - openssl_error_string (), 500); - openssl_x509_export ($req_cert, $this->caCert); - openssl_pkey_export ($req_key, $this->caKey); - return $this; - } + ); + $this->configargs["x509_extensions"] = "v3_ca"; + // x509_extensions must be defined in /etc/ssl/openssl.cnf + $req_csr = openssl_csr_new($dn, $req_key, $this->configargs); + $req_cert = openssl_csr_sign( + $req_csr, + null, + $req_key, + $days, + $this->configargs + ); + if ($req_cert === false) { + throw new \Exception("Can not create CA certificate : " . + openssl_error_string(), 500); + } + openssl_x509_export($req_cert, $this->caCert); + openssl_pkey_export($req_key, $this->caKey); + return $this; + } - /** Get/Set the ca cert - * @param string|null $caCert The CA cert to get/set - * @return ($caCert is null ? string : $this) the CA if get in PEM, $this if set - */ - public function caCert ($caCert = null) - { - if ($caCert === null) - return $this->caCert; - if (! is_string ($caCert)) - throw new \Exception ("AC : Invalid caCert provided : not a string", 500); - $this->caCert = $caCert; - return $this; - } + /** Get/Set the ca cert + * @param string|null $caCert The CA cert to get/set + * @return ($caCert is null ? string : $this) the CA if get in PEM, $this if set + */ + public function caCert($caCert = null) + { + if ($caCert === null) { + return $this->caCert; + } + if (! is_string($caCert)) { + throw new \Exception("AC : Invalid caCert provided : not a string", 500); + } + $this->caCert = $caCert; + return $this; + } - /** Get/Set the ca key - * @param string|null $caKey The CA key to get/set - * @return ($caKey is null ? string : $this) the CA if get, $this if set - */ - public function caKey ($caKey = null) - { - if ($caKey === null) - return $this->caKey; - if (! is_string ($caKey)) - throw new \Exception ("AC : invalid caKey provided : not a string", 500); - $this->caKey = $caKey; - return $this; - } + /** Get/Set the ca key + * @param string|null $caKey The CA key to get/set + * @return ($caKey is null ? string : $this) the CA if get, $this if set + */ + public function caKey($caKey = null) + { + if ($caKey === null) { + return $this->caKey; + } + if (! is_string($caKey)) { + throw new \Exception("AC : invalid caKey provided : not a string", 500); + } + $this->caKey = $caKey; + return $this; + } - /** Create a private key - * @return $this; - */ - public function createPrivateKey () - { - $this->privateKey = openssl_pkey_new (array ( + /** Create a private key + * @return $this; + */ + public function createPrivateKey() + { + $this->privateKey = openssl_pkey_new(array( "config" => $this->opensslCnfPath, "private_key_bits" => 4096, "private_key_type" => OPENSSL_KEYTYPE_RSA, - )); - return $this; - } - - /** Get in PEM/Set the private key - * @param string|null $privateKey The private key to use - * @return ($privateKey is null ? string : $this) the privatekey if get in PEM, $this if set - */ - public function privateKey ($privateKey = null) - { - if ($privateKey === null) - { - openssl_pkey_export($this->privateKey, $out); - return $out; + )); + return $this; } - if (! is_string ($privateKey)) - throw new \Exception ("AC : invalid privateKey provided : not a string", - 500); - $this->privateKey = openssl_pkey_get_private ($privateKey); - return $this; - } - /** Create a CSR. - * Will create a private key if none is already exists - * @param string $countryName Country name (like FR) - * @param string $organizationName Name of organization - * @param string $commonName Common name of authority - * @return string the CSR created in PEM - */ - public function createCSR ($countryName, $organizationName, $commonName) - { - if ($this->privateKey === null) - $this->createPrivateKey (); - $dn = array ( + /** Get in PEM/Set the private key + * @param string|null $privateKey The private key to use + * @return ($privateKey is null ? string : $this) the privatekey if get in PEM, $this if set + */ + public function privateKey($privateKey = null) + { + if ($privateKey === null) { + openssl_pkey_export($this->privateKey, $out); + return $out; + } + if (! is_string($privateKey)) { + throw new \Exception( + "AC : invalid privateKey provided : not a string", + 500 + ); + } + $this->privateKey = openssl_pkey_get_private($privateKey); + return $this; + } + + /** Create a CSR. + * Will create a private key if none is already exists + * @param string $countryName Country name (like FR) + * @param string $organizationName Name of organization + * @param string $commonName Common name of authority + * @return string the CSR created in PEM + */ + public function createCSR($countryName, $organizationName, $commonName) + { + if ($this->privateKey === null) { + $this->createPrivateKey(); + } + $dn = array( "countryName" => $countryName, "organizationName" => $organizationName, "commonName" => $commonName, - ); - $this->configargs["x509_extensions"] = "v3_req"; - $req_csr = openssl_csr_new ($dn, $this->privateKey, $this->configargs); - if ($req_csr === false) - throw new \Exception ("CA : Can not generate a CSR : ". - openssl_error_string (), 500); - openssl_csr_export ($req_csr, $out); - return $out; - } - - /** Sign a CSR with an CA cert/key pair and return the signed certificate in - * PEM mode - * The caCert and caKey must be defined - * @param string $csr The CSR to sign - * @param string $caCert The CA Certificate - * @param string $caKey The CA private key - * @param integer|null $days The number of days of validity (365 by default) - * @param array|null $altNames The alternative names allowed in cert - * @return string the signed certificate in PEM - */ - public function signCSR ($csr, $caCert, $caKey, $days = 365, - $altNames = array ()) - { - $conf = $this->opensslConf; - if (! empty($altNames)) - { - // Copy the commonName from CSR request into subjectAltName - $subject = openssl_csr_get_subject($csr); - if (key_exists ("CN", $subject)) - $commonName = $subject["CN"]; - else - throw new \Exception ("Can not get the CN from CSR", 500); - // Add all the alternateNames - $conf .= - "subjectAltName = @san\n\n[ san ]\n"; - $conf .= "DNS.0 = $commonName\n"; - foreach ($altNames as $nb => $name) - { - $conf .= "DNS.".($nb+1)." = $name\n"; - } - file_put_contents ($this->opensslCnfPath, $conf); + ); + $this->configargs["x509_extensions"] = "v3_req"; + $req_csr = openssl_csr_new($dn, $this->privateKey, $this->configargs); + if ($req_csr === false) { + throw new \Exception("CA : Can not generate a CSR : " . + openssl_error_string(), 500); + } + openssl_csr_export($req_csr, $out); + return $out; + } + + /** Sign a CSR with an CA cert/key pair and return the signed certificate in + * PEM mode + * The caCert and caKey must be defined + * @param string $csr The CSR to sign + * @param string $caCert The CA Certificate + * @param string $caKey The CA private key + * @param integer|null $days The number of days of validity (365 by default) + * @param array|null $altNames The alternative names allowed in cert + * @return string the signed certificate in PEM + */ + public function signCSR( + $csr, + $caCert, + $caKey, + $days = 365, + $altNames = array() + ) { + $conf = $this->opensslConf; + if (! empty($altNames)) { + // Copy the commonName from CSR request into subjectAltName + $subject = openssl_csr_get_subject($csr); + if (key_exists("CN", $subject)) { + $commonName = $subject["CN"]; + } else { + throw new \Exception("Can not get the CN from CSR", 500); + } + // Add all the alternateNames + $conf .= + "subjectAltName = @san\n\n[ san ]\n"; + $conf .= "DNS.0 = $commonName\n"; + foreach ($altNames as $nb => $name) { + $conf .= "DNS." . ($nb + 1) . " = $name\n"; + } + file_put_contents($this->opensslCnfPath, $conf); + } + $this->configargs["x509_extensions"] = "v3_req"; + $usercert = openssl_csr_sign( + $csr, + $caCert, + $caKey, + $days, + $this->configargs, + intval(date("YmdHis")) + ); + if ($usercert === false) { + throw new \Exception("Can not create certificate : " . + openssl_error_string(), 500); + } + openssl_x509_export($usercert, $certout); + file_put_contents($this->opensslCnfPath, $this->opensslConf); + return $certout; } - $this->configargs["x509_extensions"] = "v3_req"; - $usercert = openssl_csr_sign ($csr, $caCert, $caKey, $days, - $this->configargs, intval(date ("YmdHis"))); - if ($usercert === false) - throw new \Exception ("Can not create certificate : " . - openssl_error_string (), 500); - openssl_x509_export($usercert, $certout); - file_put_contents ($this->opensslCnfPath, $this->opensslConf); - return $certout; - } } diff --git a/src/Cli.php b/src/Cli.php index 2170497..16de14e 100644 --- a/src/Cli.php +++ b/src/Cli.php @@ -1,4 +1,5 @@ @@ -10,439 +11,472 @@ namespace Domframework; /** Allow to interract with controllers and models from the CLI */ class Cli { - /** Run in CLI mode with parameters - * Example of cli code : - * #!/usr/bin/php - * run(); - */ - /** The expert mode allow to see/execute the models */ - private $EXPERT = false; + /** Run in CLI mode with parameters + * Example of cli code : + * #!/usr/bin/php + * run(); + */ + /** The expert mode allow to see/execute the models */ + private $EXPERT = false; - /** Quiet mode don't display empty results */ - private $QUIET; + /** Quiet mode don't display empty results */ + private $QUIET; - /** Store the controllers pathes to test - */ - private $controllersPath = array ("controllers/*.php"); + /** Store the controllers pathes to test + */ + private $controllersPath = array("controllers/*.php"); - /** Store the models pathes to test - */ - private $modelsPath = array ("models/*.php"); + /** Store the models pathes to test + */ + private $modelsPath = array("models/*.php"); - /** The construtor define the catching of the errors */ - public function __construct () - { - global $argv; - $launcher = $argv[0]; - chdir (dirname ($argv[0])."/.."); - // Catch the trigger_errors and display them politely - set_error_handler(array(&$this, "cliErrorHandler")); - } - - /** Define the controllers path - * @param string|array $path The controllers pathes to use - */ - public function controllersDir ($path) - { - if (! is_array ($path)) - $path = array ($path); - $this->controllersPath = $path; - } - - /** Define the models path - * @param string|array $path The models pathes to use - */ - public function modelsDir ($path) - { - if (! is_array ($path)) - $path = array ($path); - $this->modelsPath = $path; - } - - /** The error handler for CLI : display error in STDERR - * @param integer $errno The error type - * @param string $errstr The string to send in error - * @param string $errfile The error file which generate the error - * @param integer $errline The line with an error - */ - public function cliErrorHandler ($errno, $errstr, $errfile, $errline) - { - if (!(error_reporting() & $errno)) + /** The construtor define the catching of the errors */ + public function __construct() { - // This error code is not included in error_reporting - return; + global $argv; + $launcher = $argv[0]; + chdir(dirname($argv[0]) . "/.."); + // Catch the trigger_errors and display them politely + set_error_handler(array(&$this, "cliErrorHandler")); } - switch($errno) + + /** Define the controllers path + * @param string|array $path The controllers pathes to use + */ + public function controllersDir($path) { - case E_ERROR: $severity = "ERROR"; break; - case E_WARNING: $severity = "WARNING"; break; - case E_PARSE: $severity = "PARSE"; break; - case E_NOTICE: $severity = "NOTICE"; break; - case E_CORE_ERROR: $severity = "CORE_ERROR"; break; - case E_CORE_WARNING: $severity = "CORE_WARNING"; break; - case E_COMPILE_ERROR: $severity = "COMPILE_ERROR"; break; - case E_COMPILE_WARNING: $severity = "COMPILE_WARNING"; break; - case E_USER_ERROR: $severity = "USER_ERROR"; break; - case E_USER_WARNING: $severity = "USER_WARNING"; break; - case E_USER_NOTICE: $severity = "USER_NOTICE"; break; - case E_STRICT: $severity = "STRICT"; break; - case E_RECOVERABLE_ERROR: $severity = "RECOVERABLE_ERROR"; break; - case E_DEPRECATED: $severity = "DEPRECATED"; break; - case E_USER_DEPRECATED: $severity = "USER_DEPRECATED"; break; + if (! is_array($path)) { + $path = array($path); + } + $this->controllersPath = $path; } - file_put_contents ("php://stderr", sprintf ("%-17s", $severity)." ". - "$errstr [".basename ($errfile) . + + /** Define the models path + * @param string|array $path The models pathes to use + */ + public function modelsDir($path) + { + if (! is_array($path)) { + $path = array($path); + } + $this->modelsPath = $path; + } + + /** The error handler for CLI : display error in STDERR + * @param integer $errno The error type + * @param string $errstr The string to send in error + * @param string $errfile The error file which generate the error + * @param integer $errline The line with an error + */ + public function cliErrorHandler($errno, $errstr, $errfile, $errline) + { + if (!(error_reporting() & $errno)) { + // This error code is not included in error_reporting + return; + } + switch ($errno) { + case E_ERROR: + $severity = "ERROR"; + break; + case E_WARNING: + $severity = "WARNING"; + break; + case E_PARSE: + $severity = "PARSE"; + break; + case E_NOTICE: + $severity = "NOTICE"; + break; + case E_CORE_ERROR: + $severity = "CORE_ERROR"; + break; + case E_CORE_WARNING: + $severity = "CORE_WARNING"; + break; + case E_COMPILE_ERROR: + $severity = "COMPILE_ERROR"; + break; + case E_COMPILE_WARNING: + $severity = "COMPILE_WARNING"; + break; + case E_USER_ERROR: + $severity = "USER_ERROR"; + break; + case E_USER_WARNING: + $severity = "USER_WARNING"; + break; + case E_USER_NOTICE: + $severity = "USER_NOTICE"; + break; + case E_STRICT: + $severity = "STRICT"; + break; + case E_RECOVERABLE_ERROR: + $severity = "RECOVERABLE_ERROR"; + break; + case E_DEPRECATED: + $severity = "DEPRECATED"; + break; + case E_USER_DEPRECATED: + $severity = "USER_DEPRECATED"; + break; + } + file_put_contents("php://stderr", sprintf("%-17s", $severity) . " " . + "$errstr [" . basename($errfile) . ":$errline]\n"); - if ($this->EXPERT) - { - $e = new \Exception; - file_put_contents ("php://stderr", - print_r ($e->getTraceAsString(), TRUE)."\n"); - } - } - - /** The real application launcher and helpers - */ - public function run () - { - global $argv; - $launcher = $argv[0]; - array_shift ($argv); - - if (isset ($argv[0]) && $argv[0] === "-h") - { - echo "Execute in CLI a controller or a model (in expert mode)\n"; - echo " $launcher -h : display this help\n"; - echo " $launcher -list : display controllers\n"; - echo " $launcher -expert -list : display controllers and models\n"; - echo " $launcher -listmethods : \n"; - echo " display the methods available in the controller class\n"; - echo " $launcher -expert -listmethods :\n"; - echo " display the methods available in the model or controller class" - ."\n"; - echo " $launcher -listmethodsdetails : \n"; - echo " display the methods available in the controller class\n"; - echo " $launcher -expert -listmethodsdetails :\n"; - echo " display the methods available in the model or controller class" - ."\n"; - echo " $launcher [args]\n"; - echo " execute the method with the provided args\n"; - echo " $launcher -expert [args]\n"; - echo " execute the method with the provided args\n"; - echo "You can replace ONE arg by a dash (-) to read from stdin\n"; - echo "Arrays must be coded like key1=val1&key2=val2&key3=val3...\n"; - exit; + if ($this->EXPERT) { + $e = new \Exception(); + file_put_contents( + "php://stderr", + print_r($e->getTraceAsString(), true) . "\n" + ); + } } - $this->QUIET = FALSE; - if (isset ($argv[0]) && $argv[0] === "-q") + /** The real application launcher and helpers + */ + public function run() { - $this->QUIET = true; - array_shift ($argv); - } + global $argv; + $launcher = $argv[0]; + array_shift($argv); - $this->EXPERT = FALSE; - if (isset ($argv[0]) && $argv[0] === "-expert") - { - $this->EXPERT = TRUE; - array_shift ($argv); - } + if (isset($argv[0]) && $argv[0] === "-h") { + echo "Execute in CLI a controller or a model (in expert mode)\n"; + echo " $launcher -h : display this help\n"; + echo " $launcher -list : display controllers\n"; + echo " $launcher -expert -list : display controllers and models\n"; + echo " $launcher -listmethods : \n"; + echo " display the methods available in the controller class\n"; + echo " $launcher -expert -listmethods :\n"; + echo " display the methods available in the model or controller class" + . "\n"; + echo " $launcher -listmethodsdetails : \n"; + echo " display the methods available in the controller class\n"; + echo " $launcher -expert -listmethodsdetails :\n"; + echo " display the methods available in the model or controller class" + . "\n"; + echo " $launcher [args]\n"; + echo " execute the method with the provided args\n"; + echo " $launcher -expert [args]\n"; + echo " execute the method with the provided args\n"; + echo "You can replace ONE arg by a dash (-) to read from stdin\n"; + echo "Arrays must be coded like key1=val1&key2=val2&key3=val3...\n"; + exit; + } - // List the controllers and the models if the expert mode is activated - $files = array (); - foreach ($this->controllersPath as $path) - { - $files = array_merge ($files, glob ($path)); - } - if ($this->EXPERT) - { - foreach ($this->modelsPath as $path) - { - $files = array_merge ($files, glob ($path)); - } - } - if (count ($files) === 0 && $this->EXPERT === FALSE) - { - if (isset ($argv[0]) && $argv[0] === "-listonly") + $this->QUIET = false; + if (isset($argv[0]) && $argv[0] === "-q") { + $this->QUIET = true; + array_shift($argv); + } + + $this->EXPERT = false; + if (isset($argv[0]) && $argv[0] === "-expert") { + $this->EXPERT = true; + array_shift($argv); + } + + // List the controllers and the models if the expert mode is activated + $files = array(); + foreach ($this->controllersPath as $path) { + $files = array_merge($files, glob($path)); + } + if ($this->EXPERT) { + foreach ($this->modelsPath as $path) { + $files = array_merge($files, glob($path)); + } + } + if (count($files) === 0 && $this->EXPERT === false) { + if (isset($argv[0]) && $argv[0] === "-listonly") { + exit; + } + die("No controllers available in " . getcwd() . "\n"); + } + if (count($files) === 0 && $this->EXPERT === true) { + if (isset($argv[0]) && $argv[0] === "-listonly") { + exit; + } + die("No controllers/models available in " . getcwd() . "\n"); + } + foreach ($files as $file) { + if (strpos($file, "_")) { + $classes[substr(strstr($file, "_"), 1, -4)] = $file; + } else { + $classes[str_replace("/", "\\", substr($file, 0, -4))] = $file; + } + } + // Check if there is some classes which can be shorted (classes only in + // controllers or only in models + $shortClasses = array(); + foreach ($classes as $class => $file) { + $short = substr(strstr($class, "\\"), 1); + if ($short === false) { + $short = $class; + } + if (array_key_exists($short, $shortClasses)) { + unset($shortClasses[$short]); + } else { + $shortClasses[$short] = $class; + } + } + + if (isset($argv[0]) && $argv[0] === "-listonly") { + // Lists the classes available in controllers and models if expert mode + // Don't do any presentation to be parseable (by bash completion by + // example) + $classes = array_merge($classes, $shortClasses); + echo implode("\n", array_keys($classes)) . "\n"; + exit; + } + + if (isset($argv[0]) && $argv[0] === "-list") { + // Lists the classes available in controllers and models if expert mode + $classes = array_merge($classes, $shortClasses); + foreach ($classes as $key => $class) { + $classes[$key] = str_replace("\\", "\\\\", $class); + } + echo "List of classes available :\n"; + echo " " . implode("\n ", array_keys($classes)) . "\n"; + echo "Usage : " . $launcher; + if ($this->EXPERT) { + echo " -expert"; + } + echo " -listmethods \n"; + echo "Usage : " . $launcher; + if ($this->EXPERT) { + echo " -expert"; + } + echo " -listmethodsdetails \n"; + exit; + } + + if ( + isset($argv[0]) && $argv[0] === "-listmethods" || + isset($argv[0]) && $argv[0] === "-listmethodsdetails" || + isset($argv[0]) && $argv[0] === "-listmethodsonly" + ) { + // Lists the methods of a class + if (!isset($argv[1])) { + die("Missing parameter 'class'\n"); + } + $class = $argv[1]; + if ( + ! array_key_exists($class, $classes) && + ! array_key_exists($class, $shortClasses) + ) { + die("Unknown class '$class'\n"); + } + if (array_key_exists($class, $shortClasses)) { + $class = $shortClasses[$class]; + } + $file = $classes[$class]; + require_once($file); + $refclass = new \ReflectionClass($class); + // Look at constructor parameters + // PARAMETERS MUST NOT BE OPTIONNAL + $constParams = ""; + try { + $r = new \ReflectionMethod($class, "__construct"); + $params = $r->getParameters(); + foreach ($params as $param) { + $constParams .= " "; + $constParams .= " <"; + $constParams .= $param->name; + $constParams .= ">"; + } + } catch (\Exception $e) { + // No constructor + } + + // Look at methods + $methods = $refclass->getMethods(); + if ($argv[0] !== "-listmethodsonly") { + echo "List of methods available in the class '$class' :\n"; + } + foreach ($methods as $key => $method) { + if ($method->name === "__construct") { + continue; + } + // The private/protected methods can not be called + if ($method->isPrivate() || $method->isProtected()) { + continue; + } + if ($key > 0 && $argv[0] !== "-listmethodsonly") { + echo "\n"; + } + if ($argv[0] !== "-listmethodsonly") { + echo " "; + } + echo $method->name . $constParams; + if ($argv[0] !== "-listmethodsonly") { + $r = new \ReflectionMethod($class, $method->name); + $params = $r->getParameters(); + foreach ($params as $param) { + echo " "; + if ($param->isOptional()) { + echo "["; + } else { + echo " <"; + } + echo $param->name; + if ($param->isOptional()) { + echo "]"; + } else { + echo ">"; + } + } + + if ($argv[0] === "-listmethodsdetails") { + echo "\n"; + echo trim(substr($method->getDocComment(), 3, -2)); + } + } + echo "\n"; + } + exit; + } + + // Execution of the class->method + if (!isset($argv[0])) { + echo "No class to execute provided\n"; + echo "Usage : $launcher -list\n"; + echo "Usage : $launcher -expert -list\n"; + exit; + } + $class = $argv[0]; + if ( + ! array_key_exists($class, $classes) && + ! array_key_exists($class, $shortClasses) + ) { + die("Unknown class '$class'\n"); + } + if (array_key_exists($class, $shortClasses)) { + $class = $shortClasses[$class]; + } + $file = $classes[$class]; + require_once($file); + array_shift($argv); + if (!isset($argv[0])) { + die("No method for class '$class' to execute\n"); + } + $method = $argv[0]; + array_shift($argv); + $refclass = new \ReflectionClass($class); + $methods = $refclass->getMethods(); + $found = false; + foreach ($methods as $meth) { + if ($meth->name === $method) { + $found = true; + break; + } + } + + if ($found === false) { + die("Method '$method' not available in class '$class'\n"); + } + $min = 0; + $max = 0; + $paramsConst = array(); + try { + $r1 = new \ReflectionMethod($class, "__construct"); + $paramsConst = $r1->getParameters(); + $min = $max = count($paramsConst); + } catch (\Exception $e) { + // No constructor available in class + } + + $r2 = new \ReflectionMethod($class, $method); + $params = $r2->getParameters(); + foreach ($params as $param) { + if (!$param->isOptional()) { + $min++; + } + $max++; + } + + if (in_array("-?", $argv)) { + // Question mark display the PHPDoc of the method + $comment = trim(substr($r1->getDocComment(), 3, -2)); + if ($comment !== "") { + $comment .= "\n"; + } + $comment .= trim(substr($r2->getDocComment(), 3, -2)); + $comment = preg_replace("#^\s*\*\s*#m", "", $comment); + $comment = preg_replace("#@param .+ \\$(\w+) #U", "<\\1> ", $comment); + $params = ""; + foreach ($r1->getParameters() as $param) { + $params .= "<" . $param->name . "> "; + } + foreach ($r2->getParameters() as $param) { + $params .= "<" . $param->name . "> "; + } + echo "Parameters : $params\n$comment\n"; + exit; + } + unset($r1); + unset($r2); + + if (count($argv) < $min) { + die("Not enough parameters provided to method\n"); + } + if (in_array("-", $argv)) { + $tab = array_keys($argv, "-"); + $keyStdIn = reset($tab); + $dataStdIn = file_get_contents("php://stdin"); + $argv[$keyStdIn] = $dataStdIn; + } + + // Convert "toto=ror&ypyp=oo" arg to array("toto"=>"ror","ypyp"=>"oo") + // (Array management in CLI) + foreach ($argv as $key => $arg) { + // Don't modify the stdin + if (isset($keyStdIn) && $key === $keyStdIn) { + continue; + } + $pairs = explode('&', $arg); + + foreach ($pairs as $pair) { + @list($name, $value) = explode('=', $pair, 2); + if ($value === null) { + $argv[$key] = $name; + } else { + if (! is_array($argv[$key])) { + $argv[$key] = array(); + } + $argv[$key][$name] = $value; + } + } + } + + // Manage a parameter in the constructor of the class + $paramConst = array(); + if (count($paramsConst) > 0) { + $paramConst = array_slice($argv, 0, count($paramsConst)); + $argv = array_slice($argv, count($paramsConst)); + } + + try { + $classReflection = new \ReflectionClass($class); + $r = $classReflection->newInstanceArgs($paramConst); + $s = call_user_func_array(array($r, $method), $argv); + if ($this->QUIET === false || $s !== "" && $s !== array() && $s !== null) { + if (is_string($s)) { + echo $s; + } elseif (is_array($s)) { + print_r($s); + } else { + var_dump($s); + } + } + } catch (\Exception $e) { + file_put_contents("php://stderr", $e->getMessage() . "\n"); + if ($this->EXPERT) { + file_put_contents("php://stderr", $e->getTraceAsString() . "\n"); + } + } exit; - die ("No controllers available in ".getcwd()."\n"); } - if (count ($files) === 0 && $this->EXPERT === TRUE) - { - if (isset ($argv[0]) && $argv[0] === "-listonly") - exit; - die ("No controllers/models available in ".getcwd()."\n"); - } - foreach ($files as $file) - { - if (strpos ($file, "_")) - $classes[substr (strstr ($file, "_"), 1, -4)] = $file; - else - $classes[str_replace ("/", "\\", substr ($file, 0, -4))] = $file; - } - // Check if there is some classes which can be shorted (classes only in - // controllers or only in models - $shortClasses = array (); - foreach ($classes as $class=>$file) - { - $short = substr (strstr ($class, "\\"), 1); - if ($short === false) $short = $class; - if (array_key_exists ($short, $shortClasses)) - unset ($shortClasses[$short]); - else - $shortClasses[$short] = $class; - } - - if (isset ($argv[0]) && $argv[0] === "-listonly") - { - // Lists the classes available in controllers and models if expert mode - // Don't do any presentation to be parseable (by bash completion by - // example) - $classes = array_merge ($classes, $shortClasses); - echo implode ("\n", array_keys ($classes))."\n"; - exit; - } - - if (isset ($argv[0]) && $argv[0] === "-list") - { - // Lists the classes available in controllers and models if expert mode - $classes = array_merge ($classes, $shortClasses); - foreach ($classes as $key=>$class) - $classes[$key] = str_replace ("\\", "\\\\", $class); - echo "List of classes available :\n"; - echo " ".implode ("\n ", array_keys ($classes))."\n"; - echo "Usage : ".$launcher; - if ($this->EXPERT) echo " -expert"; - echo " -listmethods \n"; - echo "Usage : ".$launcher; - if ($this->EXPERT) echo " -expert"; - echo " -listmethodsdetails \n"; - exit; - } - - if (isset ($argv[0]) && $argv[0] === "-listmethods" || - isset ($argv[0]) && $argv[0] === "-listmethodsdetails" || - isset ($argv[0]) && $argv[0] === "-listmethodsonly") - { - // Lists the methods of a class - if (!isset ($argv[1])) - die ("Missing parameter 'class'\n"); - $class = $argv[1]; - if (! array_key_exists ($class, $classes) && - ! array_key_exists ($class, $shortClasses)) - die ("Unknown class '$class'\n"); - if (array_key_exists ($class, $shortClasses)) - $class = $shortClasses[$class]; - $file = $classes[$class]; - require_once ($file); - $refclass = new \ReflectionClass ($class); - // Look at constructor parameters - // PARAMETERS MUST NOT BE OPTIONNAL - $constParams = ""; - try - { - $r = new \ReflectionMethod ($class, "__construct"); - $params = $r->getParameters(); - foreach ($params as $param) - { - $constParams .= " "; - $constParams .= " <"; - $constParams .= $param->name; - $constParams .= ">"; - } - } - catch (\Exception $e) - { - // No constructor - } - - // Look at methods - $methods = $refclass->getMethods(); - if ($argv[0] !== "-listmethodsonly") - echo "List of methods available in the class '$class' :\n"; - foreach ($methods as $key=>$method) - { - if ($method->name === "__construct") - continue; - // The private/protected methods can not be called - if ($method->isPrivate () || $method->isProtected ()) - continue; - if ($key > 0 && $argv[0] !== "-listmethodsonly") - echo "\n"; - if ($argv[0] !== "-listmethodsonly") - echo " "; - echo $method->name.$constParams; - if ($argv[0] !== "-listmethodsonly") - { - $r = new \ReflectionMethod ($class, $method->name); - $params = $r->getParameters(); - foreach ($params as $param) - { - echo " "; - if ($param->isOptional()) - echo "["; - else - echo " <"; - echo $param->name; - if ($param->isOptional()) - echo "]"; - else - echo ">"; - } - - if ($argv[0] === "-listmethodsdetails") - { - echo "\n"; - echo trim (substr ($method->getDocComment(), 3, -2)); - } - } - echo "\n"; - } - exit; - } - - // Execution of the class->method - if (!isset ($argv[0])) - { - echo "No class to execute provided\n"; - echo "Usage : $launcher -list\n"; - echo "Usage : $launcher -expert -list\n"; - exit; - } - $class = $argv[0]; - if (! array_key_exists ($class, $classes) && - ! array_key_exists ($class, $shortClasses)) - die ("Unknown class '$class'\n"); - if (array_key_exists ($class, $shortClasses)) - $class = $shortClasses[$class]; - $file = $classes[$class]; - require_once ($file); - array_shift ($argv); - if (!isset ($argv[0])) - die ("No method for class '$class' to execute\n"); - $method = $argv[0]; - array_shift ($argv); - $refclass = new \ReflectionClass ($class); - $methods = $refclass->getMethods(); - $found = FALSE; - foreach ($methods as $meth) - { - if ($meth->name === $method) - { - $found = TRUE; - break; - } - } - - if ($found === FALSE) - die ("Method '$method' not available in class '$class'\n"); - $min = 0; $max = 0; - $paramsConst = array (); - try - { - $r1 = new \ReflectionMethod ($class, "__construct"); - $paramsConst = $r1->getParameters(); - $min = $max = count ($paramsConst); - } - catch (\Exception $e) - { - // No constructor available in class - } - - $r2 = new \ReflectionMethod ($class, $method); - $params = $r2->getParameters(); - foreach ($params as $param) - { - if (!$param->isOptional()) - $min++; - $max++; - } - - if (in_array ("-?", $argv)) - { - // Question mark display the PHPDoc of the method - $comment = trim (substr ($r1->getDocComment (), 3, -2)); - if ($comment !== "") $comment .= "\n"; - $comment .= trim (substr ($r2->getDocComment (), 3, -2)); - $comment = preg_replace ("#^\s*\*\s*#m", "", $comment); - $comment = preg_replace ("#@param .+ \\$(\w+) #U", "<\\1> ", $comment); - $params = ""; - foreach ($r1->getParameters() as $param) - $params .= "<".$param->name."> "; - foreach ($r2->getParameters() as $param) - $params .= "<".$param->name."> "; - echo "Parameters : $params\n$comment\n"; - exit; - } - unset ($r1); - unset ($r2); - - if (count ($argv) < $min) - die ("Not enough parameters provided to method\n"); - if (in_array ("-", $argv)) - { - $tab = array_keys ($argv, "-"); - $keyStdIn = reset ($tab); - $dataStdIn = file_get_contents ("php://stdin"); - $argv[$keyStdIn] = $dataStdIn; - } - - // Convert "toto=ror&ypyp=oo" arg to array("toto"=>"ror","ypyp"=>"oo") - // (Array management in CLI) - foreach ($argv as $key=>$arg) - { - // Don't modify the stdin - if (isset ($keyStdIn) && $key === $keyStdIn) - continue; - $pairs = explode('&', $arg); - - foreach($pairs as $pair) - { - @list ($name, $value) = explode ('=', $pair, 2); - if ($value === null) - { - $argv[$key] = $name; - } - else - { - if (! is_array ($argv[$key])) - $argv[$key] = array (); - $argv[$key][$name] = $value; - } - } - } - - // Manage a parameter in the constructor of the class - $paramConst = array (); - if (count ($paramsConst) > 0) - { - $paramConst = array_slice ($argv, 0, count ($paramsConst)); - $argv = array_slice ($argv, count ($paramsConst)); - } - - try - { - $classReflection = new \ReflectionClass($class); - $r = $classReflection->newInstanceArgs($paramConst); - $s = call_user_func_array(array($r, $method), $argv); - if ($this->QUIET === false || $s !== "" && $s !== array () && $s !== null) - { - if (is_string ($s)) - echo $s; - elseif (is_array ($s)) - print_r ($s); - else - var_dump ($s); - } - } - catch (\Exception $e) - { - file_put_contents("php://stderr", $e->getMessage()."\n"); - if ($this->EXPERT) - file_put_contents ("php://stderr", $e->getTraceAsString()."\n"); - } - exit; - } } diff --git a/src/Color.php b/src/Color.php index 16b0e51..42a57da 100644 --- a/src/Color.php +++ b/src/Color.php @@ -1,4 +1,5 @@ @@ -11,269 +12,279 @@ namespace Domframework; */ class Color { - /** The color list - * From http://www.rapidtables.com/web/color/index.htm - */ - public $colorList = array ( + /** The color list + * From http://www.rapidtables.com/web/color/index.htm + */ + public $colorList = array( // Black - "black" => array (0, 0, 0), - "dimgrey" => array (105, 105, 105), - "grey" => array (128, 128, 128), - "darkgrey" => array (169, 169, 169), - "silver" => array (192, 192, 192), + "black" => array(0, 0, 0), + "dimgrey" => array(105, 105, 105), + "grey" => array(128, 128, 128), + "darkgrey" => array(169, 169, 169), + "silver" => array(192, 192, 192), // Blue - "aliceblue" => array (240, 248, 255), - "lavender" => array (230, 230, 250), - "powderblue" => array (176, 224, 230), - "lightblue" => array (173, 216, 230), - "lightskyblue" => array (135, 206, 250), - "skyblue" => array (135, 206, 235), - "deepskyblue" => array (0, 191, 255), - "lightsteelblue" => array (176, 196, 222), - "dodgerblue" => array (30, 144, 255), - "cornflowerblue" => array (100, 149, 237), - "steelblue" => array (70, 130, 180), - "cadetblue" => array (95, 158, 160), - "mediumslateblue" => array (123, 104, 238), - "slateblue" => array (106, 90, 205), - "darkslateblue" => array (72, 61, 139), - "royalblue" => array (65, 105, 225), - "blue" => array (0, 0, 255), - "mediumblue" => array (0, 0, 205), - "darkblue" => array (0, 0, 139), - "navy" => array (0, 0, 128), - "midnightblue" => array (25, 25, 112), - "blueviolet" => array (138, 43, 226), - "indigo" => array (75, 0, 130), + "aliceblue" => array(240, 248, 255), + "lavender" => array(230, 230, 250), + "powderblue" => array(176, 224, 230), + "lightblue" => array(173, 216, 230), + "lightskyblue" => array(135, 206, 250), + "skyblue" => array(135, 206, 235), + "deepskyblue" => array(0, 191, 255), + "lightsteelblue" => array(176, 196, 222), + "dodgerblue" => array(30, 144, 255), + "cornflowerblue" => array(100, 149, 237), + "steelblue" => array(70, 130, 180), + "cadetblue" => array(95, 158, 160), + "mediumslateblue" => array(123, 104, 238), + "slateblue" => array(106, 90, 205), + "darkslateblue" => array(72, 61, 139), + "royalblue" => array(65, 105, 225), + "blue" => array(0, 0, 255), + "mediumblue" => array(0, 0, 205), + "darkblue" => array(0, 0, 139), + "navy" => array(0, 0, 128), + "midnightblue" => array(25, 25, 112), + "blueviolet" => array(138, 43, 226), + "indigo" => array(75, 0, 130), // Brown - "cornsilk" => array (255, 248, 220), - "blanchedalmond" => array (255, 235, 205), - "bisque" => array (255, 228, 196), - "navajowhite" => array (255, 222, 173), - "wheat" => array (245, 222, 179), - "burlywood" => array (222, 184, 135), - "tan" => array (210, 180, 140), - "rosybrown" => array (188, 143, 143), - "sandybrown" => array (244, 164, 96), - "goldenrod" => array (218, 165, 32), - "peru" => array (205, 133, 63), - "chocolate" => array (210, 105, 30), - "saddlebrown" => array (139, 69, 19), - "sienna" => array (160, 82, 45), - "brown" => array (165, 42, 42), - "maroon" => array (128, 0, 0), + "cornsilk" => array(255, 248, 220), + "blanchedalmond" => array(255, 235, 205), + "bisque" => array(255, 228, 196), + "navajowhite" => array(255, 222, 173), + "wheat" => array(245, 222, 179), + "burlywood" => array(222, 184, 135), + "tan" => array(210, 180, 140), + "rosybrown" => array(188, 143, 143), + "sandybrown" => array(244, 164, 96), + "goldenrod" => array(218, 165, 32), + "peru" => array(205, 133, 63), + "chocolate" => array(210, 105, 30), + "saddlebrown" => array(139, 69, 19), + "sienna" => array(160, 82, 45), + "brown" => array(165, 42, 42), + "maroon" => array(128, 0, 0), // Cyan - "lightcyan" => array (224, 255, 255), - "cyan" => array (0, 255, 255), - "aqua" => array (0, 255, 255), - "aquamarine" => array (127, 255, 212), - "mediumaquamarine" => array (102, 205, 170), - "paleturquoise" => array (175, 238, 238), - "turquoise" => array (64, 224, 208), - "mediumturquoise" => array (72, 209, 204), - "darkturquoise" => array (0, 206, 209), - "lightseagreen" => array (32, 178, 170), - "cadetblue" => array (95, 158, 160), - "darkcyan" => array (0, 139, 139), - "teal" => array (0, 128, 128), + "lightcyan" => array(224, 255, 255), + "cyan" => array(0, 255, 255), + "aqua" => array(0, 255, 255), + "aquamarine" => array(127, 255, 212), + "mediumaquamarine" => array(102, 205, 170), + "paleturquoise" => array(175, 238, 238), + "turquoise" => array(64, 224, 208), + "mediumturquoise" => array(72, 209, 204), + "darkturquoise" => array(0, 206, 209), + "lightseagreen" => array(32, 178, 170), + "cadetblue" => array(95, 158, 160), + "darkcyan" => array(0, 139, 139), + "teal" => array(0, 128, 128), // Gold - "lightgoldenrodyellow" => array (250, 250, 210), - "palegoldenrod" => array (238, 232, 170), - "khaki" => array (240, 230, 140), - "goldenrod" => array (218, 165, 32), - "gold" => array (255, 215, 0), - "orange" => array (255, 165, 0), - "darkorange" => array (255, 140, 0), - "peru" => array (205, 133, 63), - "chocolate" => array (210, 105, 30), - "saddlebrown" => array (139, 69, 19), - "sienna" => array (160, 82, 45), - "goldenyellow" => array (255, 223, 0), - "metallicgold" => array (212, 175, 55), - "oldgold" => array (207, 181, 59), - "vegasgold" => array (197, 179, 88), - "palegold" => array (230, 190, 138), - "goldenbrown" => array (153, 101, 21), + "lightgoldenrodyellow" => array(250, 250, 210), + "palegoldenrod" => array(238, 232, 170), + "khaki" => array(240, 230, 140), + "goldenrod" => array(218, 165, 32), + "gold" => array(255, 215, 0), + "orange" => array(255, 165, 0), + "darkorange" => array(255, 140, 0), + "peru" => array(205, 133, 63), + "chocolate" => array(210, 105, 30), + "saddlebrown" => array(139, 69, 19), + "sienna" => array(160, 82, 45), + "goldenyellow" => array(255, 223, 0), + "metallicgold" => array(212, 175, 55), + "oldgold" => array(207, 181, 59), + "vegasgold" => array(197, 179, 88), + "palegold" => array(230, 190, 138), + "goldenbrown" => array(153, 101, 21), // Green - "lawngreen" => array (124, 252, 0), - "chartreuse" => array (127, 255, 0), - "limegreen" => array (50, 205, 50), - "lime" => array (0, 255, 0), - "forestgreen" => array (34, 139, 34), - "green" => array (0, 128, 0), - "darkgreen" => array (0, 100, 0), - "greenyellow" => array (173, 255, 47), - "yellowgreen" => array (154, 205, 50), - "springgreen" => array (0, 255, 127), - "mediumspringgreen" => array (0, 250, 154), - "lightgreen" => array (144, 238, 144), - "palegreen" => array (152, 251, 152), - "darkseagreen" => array (143, 188, 143), - "mediumseagreen" => array (60, 179, 113), - "lightseagreen" => array (32, 178, 170), - "seagreen" => array (46, 139, 87), - "olive" => array (128, 128, 0), - "darkolivegreen" => array (85, 107, 47), - "olivedrab" => array (107, 142, 35), + "lawngreen" => array(124, 252, 0), + "chartreuse" => array(127, 255, 0), + "limegreen" => array(50, 205, 50), + "lime" => array(0, 255, 0), + "forestgreen" => array(34, 139, 34), + "green" => array(0, 128, 0), + "darkgreen" => array(0, 100, 0), + "greenyellow" => array(173, 255, 47), + "yellowgreen" => array(154, 205, 50), + "springgreen" => array(0, 255, 127), + "mediumspringgreen" => array(0, 250, 154), + "lightgreen" => array(144, 238, 144), + "palegreen" => array(152, 251, 152), + "darkseagreen" => array(143, 188, 143), + "mediumseagreen" => array(60, 179, 113), + "lightseagreen" => array(32, 178, 170), + "seagreen" => array(46, 139, 87), + "olive" => array(128, 128, 0), + "darkolivegreen" => array(85, 107, 47), + "olivedrab" => array(107, 142, 35), // Grey - "gainsboro" => array (220, 220, 220), - "lightgray" => array (211, 211, 211), - "lightgrey" => array (211, 211, 211), - "silver" => array (192, 192, 192), - "darkgray" => array (169, 169, 169), - "darkgrey" => array (169, 169, 169), - "gray" => array (128, 128, 128), - "grey" => array (128, 128, 128), - "dimgray" => array (105, 105, 105), - "dimgrey" => array (105, 105, 105), - "lightslategray" => array (119, 136, 153), - "lightslategrey" => array (119, 136, 153), - "slategray" => array (112, 128, 144), - "slategrey" => array (112, 128, 144), - "darkslategray" => array (47, 79, 79), - "darkslategrey" => array (47, 79, 79), - "black" => array (0, 0, 0), + "gainsboro" => array(220, 220, 220), + "lightgray" => array(211, 211, 211), + "lightgrey" => array(211, 211, 211), + "silver" => array(192, 192, 192), + "darkgray" => array(169, 169, 169), + "darkgrey" => array(169, 169, 169), + "gray" => array(128, 128, 128), + "grey" => array(128, 128, 128), + "dimgray" => array(105, 105, 105), + "dimgrey" => array(105, 105, 105), + "lightslategray" => array(119, 136, 153), + "lightslategrey" => array(119, 136, 153), + "slategray" => array(112, 128, 144), + "slategrey" => array(112, 128, 144), + "darkslategray" => array(47, 79, 79), + "darkslategrey" => array(47, 79, 79), + "black" => array(0, 0, 0), // Maroon - "maroon" => array (128, 0, 0), - "darkred" => array (139, 0, 0), - "brown" => array (165, 42, 42), - "firebrick" => array (178, 34, 34), - "crimson" => array (220, 20, 60), + "maroon" => array(128, 0, 0), + "darkred" => array(139, 0, 0), + "brown" => array(165, 42, 42), + "firebrick" => array(178, 34, 34), + "crimson" => array(220, 20, 60), // Orange - "coral" => array (255, 127, 80), - "tomato" => array (255, 99, 71), - "orangered" => array (255, 69, 0), - "gold" => array (255, 215, 0), - "orange" => array (255, 165, 0), - "darkorange" => array (255, 140, 0), + "coral" => array(255, 127, 80), + "tomato" => array(255, 99, 71), + "orangered" => array(255, 69, 0), + "gold" => array(255, 215, 0), + "orange" => array(255, 165, 0), + "darkorange" => array(255, 140, 0), // Pink - "pink" => array (255, 192, 203), - "lightpink" => array (255, 182, 193), - "hotpink" => array (255, 105, 180), - "deeppink" => array (255, 20, 147), - "palevioletred" => array (219, 112, 147), - "mediumvioletred" => array (199, 21, 133), + "pink" => array(255, 192, 203), + "lightpink" => array(255, 182, 193), + "hotpink" => array(255, 105, 180), + "deeppink" => array(255, 20, 147), + "palevioletred" => array(219, 112, 147), + "mediumvioletred" => array(199, 21, 133), // Purple - "lavender" => array (230, 230, 250), - "thistle" => array (216, 191, 216), - "plum" => array (221, 160, 221), - "violet" => array (238, 130, 238), - "orchid" => array (218, 112, 214), - "fuchsia" => array (255, 0, 255), - "magenta" => array (255, 0, 255), - "mediumorchid" => array (186, 85, 211), - "mediumpurple" => array (147, 112, 219), - "blueviolet" => array (138, 43, 226), - "darkviolet" => array (148, 0, 211), - "darkorchid" => array (153, 50, 204), - "darkmagenta" => array (139, 0, 139), - "purple" => array (128, 0, 128), - "indigo" => array (75, 0, 130), + "lavender" => array(230, 230, 250), + "thistle" => array(216, 191, 216), + "plum" => array(221, 160, 221), + "violet" => array(238, 130, 238), + "orchid" => array(218, 112, 214), + "fuchsia" => array(255, 0, 255), + "magenta" => array(255, 0, 255), + "mediumorchid" => array(186, 85, 211), + "mediumpurple" => array(147, 112, 219), + "blueviolet" => array(138, 43, 226), + "darkviolet" => array(148, 0, 211), + "darkorchid" => array(153, 50, 204), + "darkmagenta" => array(139, 0, 139), + "purple" => array(128, 0, 128), + "indigo" => array(75, 0, 130), // Red - "lightsalmon" => array (255, 160, 122), - "salmon" => array (250, 128, 114), - "darksalmon" => array (233, 150, 122), - "lightcoral" => array (240, 128, 128), - "indianred" => array (205, 92, 92), - "crimson" => array (220, 20, 60), - "firebrick" => array (178, 34, 34), - "red" => array (255, 0, 0), - "darkred" => array (139, 0, 0), - "maroon" => array (128, 0, 0), - "tomato" => array (255, 99, 71), - "orangered" => array (255, 69, 0), - "palevioletred" => array (219, 112, 147), + "lightsalmon" => array(255, 160, 122), + "salmon" => array(250, 128, 114), + "darksalmon" => array(233, 150, 122), + "lightcoral" => array(240, 128, 128), + "indianred" => array(205, 92, 92), + "crimson" => array(220, 20, 60), + "firebrick" => array(178, 34, 34), + "red" => array(255, 0, 0), + "darkred" => array(139, 0, 0), + "maroon" => array(128, 0, 0), + "tomato" => array(255, 99, 71), + "orangered" => array(255, 69, 0), + "palevioletred" => array(219, 112, 147), // White - "white" => array (255, 255, 255), - "snow" => array (255, 250, 250), - "honeydew" => array (240, 255, 240), - "mintcream" => array (245, 255, 250), - "azure" => array (240, 255, 255), - "aliceblue" => array (240, 248, 255), - "ghostwhite" => array (248, 248, 255), - "whitesmoke" => array (245, 245, 245), - "seashell" => array (255, 245, 238), - "beige" => array (245, 245, 220), - "oldlace" => array (253, 245, 230), - "floralwhite" => array (255, 250, 240), - "ivory" => array (255, 255, 240), - "antiquewhite" => array (250, 235, 215), - "linen" => array (250, 240, 230), - "lavenderblush" => array (255, 240, 245), - "mistyrose" => array (255, 228, 225), - "navajowhite" => array (255, 222, 173), + "white" => array(255, 255, 255), + "snow" => array(255, 250, 250), + "honeydew" => array(240, 255, 240), + "mintcream" => array(245, 255, 250), + "azure" => array(240, 255, 255), + "aliceblue" => array(240, 248, 255), + "ghostwhite" => array(248, 248, 255), + "whitesmoke" => array(245, 245, 245), + "seashell" => array(255, 245, 238), + "beige" => array(245, 245, 220), + "oldlace" => array(253, 245, 230), + "floralwhite" => array(255, 250, 240), + "ivory" => array(255, 255, 240), + "antiquewhite" => array(250, 235, 215), + "linen" => array(250, 240, 230), + "lavenderblush" => array(255, 240, 245), + "mistyrose" => array(255, 228, 225), + "navajowhite" => array(255, 222, 173), // Yellow - "lightyellow" => array (255, 255, 224), - "lemonchiffon" => array (255, 250, 205), - "lightgoldenrodyellow" => array (250, 250, 210), - "papayawhip" => array (255, 239, 213), - "moccasin" => array (255, 228, 181), - "peachpuff" => array (255, 218, 185), - "palegoldenrod" => array (238, 232, 170), - "khaki" => array (240, 230, 140), - "darkkhaki" => array (189, 183, 107), - "yellow" => array (255, 255, 0), - "olive" => array (128, 128, 0), - "greenyellow" => array (173, 255, 47), - "yellowgreen" => array (154, 205, 50), - "lightyellow1" => array (255, 255, 204), - "lightyellow2" => array (255, 255, 153), - "lightyellow3" => array (255, 255, 102), - "lightyellow4" => array (255, 255, 51), - "yellow" => array (255, 255, 0), - "darkyellow1" => array (204, 204, 0), - "darkyellow2" => array (153, 153, 0), - "darkyellow3" => array (102, 102, 0), - "darkyellow4" => array (51, 51, 0), - ); + "lightyellow" => array(255, 255, 224), + "lemonchiffon" => array(255, 250, 205), + "lightgoldenrodyellow" => array(250, 250, 210), + "papayawhip" => array(255, 239, 213), + "moccasin" => array(255, 228, 181), + "peachpuff" => array(255, 218, 185), + "palegoldenrod" => array(238, 232, 170), + "khaki" => array(240, 230, 140), + "darkkhaki" => array(189, 183, 107), + "yellow" => array(255, 255, 0), + "olive" => array(128, 128, 0), + "greenyellow" => array(173, 255, 47), + "yellowgreen" => array(154, 205, 50), + "lightyellow1" => array(255, 255, 204), + "lightyellow2" => array(255, 255, 153), + "lightyellow3" => array(255, 255, 102), + "lightyellow4" => array(255, 255, 51), + "yellow" => array(255, 255, 0), + "darkyellow1" => array(204, 204, 0), + "darkyellow2" => array(153, 153, 0), + "darkyellow3" => array(102, 102, 0), + "darkyellow4" => array(51, 51, 0), + ); - /** Return the list of the known colors list - */ - public static function colorList () - { - $color = new color (); - $colorList = $color->colorList; - return array_keys ($colorList); - } + /** Return the list of the known colors list + */ + public static function colorList() + { + $color = new color(); + $colorList = $color->colorList; + return array_keys($colorList); + } - /** Return an array with the RGB colors - * @param string $colorInText The color in textual form - */ - public static function textToRGB ($colorInText) - { - $color = new color (); - $colorList = $color->colorList; - if (! array_key_exists ($colorInText, $colorList)) - throw new \Exception (sprintf (dgettext ("domframework", - "Unknown color provided to graphColor::textToRGB: '%s'"), - $colorInText), 500); - return $colorList[$colorInText]; - } + /** Return an array with the RGB colors + * @param string $colorInText The color in textual form + */ + public static function textToRGB($colorInText) + { + $color = new color(); + $colorList = $color->colorList; + if (! array_key_exists($colorInText, $colorList)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown color provided to graphColor::textToRGB: '%s'" + ), + $colorInText + ), 500); + } + return $colorList[$colorInText]; + } - /** Allocate the color provided in text to the provided GD object - * @param resource $gd The GD resource to add the color - * @param string $colorInText The color in textual form - */ - public static function allocateFromText ($gd, $colorInText) - { - if (! function_exists ("imagecolorallocate")) - throw new \Exception (dgettext ("domframework", - "No GD support in PHP : can't allocate color"), - 500); - $rgb = color::textToRGB ($colorInText); - return imagecolorallocate ($gd, $rgb[0], $rgb[1], $rgb[2]); - } + /** Allocate the color provided in text to the provided GD object + * @param resource $gd The GD resource to add the color + * @param string $colorInText The color in textual form + */ + public static function allocateFromText($gd, $colorInText) + { + if (! function_exists("imagecolorallocate")) { + throw new \Exception( + dgettext( + "domframework", + "No GD support in PHP : can't allocate color" + ), + 500 + ); + } + $rgb = color::textToRGB($colorInText); + return imagecolorallocate($gd, $rgb[0], $rgb[1], $rgb[2]); + } } diff --git a/src/Config.php b/src/Config.php index 2dc231f..d77b125 100644 --- a/src/Config.php +++ b/src/Config.php @@ -1,4 +1,5 @@ @@ -27,491 +28,591 @@ namespace Domframework; */ class Config { - /** All the parameters allowed with their default value */ - public $default = array (); - /** Use the .php to protect the information */ - public $confFile = null; + /** All the parameters allowed with their default value */ + public $default = array(); + /** Use the .php to protect the information */ + public $confFile = null; - /** Select the configuration file - */ - public function selectConfFile () - { - if ($this->confFile !== null) - $this->confFile = $this->confFile; - elseif (defined("CONFIGFILE")) - $this->confFile = CONFIGFILE; - elseif (file_exists ("./datas/configuration.php")) - $this->confFile = "./datas/configuration.php"; - elseif (file_exists ("./data/configuration.php")) - $this->confFile = "./data/configuration.php"; - else - $this->confFile = "./data/configuration.php"; - } - - /** List all the parameters configurable in the software - */ - public function params () - { - $this->selectConfFile (); - return $this->default; - } - - /** Return the defined values in array format - */ - public function getAll () - { - $this->selectConfFile (); - $conf = array (); - $rc = include ($this->confFile); - if ($rc !== 1) - throw new \Exception ("Error in configuration file", 500); - return $conf; - } - - /** Return the defined values in Slash format - */ - public function getAllInSlash () - { - $conf = $this->getAll (); - $vals = array (); - foreach ($this->docComment () as $key) + /** Select the configuration file + */ + public function selectConfFile() { - if (! key_exists ("param", $key)) - continue; - if (substr ($key["param"], 0, 1) !== "/") - throw new \Exception ("Config param '".$key["param"]. - "' don't start by /"); - $exp = explode ("/", $key["param"]); - unset ($exp[0]); - if (count ($exp) === 1 && key_exists ($exp[1], $conf)) - $vals[$key["param"]] = $conf[$exp[1]]; - elseif (count ($exp) === 2 && key_exists ($exp[1], $conf) && - key_exists ($exp[2], $conf[$exp[1]])) - $vals[$key["param"]] = $conf[$exp[1]][$exp[2]]; - elseif (count ($exp) === 3 && key_exists ($exp[1], $conf) && - key_exists ($exp[2], $conf[$exp[1]]) && - key_exists ($exp[3], $conf[$exp[1]][$exp[2]])) - $vals[$key["param"]] = $conf[$exp[1]][$exp[2]][$exp[3]]; - } - return $vals; - } - - /** Get the value of the provided parameter recorded in .php file - * If it is not set in .php file, use the default value - * @param string $param The option name to be returned - */ - public function get ($param) - { - $this->selectConfFile (); - if (!array_key_exists ($param, $this->default)) - throw new \Exception ("Unknown configuration parameter '$param'", 500); - if (!file_exists ($this->confFile)) - { - if (@file_put_contents ($this->confFile, - "confFile), 500); - } - elseif (! is_readable ($this->confFile)) - throw new \Exception (sprintf ( dgettext ("domframework", - "The configuration file '%s' is not readable"), - $this->confFile)); - $conf = array (); - $rc = include ($this->confFile); - if ($rc !== 1) - throw new \Exception ("Error in configuration file", 500); - if (! array_key_exists ($param, $this->default)) - throw new \Exception (sprintf ("Configuration parameter '%s' not defined", - $param), 500); - // Create a conf where all the keys are defined. If the keys are already - // define, use them, or use the default ones - // Don't allow keys not defined in default ones - if (! is_array ($this->default[$param])) - { - if (! array_key_exists ($param, $conf)) - return $this->default[$param]; - return $conf[$param]; - } - foreach ($this->default[$param] as $key=>$val) - { - if ($key === "not configured") - { - if (! array_key_exists ($param, $conf)) - continue; - foreach ($conf[$param] as $k=>$v) - { - $conf[$param][$k] = array_replace_recursive ($val, - $conf[$param][$k]); + if ($this->confFile !== null) { + $this->confFile = $this->confFile; + } elseif (defined("CONFIGFILE")) { + $this->confFile = CONFIGFILE; + } elseif (file_exists("./datas/configuration.php")) { + $this->confFile = "./datas/configuration.php"; + } elseif (file_exists("./data/configuration.php")) { + $this->confFile = "./data/configuration.php"; + } else { + $this->confFile = "./data/configuration.php"; } - continue; - } - if (! isset ($conf[$param][$key])) - $conf[$param][$key] = $val; - elseif (is_array ($val)) - $conf[$param][$key] = array_replace_recursive ($val, - $conf[$param][$key]); - } - if (! array_key_exists ($param, $conf)) - return $this->default[$param]; - return $conf[$param]; - } - - /** Define a value for the parameter in the config file. Add all the default - * values if they are not defined - * @param string $param The option name - * @param mixed $value The option value - * @return TRUE if the parameter is saved or an exception - */ - public function set ($param, $value) - { - $this->selectConfFile (); - if (!array_key_exists ($param, $this->default)) - throw new \Exception ("Unknown parameter '$param'", 500); - if (!file_exists ($this->confFile)) - { - if (@file_put_contents ($this->confFile, - "confFile)); - } - elseif (! is_readable ($this->confFile)) - throw new \Exception (sprintf ( - dgettext ("domframework", - "The configuration file '%s' is not readable"), - $this->confFile), 500); - if (!is_writeable ($this->confFile)) - throw new \Exception (sprintf (dgettext ("domframework", - "Configuration file '%s' is write protected"), - $this->confFile), 500); - $conf = array (); - $rc = include ($this->confFile); - if ($rc !== 1) - throw new \Exception (dgettext ("domframework", - "Error in configuration file"), 500); - $newconf = array_merge ($this->default, $conf, array ($param=>$value)); - $txt = "writePHP ($newconf, $txt, 4); - $txt .= ");\r\n"; - - if (@file_put_contents ($this->confFile, $txt, LOCK_EX) === FALSE) - throw new \Exception (sprintf (dgettext ("domframework", - "Can't save configuration file '%s'"), - $this->confFile), 500); - return TRUE; - } - - /** Display the $values in PHP format to be "require" easily - * @param mixed $values Values to be recorded - * @param string $phpcode Actual value of the php code - * @param integer $indent Number of spaces in the indentation of config - */ - private function writePHP ($values, $phpcode, $indent) - { - foreach ($values as $key=>$val) - { - $phpcode .= str_pad (" ", $indent); - $phpcode .= (is_numeric ($key)) ? $key : "\"$key\""; - $phpcode .= " => "; - if (is_bool ($val)) - { - if ($val === FALSE) $phpcode .= "FALSE,\r\n"; - else $phpcode .= "TRUE,\r\n"; - } - elseif (is_null ($val)) - $phpcode .= "NULL,\r\n"; - elseif (is_int ($val) || is_float ($val)) - $phpcode .= "$val,\r\n"; - elseif (is_string ($val)) - $phpcode .= "\"$val\",\r\n"; - elseif (is_array ($val)) - { - $phpcode .= "array (\r\n"; - $phpcode = $this->writePHP ($val, $phpcode, $indent+4); - $phpcode .= str_pad (" ", $indent); - $phpcode .= "),\r\n"; - } - else - throw new \Exception (dgettext ("domframework", - "Config : missing type ").gettype ($val), 500); } - return $phpcode; - } - - /** Convert a string to the right PHP type, without using the eval function - * @param string $values The string to convert - */ - private function strToType ($values) - { - $values = str_replace ("array (", "array(", $values); - if (stripos ($values, "array(") !== false) + /** List all the parameters configurable in the software + */ + public function params() { - $values = substr ($values, 6, -1); - $values = explode (",", $values); - $new = array (); - foreach ($values as $key=>$val) - { - $val = trim ($val); - if (strpos ($val, "=>") !== false) - { - // Associated array - unset ($values[$key]); - list ($key1, $val1) = explode ("=>", $val); - $key1 = trim ($key1); - $val1 = trim ($val1); - if ($val1[0] === "\"" || $val1[0] === "'") - $val1 = substr($val1, 1, -1); - elseif (strpos ($val1, ".")) - $val1 = floatval ($val1); - else - $val1 = intval ($val1); - $new[$key1] = $val1; + $this->selectConfFile(); + return $this->default; + } + + /** Return the defined values in array format + */ + public function getAll() + { + $this->selectConfFile(); + $conf = array(); + $rc = include($this->confFile); + if ($rc !== 1) { + throw new \Exception("Error in configuration file", 500); } - else - { - // Unique value (string or integer or float) - if ($val[0] === "\"" || $val[0] === "'") - $val = substr($val, 1, -1); - elseif (strpos ($val, ".")) - $val = floatval ($val); - else - $val = intval ($val); - $new[$key] = $val; - } - } - } - else - { - if ($values[0] === "\"" || $values[0] === "'" ) - $new = substr ($values, 1, -1); - elseif (strpos ($values, ".")) - $new = floatval ($values); - elseif ($values === "null") - $new = null; - elseif ($values === "false") - $new = "false"; - elseif ($values === "true") - $new = "true"; - else - $new = intval ($values); - } - return $new; - } - - /** Update the configuration file with the provided parameters - * @param array $paramsSlash The parameters to analyze for updating the file - * The params are in an array like array ("/authentication/html" => "value") - * All the parameters are not needed - * To remove a parameter, set it to default value - */ - public function updateParamsSlash ($paramsSlash) - { - $debug = 0; - if ($debug) echo "
                ";
                -    if ($debug) echo "########## BEFORE\n";
                -    if ($debug) echo "PARAMSLASH=";
                -    if ($debug) var_dump ($paramsSlash);
                -    // Check if the provided slash parameters are defined
                -    $definitions = $this->docComment ();
                -    // Actually stored values
                -    $stored = $this->getAllInSlash ();
                -    if ($debug) echo "stored =";
                -    if ($debug) var_dump ($stored);
                -    $new = array ();
                -    // Update the stored values with the provided ones
                -    foreach ($definitions as $key=>$unused)
                -    {
                -      if ($debug) echo "CHECK $key\n";
                -      if (! key_exists ($key, $paramsSlash) && key_exists ($key, $stored))
                -      {
                -        if ($debug) echo "COPY the OLD value fo '$key' to the new array\n";
                -        $new[$key] = $this->cast ($stored[$key]);
                -        continue;
                -      }
                -      if (! key_exists ($key, $paramsSlash))
                -      {
                -        if ($debug) echo "Param $key not provided : skipped\n";
                -        continue;
                -      }
                -      $val = $paramsSlash[$key];
                -      if ($val === "")
                -      {
                -        if ($debug) echo "MUST REMOVE $key => Empty val\n";
                -      }
                -      // Do NOT use the === as the $val is always a string and must be compared
                -      // with default integers
                -      elseif (key_exists ("default", $definitions[$key]) &&
                -              $this->cast ($val) ===
                -                $this->cast ($definitions[$key]["default"]))
                -      {
                -        if ($debug) echo "MUST REMOVE $key => default\n";
                -      }
                -      elseif (key_exists ($key, $paramsSlash) && key_exists ($key, $stored) &&
                -          $paramsSlash[$key] === $stored[$key])
                -      {
                -        if ($debug) echo "MUST COPY $key\n";
                -        $new[$key] = $this->cast ($val);
                -      }
                -      elseif (key_exists ($key, $stored) && $stored[$key] !== $val)
                -      {
                -        if ($debug) echo "MUST OVERWRITE $key WITH NEW VALUE\n";
                -        $new[$key] = $this->cast ($val);
                -      }
                -      elseif (! key_exists ($key, $stored))
                -      {
                -        if ($debug) echo "MUST ADD $key without DEFAULT\n";
                -        $new[$key] = $this->cast ($val);
                -      }
                -      else
                -      {
                -        if ($debug) echo "NOT CATCHED !!!\n";
                -        if ($debug) echo "   STORED=";var_dump ($stored);
                -        if ($debug) echo "   DEFS=";var_dump ($definitions[$key]);
                -        if ($debug) echo "   SLASH=";var_dump ($val);
                -      }
                +        return $conf;
                     }
                 
                -    // Save the new stored values in the file
                -    $txt = "$val)
                +    /** Return the defined values in Slash format
                +      */
                +    public function getAllInSlash()
                     {
                -      $exp = explode ("/", substr ($key, 1));
                -      $txt .= "\$conf['".implode ("']['", $exp)."'] = ".
                -        var_export ($val, true).";\n";
                +        $conf = $this->getAll();
                +        $vals = array();
                +        foreach ($this->docComment() as $key) {
                +            if (! key_exists("param", $key)) {
                +                continue;
                +            }
                +            if (substr($key["param"], 0, 1) !== "/") {
                +                throw new \Exception("Config param '" . $key["param"] .
                +                "' don't start by /");
                +            }
                +            $exp = explode("/", $key["param"]);
                +            unset($exp[0]);
                +            if (count($exp) === 1 && key_exists($exp[1], $conf)) {
                +                $vals[$key["param"]] = $conf[$exp[1]];
                +            } elseif (
                +                count($exp) === 2 && key_exists($exp[1], $conf) &&
                +                key_exists($exp[2], $conf[$exp[1]])
                +            ) {
                +                $vals[$key["param"]] = $conf[$exp[1]][$exp[2]];
                +            } elseif (
                +                count($exp) === 3 && key_exists($exp[1], $conf) &&
                +                key_exists($exp[2], $conf[$exp[1]]) &&
                +                key_exists($exp[3], $conf[$exp[1]][$exp[2]])
                +            ) {
                +                $vals[$key["param"]] = $conf[$exp[1]][$exp[2]][$exp[3]];
                +            }
                +        }
                +        return $vals;
                     }
                -    if (file_put_contents ($this->confFile, $txt, LOCK_EX) === FALSE)
                -      throw new \Exception (sprintf (dgettext ("domframework",
                -                                    "Can't save configuration file '%s'"),
                -                                    $this->confFile), 500);
                -    // The next command clear the include cache file and force the PHP to
                -    // read it again on next request.
                -    // If it is not used, include () return the old value
                -    opcache_invalidate ($this->confFile);
                -    return TRUE;
                -  }
                 
                -  /** Cast the provided string into the associated value
                -    * @param string $val The val to cast
                -    */
                -  private function cast ($val)
                -  {
                -    if (isset ($val[0]) && ($val[0] === "\"" || $val[0] === "'" ))
                -      $new = substr ($val, 1, -1);
                -    elseif ($val === "null")
                -      $new = null;
                -    elseif ($val === "false")
                -      $new = false;
                -    elseif ($val === "true")
                -      $new = true;
                -    elseif ($val === "")
                -      $new = "";
                -    elseif (is_array ($val))
                -      $new = $val;
                -    elseif (strspn ($val, "0123456789") === strlen ($val))
                -      $new = intval ($val);
                -    elseif (strspn ($val, "0123456789.") === strlen ($val))
                -      $new = floatval ($val);
                -    else
                -      $new = $val;
                -    return $new;
                -  }
                -
                -  /** Return an array containing the definitions read from the default config
                -    * file
                -    * The definition of param are in Slash format
                -    */
                -  public function docComment ()
                -  {
                -    $debug = 0;
                -    $reflector = new \ReflectionClass (get_class ($this));
                -    $modelFile = $reflector->getFileName();
                -    if (! file_exists ($modelFile))
                -      throw new \Exception (dgettext ("domframework",
                -                           "The configuration model file is missing"), 500);
                -    if (! is_readable ($modelFile))
                -      throw new \Exception (dgettext ("domframework",
                -                           "The configuration model file is not readable"),
                -                           500);
                -    $filecontent = file_get_contents ($modelFile);
                -    $tokens = token_get_all ($filecontent);
                -    $foundDefault = "";
                -    $parenthesis = 0;
                -    $params = array ();
                -    $path = "";
                -    $group = dgettext ("domframework", "Default parameters");
                -    foreach ($tokens as $token)
                +    /** Get the value of the provided parameter recorded in .php file
                +      * If it is not set in .php file, use the default value
                +      * @param string $param The option name to be returned
                +      */
                +    public function get($param)
                     {
                -      if (is_array ($token))
                -      {
                -        list ($id, $text) = $token;
                -        if ($debug) echo "ARRAY : $id (".token_name ($id)."), $text\n";
                -        if ($foundDefault === "" && $text === "->")
                -          $foundDefault = $text;
                -        if ($id === T_DOC_COMMENT)
                -        {
                -          // Look at @param, @description, @type, @values, @default
                -          if ($debug) echo "DOC_COMMENT : $text\n";
                -          // Append the not completed lines
                -          $text = trim (substr ($text, 3, -2));
                -          $text = preg_replace ("/\n\s+\*?\s*/", " ", $text);
                -          $text = preg_replace (
                -                    "/(@(param|description|type|values|default|group|prefix))/",
                -                    "\n\${1}", $text);
                -          $text = ltrim ($text);
                -          // Look at each parameter and save them in a data array
                -          $data = array ();
                -          foreach (explode ("\n", $text) as $line)
                -          {
                -            $tmp = explode (" ", $line);
                -            $key = reset ($tmp);
                -            $key = substr ($key, 1);
                -            $data[$key] = trim (implode (" ", array_slice ($tmp, 1)));
                -          }
                -          if (isset ($data["group"]))
                -            $group = $data["group"];
                -          if (! isset ($data["param"]))
                -            continue;
                -          if (substr ($data["param"], 0, 1) !== "/")
                -            throw new \Exception (sprintf (dgettext ("domframework",
                -              "Parameter '%s' doesn't start by slash"), $data["param"]), 500);
                -          $data["depth"] = $parenthesis;
                -          $data["group"] = $group;
                -          //if (isset ($data["values"]) && $data["values"][0] !== "\"")
                -          if (isset ($data["values"]))
                -          {
                -            // A function or an array or a number is provided
                -            if ( function_exists ($data["values"]))
                -              $data["values"] = call_user_func ($data["values"]);
                -            elseif (is_string ($data["values"]))
                -              $data["values"] = $this->strToType ($data["values"]);
                -          }
                -          if (isset ($data["default"]))
                -            $data["default"] = $this->strToType ($data["default"]);
                -          if ($debug) var_dump ($data);
                -          $params[$data["param"]] = $data;
                +        $this->selectConfFile();
                +        if (!array_key_exists($param, $this->default)) {
                +            throw new \Exception("Unknown configuration parameter '$param'", 500);
                         }
                -      }
                -      else
                -      {
                -        if ($debug) echo "TEXT  : $token\n";
                -        if ($foundDefault !== "" && $token === "(")
                -        {
                -          $parenthesis++;
                +        if (!file_exists($this->confFile)) {
                +            if (
                +                @file_put_contents(
                +                    $this->confFile,
                +                    "confFile
                +                ), 500);
                +            }
                +        } elseif (! is_readable($this->confFile)) {
                +            throw new \Exception(sprintf(
                +                dgettext(
                +                    "domframework",
                +                    "The configuration file '%s' is not readable"
                +                ),
                +                $this->confFile
                +            ));
                         }
                -        if ($foundDefault !== "" && $token === ")")
                -        {
                -          $parenthesis--;
                -          if ($parenthesis === 0)
                -            break;
                +        $conf = array();
                +        $rc = include($this->confFile);
                +        if ($rc !== 1) {
                +            throw new \Exception("Error in configuration file", 500);
                         }
                -      }
                +        if (! array_key_exists($param, $this->default)) {
                +            throw new \Exception(sprintf(
                +                "Configuration parameter '%s' not defined",
                +                $param
                +            ), 500);
                +        }
                +        // Create a conf where all the keys are defined. If the keys are already
                +        // define, use them, or use the default ones
                +        // Don't allow keys not defined in default ones
                +        if (! is_array($this->default[$param])) {
                +            if (! array_key_exists($param, $conf)) {
                +                return $this->default[$param];
                +            }
                +            return $conf[$param];
                +        }
                +        foreach ($this->default[$param] as $key => $val) {
                +            if ($key === "not configured") {
                +                if (! array_key_exists($param, $conf)) {
                +                    continue;
                +                }
                +                foreach ($conf[$param] as $k => $v) {
                +                    $conf[$param][$k] = array_replace_recursive(
                +                        $val,
                +                        $conf[$param][$k]
                +                    );
                +                }
                +                continue;
                +            }
                +            if (! isset($conf[$param][$key])) {
                +                $conf[$param][$key] = $val;
                +            } elseif (is_array($val)) {
                +                $conf[$param][$key] = array_replace_recursive(
                +                    $val,
                +                    $conf[$param][$key]
                +                );
                +            }
                +        }
                +        if (! array_key_exists($param, $conf)) {
                +            return $this->default[$param];
                +        }
                +        return $conf[$param];
                +    }
                +
                +    /** Define a value for the parameter in the config file. Add all the default
                +      * values if they are not defined
                +      * @param string $param The option name
                +      * @param mixed $value The option value
                +      * @return TRUE if the parameter is saved or an exception
                +      */
                +    public function set($param, $value)
                +    {
                +        $this->selectConfFile();
                +        if (!array_key_exists($param, $this->default)) {
                +            throw new \Exception("Unknown parameter '$param'", 500);
                +        }
                +        if (!file_exists($this->confFile)) {
                +            if (
                +                @file_put_contents(
                +                    $this->confFile,
                +                    "confFile
                +                ));
                +            }
                +        } elseif (! is_readable($this->confFile)) {
                +            throw new \Exception(sprintf(
                +                dgettext(
                +                    "domframework",
                +                    "The configuration file '%s' is not readable"
                +                ),
                +                $this->confFile
                +            ), 500);
                +        }
                +        if (!is_writeable($this->confFile)) {
                +            throw new \Exception(sprintf(
                +                dgettext(
                +                    "domframework",
                +                    "Configuration file '%s' is write protected"
                +                ),
                +                $this->confFile
                +            ), 500);
                +        }
                +        $conf = array();
                +        $rc = include($this->confFile);
                +        if ($rc !== 1) {
                +            throw new \Exception(dgettext(
                +                "domframework",
                +                "Error in configuration file"
                +            ), 500);
                +        }
                +        $newconf = array_merge($this->default, $conf, array($param => $value));
                +        $txt = "writePHP($newconf, $txt, 4);
                +        $txt .= ");\r\n";
                +
                +        if (@file_put_contents($this->confFile, $txt, LOCK_EX) === false) {
                +            throw new \Exception(sprintf(
                +                dgettext(
                +                    "domframework",
                +                    "Can't save configuration file '%s'"
                +                ),
                +                $this->confFile
                +            ), 500);
                +        }
                +        return true;
                +    }
                +
                +    /** Display the $values in PHP format to be "require" easily
                +      * @param mixed $values Values to be recorded
                +      * @param string $phpcode Actual value of the php code
                +      * @param integer $indent Number of spaces in the indentation of config
                +      */
                +    private function writePHP($values, $phpcode, $indent)
                +    {
                +        foreach ($values as $key => $val) {
                +            $phpcode .= str_pad(" ", $indent);
                +            $phpcode .= (is_numeric($key)) ? $key : "\"$key\"";
                +            $phpcode .= " => ";
                +            if (is_bool($val)) {
                +                if ($val === false) {
                +                    $phpcode .= "FALSE,\r\n";
                +                } else {
                +                    $phpcode .= "TRUE,\r\n";
                +                }
                +            } elseif (is_null($val)) {
                +                $phpcode .= "NULL,\r\n";
                +            } elseif (is_int($val) || is_float($val)) {
                +                $phpcode .= "$val,\r\n";
                +            } elseif (is_string($val)) {
                +                $phpcode .= "\"$val\",\r\n";
                +            } elseif (is_array($val)) {
                +                $phpcode .= "array (\r\n";
                +                $phpcode = $this->writePHP($val, $phpcode, $indent + 4);
                +                $phpcode .= str_pad(" ", $indent);
                +                $phpcode .= "),\r\n";
                +            } else {
                +                throw new \Exception(dgettext(
                +                    "domframework",
                +                    "Config : missing type "
                +                ) . gettype($val), 500);
                +            }
                +        }
                +
                +        return $phpcode;
                +    }
                +
                +    /** Convert a string to the right PHP type, without using the eval function
                +      * @param string $values The string to convert
                +      */
                +    private function strToType($values)
                +    {
                +        $values = str_replace("array (", "array(", $values);
                +        if (stripos($values, "array(") !== false) {
                +            $values = substr($values, 6, -1);
                +            $values = explode(",", $values);
                +            $new = array();
                +            foreach ($values as $key => $val) {
                +                $val = trim($val);
                +                if (strpos($val, "=>") !== false) {
                +                    // Associated array
                +                    unset($values[$key]);
                +                    list($key1, $val1) = explode("=>", $val);
                +                    $key1 = trim($key1);
                +                    $val1 = trim($val1);
                +                    if ($val1[0] === "\"" || $val1[0] === "'") {
                +                        $val1 = substr($val1, 1, -1);
                +                    } elseif (strpos($val1, ".")) {
                +                        $val1 = floatval($val1);
                +                    } else {
                +                        $val1 = intval($val1);
                +                    }
                +                    $new[$key1] = $val1;
                +                } else {
                +                    // Unique value (string or integer or float)
                +                    if ($val[0] === "\"" || $val[0] === "'") {
                +                        $val = substr($val, 1, -1);
                +                    } elseif (strpos($val, ".")) {
                +                        $val = floatval($val);
                +                    } else {
                +                        $val = intval($val);
                +                    }
                +                    $new[$key] = $val;
                +                }
                +            }
                +        } else {
                +            if ($values[0] === "\"" || $values[0] === "'") {
                +                $new = substr($values, 1, -1);
                +            } elseif (strpos($values, ".")) {
                +                $new = floatval($values);
                +            } elseif ($values === "null") {
                +                $new = null;
                +            } elseif ($values === "false") {
                +                $new = "false";
                +            } elseif ($values === "true") {
                +                $new = "true";
                +            } else {
                +                $new = intval($values);
                +            }
                +        }
                +        return $new;
                +    }
                +
                +    /** Update the configuration file with the provided parameters
                +      * @param array $paramsSlash The parameters to analyze for updating the file
                +      * The params are in an array like array ("/authentication/html" => "value")
                +      * All the parameters are not needed
                +      * To remove a parameter, set it to default value
                +      */
                +    public function updateParamsSlash($paramsSlash)
                +    {
                +        $debug = 0;
                +        if ($debug) {
                +            echo "
                ";
                +        }
                +        if ($debug) {
                +            echo "########## BEFORE\n";
                +        }
                +        if ($debug) {
                +            echo "PARAMSLASH=";
                +        }
                +        if ($debug) {
                +            var_dump($paramsSlash);
                +        }
                +        // Check if the provided slash parameters are defined
                +        $definitions = $this->docComment();
                +        // Actually stored values
                +        $stored = $this->getAllInSlash();
                +        if ($debug) {
                +            echo "stored =";
                +        }
                +        if ($debug) {
                +            var_dump($stored);
                +        }
                +        $new = array();
                +        // Update the stored values with the provided ones
                +        foreach ($definitions as $key => $unused) {
                +            if ($debug) {
                +                echo "CHECK $key\n";
                +            }
                +            if (! key_exists($key, $paramsSlash) && key_exists($key, $stored)) {
                +                if ($debug) {
                +                    echo "COPY the OLD value fo '$key' to the new array\n";
                +                }
                +                $new[$key] = $this->cast($stored[$key]);
                +                continue;
                +            }
                +            if (! key_exists($key, $paramsSlash)) {
                +                if ($debug) {
                +                    echo "Param $key not provided : skipped\n";
                +                }
                +                continue;
                +            }
                +            $val = $paramsSlash[$key];
                +            if ($val === "") {
                +                if ($debug) {
                +                    echo "MUST REMOVE $key => Empty val\n";
                +                }
                +            } elseif (
                +                // Do NOT use the === as the $val is always a string and must be compared
                +                // with default integers
                +                key_exists("default", $definitions[$key]) &&
                +                $this->cast($val) ===
                +                $this->cast($definitions[$key]["default"])
                +            ) {
                +                if ($debug) {
                +                    echo "MUST REMOVE $key => default\n";
                +                }
                +            } elseif (
                +                key_exists($key, $paramsSlash) && key_exists($key, $stored) &&
                +                $paramsSlash[$key] === $stored[$key]
                +            ) {
                +                if ($debug) {
                +                    echo "MUST COPY $key\n";
                +                }
                +                $new[$key] = $this->cast($val);
                +            } elseif (key_exists($key, $stored) && $stored[$key] !== $val) {
                +                if ($debug) {
                +                    echo "MUST OVERWRITE $key WITH NEW VALUE\n";
                +                }
                +                $new[$key] = $this->cast($val);
                +            } elseif (! key_exists($key, $stored)) {
                +                if ($debug) {
                +                    echo "MUST ADD $key without DEFAULT\n";
                +                }
                +                $new[$key] = $this->cast($val);
                +            } else {
                +                if ($debug) {
                +                    echo "NOT CATCHED !!!\n";
                +                }
                +                if ($debug) {
                +                    echo "   STORED=";
                +                }
                +                var_dump($stored);
                +                if ($debug) {
                +                    echo "   DEFS=";
                +                }
                +                var_dump($definitions[$key]);
                +                if ($debug) {
                +                    echo "   SLASH=";
                +                }
                +                var_dump($val);
                +            }
                +        }
                +
                +        // Save the new stored values in the file
                +        $txt = " $val) {
                +            $exp = explode("/", substr($key, 1));
                +            $txt .= "\$conf['" . implode("']['", $exp) . "'] = " .
                +            var_export($val, true) . ";\n";
                +        }
                +        if (file_put_contents($this->confFile, $txt, LOCK_EX) === false) {
                +            throw new \Exception(sprintf(
                +                dgettext(
                +                    "domframework",
                +                    "Can't save configuration file '%s'"
                +                ),
                +                $this->confFile
                +            ), 500);
                +        }
                +        // The next command clear the include cache file and force the PHP to
                +        // read it again on next request.
                +        // If it is not used, include () return the old value
                +        opcache_invalidate($this->confFile);
                +        return true;
                +    }
                +
                +    /** Cast the provided string into the associated value
                +      * @param string $val The val to cast
                +      */
                +    private function cast($val)
                +    {
                +        if (isset($val[0]) && ($val[0] === "\"" || $val[0] === "'")) {
                +            $new = substr($val, 1, -1);
                +        } elseif ($val === "null") {
                +            $new = null;
                +        } elseif ($val === "false") {
                +            $new = false;
                +        } elseif ($val === "true") {
                +            $new = true;
                +        } elseif ($val === "") {
                +            $new = "";
                +        } elseif (is_array($val)) {
                +            $new = $val;
                +        } elseif (strspn($val, "0123456789") === strlen($val)) {
                +            $new = intval($val);
                +        } elseif (strspn($val, "0123456789.") === strlen($val)) {
                +            $new = floatval($val);
                +        } else {
                +            $new = $val;
                +        }
                +        return $new;
                +    }
                +
                +    /** Return an array containing the definitions read from the default config
                +      * file
                +      * The definition of param are in Slash format
                +      */
                +    public function docComment()
                +    {
                +        $debug = 0;
                +        $reflector = new \ReflectionClass(get_class($this));
                +        $modelFile = $reflector->getFileName();
                +        if (! file_exists($modelFile)) {
                +            throw new \Exception(dgettext(
                +                "domframework",
                +                "The configuration model file is missing"
                +            ), 500);
                +        }
                +        if (! is_readable($modelFile)) {
                +            throw new \Exception(
                +                dgettext(
                +                    "domframework",
                +                    "The configuration model file is not readable"
                +                ),
                +                500
                +            );
                +        }
                +        $filecontent = file_get_contents($modelFile);
                +        $tokens = token_get_all($filecontent);
                +        $foundDefault = "";
                +        $parenthesis = 0;
                +        $params = array();
                +        $path = "";
                +        $group = dgettext("domframework", "Default parameters");
                +        foreach ($tokens as $token) {
                +            if (is_array($token)) {
                +                list($id, $text) = $token;
                +                if ($debug) {
                +                    echo "ARRAY : $id (" . token_name($id) . "), $text\n";
                +                }
                +                if ($foundDefault === "" && $text === "->") {
                +                    $foundDefault = $text;
                +                }
                +                if ($id === T_DOC_COMMENT) {
                +                    // Look at @param, @description, @type, @values, @default
                +                    if ($debug) {
                +                        echo "DOC_COMMENT : $text\n";
                +                    }
                +                    // Append the not completed lines
                +                    $text = trim(substr($text, 3, -2));
                +                    $text = preg_replace("/\n\s+\*?\s*/", " ", $text);
                +                    $text = preg_replace(
                +                        "/(@(param|description|type|values|default|group|prefix))/",
                +                        "\n\${1}",
                +                        $text
                +                    );
                +                    $text = ltrim($text);
                +                    // Look at each parameter and save them in a data array
                +                    $data = array();
                +                    foreach (explode("\n", $text) as $line) {
                +                        $tmp = explode(" ", $line);
                +                        $key = reset($tmp);
                +                        $key = substr($key, 1);
                +                        $data[$key] = trim(implode(" ", array_slice($tmp, 1)));
                +                    }
                +                    if (isset($data["group"])) {
                +                        $group = $data["group"];
                +                    }
                +                    if (! isset($data["param"])) {
                +                        continue;
                +                    }
                +                    if (substr($data["param"], 0, 1) !== "/") {
                +                        throw new \Exception(sprintf(dgettext(
                +                            "domframework",
                +                            "Parameter '%s' doesn't start by slash"
                +                        ), $data["param"]), 500);
                +                    }
                +                    $data["depth"] = $parenthesis;
                +                    $data["group"] = $group;
                +                    //if (isset ($data["values"]) && $data["values"][0] !== "\"")
                +                    if (isset($data["values"])) {
                +                        // A function or an array or a number is provided
                +                        if (function_exists($data["values"])) {
                +                            $data["values"] = call_user_func($data["values"]);
                +                        } elseif (is_string($data["values"])) {
                +                            $data["values"] = $this->strToType($data["values"]);
                +                        }
                +                    }
                +                    if (isset($data["default"])) {
                +                        $data["default"] = $this->strToType($data["default"]);
                +                    }
                +                    if ($debug) {
                +                        var_dump($data);
                +                    }
                +                    $params[$data["param"]] = $data;
                +                }
                +            } else {
                +                if ($debug) {
                +                    echo "TEXT  : $token\n";
                +                }
                +                if ($foundDefault !== "" && $token === "(") {
                +                    $parenthesis++;
                +                }
                +                if ($foundDefault !== "" && $token === ")") {
                +                    $parenthesis--;
                +                    if ($parenthesis === 0) {
                +                        break;
                +                    }
                +                }
                +            }
                +        }
                +        return $params;
                     }
                -    return $params;
                -  }
                 }
                diff --git a/src/Console.php b/src/Console.php
                index 19120cb..3561d62 100644
                --- a/src/Console.php
                +++ b/src/Console.php
                @@ -1,4 +1,5 @@
                 
                @@ -25,965 +26,937 @@ namespace Domframework;
                   */
                 class Console
                 {
                -  // PROPERTIES
                -  /** Set the debug on if a filename is provided, or do not debug if false is
                -    * provided
                -    */
                -  //private $debug = "/tmp/debug";
                -  private $debug = false;
                +    // PROPERTIES
                +    /** Set the debug on if a filename is provided, or do not debug if false is
                +      * provided
                +      */
                +    //private $debug = "/tmp/debug";
                +    private $debug = false;
                 
                -  /** Save the initial stty value
                -    */
                -  private $initSttyState;
                +    /** Save the initial stty value
                +      */
                +    private $initSttyState;
                 
                -  /** Line Content
                -    */
                -  private $lineContent = "";
                +    /** Line Content
                +      */
                +    private $lineContent = "";
                 
                -  /** If true, display each char the user has pressed (echo mode)
                -    */
                -  private $echoMode = true;
                +    /** If true, display each char the user has pressed (echo mode)
                +      */
                +    private $echoMode = true;
                 
                -  /** List of non printable chars in decimal. The non printable chars are not
                -    * displayed but are correctely captured
                -    */
                -  private $nonWriteableChar = array (1, 2, 3, 4, 6, 8, 9, 16, 18,
                +    /** List of non printable chars in decimal. The non printable chars are not
                +      * displayed but are correctely captured
                +      */
                +    private $nonWriteableChar = array(1, 2, 3, 4, 6, 8, 9, 16, 18,
                                                      20, 21, 22, 23, 24, 25, 27,
                                                      127);
                 
                -  /** The history list in an array
                -    */
                -  private $history = array ();
                +    /** The history list in an array
                +      */
                +    private $history = array();
                 
                -  /** The history max size in entries
                -    */
                -  private $historyMaxSize = 1000;
                +    /** The history max size in entries
                +      */
                +    private $historyMaxSize = 1000;
                 
                -  /** Set the completion keys. Not set by default
                -    */
                -  private $completionKeys = false;
                +    /** Set the completion keys. Not set by default
                +      */
                +    private $completionKeys = false;
                 
                -  /** Set the function called when the completion char is called
                -    */
                -  private $completionFunction = array ();
                +    /** Set the function called when the completion char is called
                +      */
                +    private $completionFunction = array();
                 
                -  /** Set the width of the terminal in chars
                -    */
                -  private $termWidth;
                +    /** Set the width of the terminal in chars
                +      */
                +    private $termWidth;
                 
                -  /** Set the height of the terminal in chars
                -    */
                -  private $termHeight;
                +    /** Set the height of the terminal in chars
                +      */
                +    private $termHeight;
                 
                -  /** Store the last cursor position in the last readline
                -    */
                -  private $cursorPos = 1;
                +    /** Store the last cursor position in the last readline
                +      */
                +    private $cursorPos = 1;
                 
                -  /** The constructor init the console.
                -    * Check if we have the rights to execute, if wa have in cli...
                -    */
                -  public function __construct ()
                -  {
                -    if (! function_exists ("exec"))
                -      throw $this->ConsoleException ("No exec support in PHP");
                -    $this->initSttyState = exec ("stty -g 2>/dev/null");
                -    // Set the terminal to return the value each time a key is pressed.
                -    // Do not display anything, so we don't see the characters when the user is
                -    // deleting.
                -    // 'intr ^J' allow to redefine the interruption from Ctrl+C to Ctrl+J. It
                -    // allow to manage the Ctrl+C key to clean the entry
                -    exec ("stty -echo -icanon min 1 time 0 2>/dev/null");
                -    $this->updateTerminalSize ();
                -  }
                -
                -  /** Update the terminal size
                -    */
                -  public function updateTerminalSize ()
                -  {
                -    $this->termWidth = 80;
                -    $this->termHeight = 25;
                -    $termSize = exec ("stty size 2>/dev/null", $null, $rc);
                -    if ($rc === 0)
                +    /** The constructor init the console.
                +      * Check if we have the rights to execute, if wa have in cli...
                +      */
                +    public function __construct()
                +    {
                +        if (! function_exists("exec")) {
                +            throw $this->ConsoleException("No exec support in PHP");
                +        }
                +        $this->initSttyState = exec("stty -g 2>/dev/null");
                +        // Set the terminal to return the value each time a key is pressed.
                +        // Do not display anything, so we don't see the characters when the user is
                +        // deleting.
                +        // 'intr ^J' allow to redefine the interruption from Ctrl+C to Ctrl+J. It
                +        // allow to manage the Ctrl+C key to clean the entry
                +        exec("stty -echo -icanon min 1 time 0 2>/dev/null");
                +        $this->updateTerminalSize();
                +    }
                +
                +    /** Update the terminal size
                +      */
                +    public function updateTerminalSize()
                     {
                -      list ($termHeight, $termWidth) = explode (" ", $termSize);
                -      if (is_null ($termWidth) || is_bool ($termWidth))
                         $this->termWidth = 80;
                -      else
                -        $this->termWidth = intval ($termWidth);
                -      if (is_null ($termHeight) || is_bool ($termHeight))
                         $this->termHeight = 25;
                -      else
                -        $this->termHeight = intval ($termHeight);
                -    }
                -  }
                -
                -  /** The destructor return the terminal to initial state
                -    */
                -  public function __destruct ()
                -  {
                -    if ($this->initSttyState !== "")
                -      exec ("stty $this->initSttyState");
                -    $this->colorReset ();
                -    $this->textUnderline (false);
                -    $this->textBold (false);
                -  }
                -
                -  /** Each time a key is pressed by the user, display the value on screen (echo)
                -    */
                -  public function setEcho ()
                -  {
                -    $this->echoMode = true;
                -  }
                -
                -  /** Each time a key is pressed by the user, DO NOT display the value on screen
                -    * (echo disabled)
                -    */
                -  public function unsetEcho ()
                -  {
                -    $this->echoMode = false;
                -  }
                -
                -  /** Display a text on screen. Must be used before "readline" method because
                -    * the provided message will not be deleted by readline process.
                -    * @param string $message The message to display
                -    */
                -  public function echo ($message)
                -  {
                -    echo $message;
                -    $this->lineContent .= $message;
                -  }
                -
                -  /** Wait one valid character from the user.
                -    * The non printable chars are not displayed, nor returned
                -    * The ESC Sequences are skipped
                -    * @return the pressed char
                -    */
                -  public function getc ()
                -  {
                -    $char = $this->getKey ();
                -    while (in_array (ord ($char), $this->nonWriteableChar))
                -      $char = $this->getKey ();
                -    return $char;
                -  }
                -
                -  /** Wait one key pressed by the user. If the key pressed is an ESC sequence,
                -    * return this sequence
                -    * The non printable chars are not displayed, but are correctely returned
                -    * The UTF8 chars are return as multiple length chars
                -    * @return the pressed char
                -    */
                -  public function getKey ()
                -  {
                -    $char = fgetc (STDIN);
                -    if ($char === chr (27))
                -    {
                -      $sequence = $char;
                -      $char2 = fgetc (STDIN);
                -      if (ord ($char2) === 27)
                -      {
                -        // Sequence of ESC ESC
                -      }
                -      elseif (ord ($char2) === 79)
                -      {
                -        // Start an ESC SS3 sequence
                -        // Like F2 Key
                -        $sequence .= $char2;
                -        $char = fgetc (STDIN);
                -        $sequence .= $char;
                -      }
                -      elseif (ord ($char2) === 91 || ord($char2) === 93)
                -      {
                -        // Start an ESC CSI sequence. Do not display it, just return it.
                -        // The ESC squences are used to communicate the cursor keys, associated
                -        // with the Ctrl key, by example
                -        // ESC [ is followed by any number (including none) of "parameter bytes"
                -        // in the range 0x30–0x3F (ASCII 0–9:;<=>?), then by any number of
                -        // "intermediate bytes" in the range 0x20–0x2F (ASCII space and
                -        // !"#$%&'()*+,-./), then finally by a single "final byte" in the range
                -        // 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).[14]:5.4
                -        $sequence .= $char2;
                -        $char = fgetc (STDIN);
                -        while (ord ($char) < 64 || ord ($char) > 126)
                -        {
                -          $sequence .= $char;
                -          $char = fgetc (STDIN);
                +        $termSize = exec("stty size 2>/dev/null", $null, $rc);
                +        if ($rc === 0) {
                +            list($termHeight, $termWidth) = explode(" ", $termSize);
                +            if (is_null($termWidth) || is_bool($termWidth)) {
                +                $this->termWidth = 80;
                +            } else {
                +                $this->termWidth = intval($termWidth);
                +            }
                +            if (is_null($termHeight) || is_bool($termHeight)) {
                +                $this->termHeight = 25;
                +            } else {
                +                $this->termHeight = intval($termHeight);
                +            }
                         }
                -        $sequence .= $char;
                -      }
                -      else
                -      {
                -        $this->consoleException ("Invalid ESC seq : ".ord($char2));
                -      }
                -      return $sequence;
                     }
                 
                -    // UTF Sequence :
                -    // - char1 < 128 : One char (like ascii)
                -    // - char1 >= 194 && char1 <= 223 : Two chars
                -    // - char1 >= 224 && char1 <= 239 : Three chars
                -    // - char1 >= 240 && char1 <= 244 : Four chars
                -    if (ord ($char) < 128)
                +    /** The destructor return the terminal to initial state
                +      */
                +    public function __destruct()
                     {
                -      // One Char like ascii
                +        if ($this->initSttyState !== "") {
                +            exec("stty $this->initSttyState");
                +        }
                +        $this->colorReset();
                +        $this->textUnderline(false);
                +        $this->textBold(false);
                     }
                -    elseif (ord ($char) >= 194 && ord ($char) <= 223)
                -    {
                -      // Two chars
                -      $char .= fgetc (STDIN);
                -    }
                -    elseif (ord ($char) >= 224 && ord ($char) <= 239)
                -    {
                -      // Three chars
                -      $char .= fgetc (STDIN).fgetc (STDIN);
                -    }
                -    elseif (ord ($char) >= 240 && ord ($char) <= 244)
                -    {
                -      // Four chars
                -      $char .= fgetc (STDIN).fgetc (STDIN).fgetc (STDIN);
                -    }
                -    if ($this->echoMode && ! in_array (ord ($char), $this->nonWriteableChar))
                -      echo $char;
                -    return $char;
                -  }
                 
                -  /** Get the line of characters pressed by the user and return the result.
                -    * Stop when the user valid by \n.
                -    * Manage correctely the backspace, the Ctrl+W to remove word...
                -    * @param string $propo Preset the text for the user
                -    * @param boolean|string $stopperChar The chars to stop the analysis and
                -    * return the result
                -    * @return string The typed string
                -    */
                -  public function readline ($propo = "", $stopperChar = false)
                -  {
                -    // Gets can not delete chars before the call. Keep the prompt (if exists)
                -    if (! is_string ($propo))
                -      $this->consoleException ("Invalid proposition provided to readline");
                -    $prompt = $this->lineContent;
                -    $minLength = mb_strlen ($this->lineContent) + 1;
                -    // Manage the history and a temporary buffer if the user has already type
                -    // something before calling the history
                -    $historyPos = count ($this->history);
                -    $string = $propo;
                -    echo $string;
                -    $this->lineContent = $prompt.$string;
                -    // The cursor position from last char of line.
                -    $cursorPos = mb_strlen ($this->lineContent) + 1;
                -    while (1)
                +    /** Each time a key is pressed by the user, display the value on screen (echo)
                +      */
                +    public function setEcho()
                     {
                -      $char = $this->getKey ();
                -      if ($stopperChar === false && $char === "\n")
                -      {
                -        // End of process without stopperChars
                -        $this->lineContent = "";
                -        break;
                -      }
                -      if ($stopperChar !== false &&
                -          in_array ($char, $this->mb_str_split ($stopperChar)))
                -      {
                -        // End of process with stopperChars
                -        $this->lineContent = "";
                -        break;
                -      }
                -      if ($this->completionKeys !== false &&
                -          in_array ($char, $this->mb_str_split ($this->completionKeys)))
                -      // Manage autocompletion
                -      {
                -        $this->debug ("Autocompletion starting");
                -        // Take the last part of the string without space or double quotes
                -        $pos = strrpos ($string, " ");
                -        if ($pos === false)
                -        {
                -          // No space : put all in end
                -          $start = "";
                -          $end = $string;
                -        }
                -        elseif ($pos === mb_strlen ($string))
                -        {
                -          // Last char is a space : put all in start
                -          $start = $string;
                -          $end = "";
                -        }
                -        else
                -        {
                -          // Last char is not a space, end is the last word and start is the
                -          // begin to before last word
                -          $start = mb_substr ($string, 0, $pos + 1);
                -          $end = mb_substr ($string, $pos + 1);
                +        $this->echoMode = true;
                +    }
                 
                +    /** Each time a key is pressed by the user, DO NOT display the value on screen
                +      * (echo disabled)
                +      */
                +    public function unsetEcho()
                +    {
                +        $this->echoMode = false;
                +    }
                +
                +    /** Display a text on screen. Must be used before "readline" method because
                +      * the provided message will not be deleted by readline process.
                +      * @param string $message The message to display
                +      */
                +    public function echo($message)
                +    {
                +        echo $message;
                +        $this->lineContent .= $message;
                +    }
                +
                +    /** Wait one valid character from the user.
                +      * The non printable chars are not displayed, nor returned
                +      * The ESC Sequences are skipped
                +      * @return the pressed char
                +      */
                +    public function getc()
                +    {
                +        $char = $this->getKey();
                +        while (in_array(ord($char), $this->nonWriteableChar)) {
                +            $char = $this->getKey();
                         }
                -        $this->debug ("Autocompletion : start='$start', end='$end'");
                -        $completeArr = call_user_func ($this->completionFunction,
                -          self::tokenize ($start));
                -        if (! is_array ($completeArr))
                -          throw new \Exception ("Autocompletion : return is not an array");
                -        $isAssoc = is_array ($completeArr) &&
                -          array_diff_key ($completeArr, array_keys (array_keys ($completeArr)));
                -        // Remove from completeArr the proposed values which doesn't match with
                -        // $end (invalid proposals)
                -        foreach ($completeArr as $key => $val)
                -        {
                -          if ($isAssoc)
                -            $val = $key;
                -          if (mb_substr ($val, 0, mb_strlen ($end)) !== $end)
                -            unset ($completeArr[$key]);
                +        return $char;
                +    }
                +
                +    /** Wait one key pressed by the user. If the key pressed is an ESC sequence,
                +      * return this sequence
                +      * The non printable chars are not displayed, but are correctely returned
                +      * The UTF8 chars are return as multiple length chars
                +      * @return the pressed char
                +      */
                +    public function getKey()
                +    {
                +        $char = fgetc(STDIN);
                +        if ($char === chr(27)) {
                +            $sequence = $char;
                +            $char2 = fgetc(STDIN);
                +            if (ord($char2) === 27) {
                +                // Sequence of ESC ESC
                +            } elseif (ord($char2) === 79) {
                +                // Start an ESC SS3 sequence
                +                // Like F2 Key
                +                $sequence .= $char2;
                +                $char = fgetc(STDIN);
                +                $sequence .= $char;
                +            } elseif (ord($char2) === 91 || ord($char2) === 93) {
                +                // Start an ESC CSI sequence. Do not display it, just return it.
                +                // The ESC squences are used to communicate the cursor keys, associated
                +                // with the Ctrl key, by example
                +                // ESC [ is followed by any number (including none) of "parameter bytes"
                +                // in the range 0x30–0x3F (ASCII 0–9:;<=>?), then by any number of
                +                // "intermediate bytes" in the range 0x20–0x2F (ASCII space and
                +                // !"#$%&'()*+,-./), then finally by a single "final byte" in the range
                +                // 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).[14]:5.4
                +                $sequence .= $char2;
                +                $char = fgetc(STDIN);
                +                while (ord($char) < 64 || ord($char) > 126) {
                +                    $sequence .= $char;
                +                    $char = fgetc(STDIN);
                +                }
                +                $sequence .= $char;
                +            } else {
                +                $this->consoleException("Invalid ESC seq : " . ord($char2));
                +            }
                +            return $sequence;
                         }
                -        if (count ($completeArr) === 1 &&
                -             ($isAssoc && key ($completeArr) !== "" ||
                -             ! $isAssoc && reset ($completeArr) !== ""))
                -        {
                -          // One entry : add a space to put on the next
                -          $this->debug ("Autocompletion : One entry not empty : ".
                -            "add it + ending space");
                -          if ($isAssoc)
                -            $string = $start.key ($completeArr)." ";
                -          else
                -            $string = $start.reset ($completeArr)." ";
                +
                +        // UTF Sequence :
                +        // - char1 < 128 : One char (like ascii)
                +        // - char1 >= 194 && char1 <= 223 : Two chars
                +        // - char1 >= 224 && char1 <= 239 : Three chars
                +        // - char1 >= 240 && char1 <= 244 : Four chars
                +        if (ord($char) < 128) {
                +            // One Char like ascii
                +        } elseif (ord($char) >= 194 && ord($char) <= 223) {
                +            // Two chars
                +            $char .= fgetc(STDIN);
                +        } elseif (ord($char) >= 224 && ord($char) <= 239) {
                +            // Three chars
                +            $char .= fgetc(STDIN) . fgetc(STDIN);
                +        } elseif (ord($char) >= 240 && ord($char) <= 244) {
                +            // Four chars
                +            $char .= fgetc(STDIN) . fgetc(STDIN) . fgetc(STDIN);
                         }
                -        elseif (count ($completeArr))
                -        {
                -          // Multiple entries : display them to allow the user to choose
                -          $this->debug ("Autocompletion : Multiple entries : display choices");
                -          echo "\n";
                -          // In associative array, the key is the possible answer to
                -          // autocompletion, and the value is the helper message
                -          // Get the largest key length to make a beautiful alignment
                -          // Get the smaller key length to found a affined answer
                -          $maxlen = 0;
                -          foreach ($completeArr as $key => $val)
                -          {
                -            $maxlen = max ($maxlen, mb_strlen ($key));
                -          }
                -          $maxlen = $maxlen + 5;
                -          if ($isAssoc)
                -            ksort ($completeArr, SORT_NATURAL);
                -          else
                -            sort ($completeArr, SORT_NATURAL);
                -          foreach ($completeArr as $key => $val)
                -          {
                -            if ($isAssoc)
                -              printf ("%-${maxlen}s %s\n", $key, $val);
                -            elseif (trim ($val) === "")
                -              // TODO : Define the string to display for ending string
                -              echo "
                \n"; - else - echo "$val\n"; - } - if ($isAssoc) - $addChars = $this->shortestIdenticalValues ( - array_keys ($completeArr)); - else - $addChars = $this->shortestIdenticalValues ($completeArr); - if ($addChars === "") - $addChars = $end; - $string = $start.$addChars; + if ($this->echoMode && ! in_array(ord($char), $this->nonWriteableChar)) { + echo $char; } - else - { - $this->debug ("Autocompletion : Zero entry : do not change"); - $string = $start.$end; + return $char; + } + + /** Get the line of characters pressed by the user and return the result. + * Stop when the user valid by \n. + * Manage correctely the backspace, the Ctrl+W to remove word... + * @param string $propo Preset the text for the user + * @param boolean|string $stopperChar The chars to stop the analysis and + * return the result + * @return string The typed string + */ + public function readline($propo = "", $stopperChar = false) + { + // Gets can not delete chars before the call. Keep the prompt (if exists) + if (! is_string($propo)) { + $this->consoleException("Invalid proposition provided to readline"); } - if (is_array ($completeArr) && count ($completeArr)) - { - // If there were multiple suggestions displayed, rewrite the line - $cursorPos = mb_strlen ($prompt.$string) + 1; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); + $prompt = $this->lineContent; + $minLength = mb_strlen($this->lineContent) + 1; + // Manage the history and a temporary buffer if the user has already type + // something before calling the history + $historyPos = count($this->history); + $string = $propo; + echo $string; + $this->lineContent = $prompt . $string; + // The cursor position from last char of line. + $cursorPos = mb_strlen($this->lineContent) + 1; + while (1) { + $char = $this->getKey(); + if ($stopperChar === false && $char === "\n") { + // End of process without stopperChars + $this->lineContent = ""; + break; + } + if ( + $stopperChar !== false && + in_array($char, $this->mb_str_split($stopperChar)) + ) { + // End of process with stopperChars + $this->lineContent = ""; + break; + } + if ( + $this->completionKeys !== false && + in_array($char, $this->mb_str_split($this->completionKeys)) + ) { + // Manage autocompletion + $this->debug("Autocompletion starting"); + // Take the last part of the string without space or double quotes + $pos = strrpos($string, " "); + if ($pos === false) { + // No space : put all in end + $start = ""; + $end = $string; + } elseif ($pos === mb_strlen($string)) { + // Last char is a space : put all in start + $start = $string; + $end = ""; + } else { + // Last char is not a space, end is the last word and start is the + // begin to before last word + $start = mb_substr($string, 0, $pos + 1); + $end = mb_substr($string, $pos + 1); + } + $this->debug("Autocompletion : start='$start', end='$end'"); + $completeArr = call_user_func( + $this->completionFunction, + self::tokenize($start) + ); + if (! is_array($completeArr)) { + throw new \Exception("Autocompletion : return is not an array"); + } + $isAssoc = is_array($completeArr) && + array_diff_key($completeArr, array_keys(array_keys($completeArr))); + // Remove from completeArr the proposed values which doesn't match with + // $end (invalid proposals) + foreach ($completeArr as $key => $val) { + if ($isAssoc) { + $val = $key; + } + if (mb_substr($val, 0, mb_strlen($end)) !== $end) { + unset($completeArr[$key]); + } + } + if ( + count($completeArr) === 1 && + ($isAssoc && key($completeArr) !== "" || + ! $isAssoc && reset($completeArr) !== "") + ) { + // One entry : add a space to put on the next + $this->debug("Autocompletion : One entry not empty : " . + "add it + ending space"); + if ($isAssoc) { + $string = $start . key($completeArr) . " "; + } else { + $string = $start . reset($completeArr) . " "; + } + } elseif (count($completeArr)) { + // Multiple entries : display them to allow the user to choose + $this->debug("Autocompletion : Multiple entries : display choices"); + echo "\n"; + // In associative array, the key is the possible answer to + // autocompletion, and the value is the helper message + // Get the largest key length to make a beautiful alignment + // Get the smaller key length to found a affined answer + $maxlen = 0; + foreach ($completeArr as $key => $val) { + $maxlen = max($maxlen, mb_strlen($key)); + } + $maxlen = $maxlen + 5; + if ($isAssoc) { + ksort($completeArr, SORT_NATURAL); + } else { + sort($completeArr, SORT_NATURAL); + } + foreach ($completeArr as $key => $val) { + if ($isAssoc) { + printf("%-${maxlen}s %s\n", $key, $val); + } elseif (trim($val) === "") { + // TODO : Define the string to display for ending string + echo "
                \n"; + } else { + echo "$val\n"; + } + } + if ($isAssoc) { + $addChars = $this->shortestIdenticalValues( + array_keys($completeArr) + ); + } else { + $addChars = $this->shortestIdenticalValues($completeArr); + } + if ($addChars === "") { + $addChars = $end; + } + $string = $start . $addChars; + } else { + $this->debug("Autocompletion : Zero entry : do not change"); + $string = $start . $end; + } + if (is_array($completeArr) && count($completeArr)) { + // If there were multiple suggestions displayed, rewrite the line + $cursorPos = mb_strlen($prompt . $string) + 1; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } + $this->debug("Autocompletion : end '$prompt.$string'"); + } elseif (ord($char) === 0) { + // End of file + $this->debug("Empty File entry : " . ord($char)); + $string = chr(0); + break; + } elseif (ord($char) === 3) { + // Abort (Ctrl+C) + $this->debug("Abort Ctrl+C : " . ord($char)); + $this->lineContent = ""; + $string = ""; + $this->clearLine(); + echo "$prompt\n"; + break; + } elseif (ord($char) === 4) { + // Logout (Ctrl+D) + $this->debug("Logout Ctrl+D : " . ord($char)); + $string = "exit\n"; + $this->rewriteLine($prompt . $string); + return $string; + } elseif (ord($char) === 12) { + // Refresh page (Ctrl+L) + $this->debug("Refresh Ctrl+L : " . ord($char)); + echo "\033[2J\033[;H\033c"; + $cursorPos = mb_strlen($prompt . $string) + 1; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } elseif (ord($char) === 21) { + // Empty line from prompt to cursor (Ctrl+U) + $this->debug("Empty line from prompt to cursor Ctrl+U : " . ord($char)); + $string = mb_substr($string, $cursorPos - $minLength); + $cursorPos = $minLength; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } elseif (ord($char) === 23) { + // Remove the last word (Ctrl+W) + $this->debug("Remove the last word Ctrl+W : " . ord($char)); + $tmp = mb_substr($string, 0, $cursorPos - $minLength); + $end = mb_substr($string, $cursorPos - $minLength); + $tmp = rtrim($tmp); + $pos = mb_strrpos($tmp, " "); + if ($pos !== false) { + $pos++; + } + $string = mb_substr($string, 0, $pos) . $end; + $cursorPos = $minLength + $pos; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } elseif (ord($char) === 127 || ord($char) === 8) { + // Remove the previous char (Backspace) + $this->debug("Remove the previous char (Backspace) : " . ord($char)); + if ($cursorPos <= $minLength) { + continue; + } + $strArr = $this->mb_str_split($string); + $cursorPos--; + unset($strArr[$cursorPos - $minLength]); + $string = implode($strArr); + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } elseif (ord($char[0]) === 27) { + // ESC SEQUENCE + $sequence = ""; + foreach (str_split($char) as $key) { + $sequence .= ord($key) . " "; + } + $this->debug("ESC SEQUENCE : $sequence"); + if ($char === chr(27) . chr(91) . chr(49) . chr(59) . chr(53) . chr(67)) { + // Cursor right + Ctrl : cursor jump by word + $this->debug("Cursor right + Ctrl"); + $tmp = mb_substr($string, $cursorPos - $minLength); + $tmp = ltrim($tmp); + $pos = strpos($tmp, " "); + if ($pos !== false) { + $cursorPos += $pos + 1 ; + } else { + $cursorPos = mb_strlen($prompt . $string) + 1; + } + $this->moveCursor($cursorPos); + } elseif ($char === chr(27) . chr(91) . chr(49) . chr(59) . chr(53) . chr(68)) { + // Cursor left + Ctrl : cursor jump by word + $this->debug("Cursor left + Ctrl"); + $tmp = mb_substr($string, 0, $cursorPos - $minLength); + $tmp = rtrim($tmp); + $pos = strrpos($tmp, " "); + if ($pos !== false) { + $pos++; + } + $cursorPos = $minLength + $pos; + $this->moveCursor($cursorPos); + } elseif ($char === chr(27) . chr(91) . chr(65)) { + // Cursor up : display the previous history if defined + $this->debug("Cursor up"); + if (! isset($historyTmp)) { + $historyTmp = $string; + $historyTmpPos = $cursorPos; + } + if ($historyPos > 0) { + $historyPos--; + $slice = array_slice($this->history, $historyPos, 1); + $string = reset($slice); + $cursorPos = mb_strlen($prompt . $string) + 1; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } + } elseif ($char === chr(27) . chr(91) . chr(66)) { + // Cursor down : display the next history if defined + $this->debug("Cursor down"); + if ($historyPos < count($this->history) - 1) { + $historyPos++; + $slice = array_slice($this->history, $historyPos, 1); + $string = reset($slice); + $cursorPos = mb_strlen($prompt . $string) + 1; + } elseif (isset($historyTmp)) { + $string = $historyTmp; + $cursorPos = $historyTmpPos; + unset($historyTmp); + } + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } elseif ($char === chr(27) . chr(91) . chr(67)) { + // Cursor right + $this->debug("Cursor right"); + if ($cursorPos <= mb_strlen($this->lineContent)) { + $cursorPos++; + $this->moveCursor($cursorPos); + } + } elseif ($char === chr(27) . chr(91) . chr(68)) { + // Cursor left + $this->debug("Cursor left"); + if ($cursorPos > $minLength) { + $cursorPos--; + $this->moveCursor($cursorPos); + } + } elseif ($char === chr(27) . chr(91) . chr(70)) { + // End key + $this->debug("End key"); + $cursorPos = $minLength + mb_strlen($string); + $this->moveCursor($cursorPos); + } elseif ($char === chr(27) . chr(91) . chr(72)) { + // Home key + $this->debug("Home key"); + $cursorPos = $minLength; + $this->moveCursor($cursorPos); + } elseif ($char === chr(27) . chr(91) . chr(51) . chr(126)) { + // Remove the char under the cursor (Delete) + $this->debug("Delete key"); + if ($cursorPos > mb_strlen($prompt . $string)) { + continue; + } + $strArr = $this->mb_str_split($string); + unset($strArr[$cursorPos - $minLength]); + $string = implode($strArr); + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } + } elseif (in_array(ord($char), $this->nonWriteableChar)) { + // Non writeable char : skip it + $this->debug("Non writeable char : " . ord($char)); + } else { + // Normal char : Add it to the string + $this->debug("Normal char : " . ord($char)); + $strArr = $this->mb_str_split($string); + $firstArr = array_slice($strArr, 0, $cursorPos - $minLength); + $lastArr = array_slice($strArr, $cursorPos - $minLength); + $insertArr = array($char); + $strArr = array_merge($firstArr, $insertArr, $lastArr); + $string = implode($strArr); + $cursorPos++; + $this->rewriteLine($prompt . $string); + $this->moveCursor($cursorPos); + } } - $this->debug ("Autocompletion : end '$prompt.$string'"); - } - elseif (ord ($char) === 0) - // End of file - { - $this->debug("Empty File entry : ".ord($char)); - $string = chr(0); - break; - } - elseif (ord ($char) === 3) - // Abort (Ctrl+C) - { - $this->debug ("Abort Ctrl+C : ".ord ($char)); - $this->lineContent = ""; - $string = ""; - $this->clearLine (); - echo "$prompt\n"; - break; - } - elseif (ord ($char) === 4) - // Logout (Ctrl+D) - { - $this->debug ("Logout Ctrl+D : ".ord ($char)); - $string = "exit\n"; - $this->rewriteLine ($prompt.$string); + $this->debug("End of readline '$string'"); return $string; - } - elseif (ord($char) === 12) - // Refresh page (Ctrl+L) - { - $this->debug ("Refresh Ctrl+L : ".ord ($char)); - echo "\033[2J\033[;H\033c"; - $cursorPos = mb_strlen ($prompt.$string) + 1; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - elseif (ord($char) === 21) - // Empty line from prompt to cursor (Ctrl+U) - { - $this->debug ("Empty line from prompt to cursor Ctrl+U : ".ord ($char)); - $string = mb_substr ($string, $cursorPos - $minLength); - $cursorPos = $minLength; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - elseif (ord($char) === 23) - // Remove the last word (Ctrl+W) - { - $this->debug ("Remove the last word Ctrl+W : ".ord ($char)); - $tmp = mb_substr ($string, 0, $cursorPos - $minLength); - $end = mb_substr ($string, $cursorPos - $minLength); - $tmp = rtrim ($tmp); - $pos = mb_strrpos ($tmp, " "); - if ($pos !== false) - $pos++; - $string = mb_substr ($string, 0, $pos).$end; - $cursorPos = $minLength + $pos; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - elseif (ord($char) === 127 || ord($char) === 8) - // Remove the previous char (Backspace) - { - $this->debug ("Remove the previous char (Backspace) : ".ord ($char)); - if ($cursorPos <= $minLength) - continue; - $strArr = $this->mb_str_split ($string); - $cursorPos--; - unset ($strArr[$cursorPos - $minLength]); - $string = implode ($strArr); - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - elseif (ord ($char[0]) === 27) - { - // ESC SEQUENCE - $sequence = ""; - foreach (str_split ($char) as $key) - $sequence .= ord ($key)." "; - $this->debug ("ESC SEQUENCE : $sequence"); - if ($char === chr (27).chr (91).chr (49).chr (59).chr (53).chr (67)) - // Cursor right + Ctrl : cursor jump by word - { - $this->debug ("Cursor right + Ctrl"); - $tmp = mb_substr ($string, $cursorPos - $minLength); - $tmp = ltrim ($tmp); - $pos = strpos ($tmp, " "); - if ($pos !== false) - $cursorPos += $pos +1 ; - else - $cursorPos = mb_strlen ($prompt.$string) + 1; - $this->moveCursor ($cursorPos); - } - elseif ($char === chr (27).chr (91).chr (49).chr (59).chr (53).chr (68)) - // Cursor left + Ctrl : cursor jump by word - { - $this->debug ("Cursor left + Ctrl"); - $tmp = mb_substr ($string, 0, $cursorPos - $minLength); - $tmp = rtrim ($tmp); - $pos = strrpos ($tmp, " "); - if ($pos !== false) $pos++; - $cursorPos = $minLength + $pos; - $this->moveCursor ($cursorPos); - } - elseif ($char === chr (27).chr (91).chr (65)) - // Cursor up : display the previous history if defined - { - $this->debug ("Cursor up"); - if (! isset ($historyTmp)) - { - $historyTmp = $string; - $historyTmpPos = $cursorPos; - } - if ($historyPos > 0) - { - $historyPos--; - $slice = array_slice ($this->history, $historyPos, 1); - $string = reset ($slice); - $cursorPos = mb_strlen ($prompt.$string) + 1; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - } - elseif ($char === chr (27).chr (91).chr (66)) - // Cursor down : display the next history if defined - { - $this->debug ("Cursor down"); - if ($historyPos < count ($this->history) - 1) - { - $historyPos++; - $slice = array_slice ($this->history, $historyPos, 1); - $string = reset ($slice); - $cursorPos = mb_strlen ($prompt.$string) + 1; - } - elseif (isset ($historyTmp)) - { - $string = $historyTmp; - $cursorPos = $historyTmpPos; - unset ($historyTmp); - } - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - elseif ($char === chr (27).chr (91).chr (67)) - // Cursor right - { - $this->debug ("Cursor right"); - if ($cursorPos <= mb_strlen ($this->lineContent)) - { - $cursorPos++; - $this->moveCursor ($cursorPos); - } - } - elseif ($char === chr (27).chr (91).chr (68)) - // Cursor left - { - $this->debug ("Cursor left"); - if ($cursorPos > $minLength) - { - $cursorPos--; - $this->moveCursor ($cursorPos); - } - } - elseif ($char === chr (27).chr (91).chr (70)) - // End key - { - $this->debug ("End key"); - $cursorPos = $minLength + mb_strlen ($string); - $this->moveCursor ($cursorPos); - } - elseif ($char === chr (27).chr (91).chr (72)) - // Home key - { - $this->debug ("Home key"); - $cursorPos = $minLength; - $this->moveCursor ($cursorPos); - } - elseif ($char === chr (27).chr (91).chr (51).chr (126)) - // Remove the char under the cursor (Delete) - { - $this->debug ("Delete key"); - if ($cursorPos > mb_strlen ($prompt.$string)) - continue; - $strArr = $this->mb_str_split ($string); - unset ($strArr[$cursorPos - $minLength]); - $string = implode ($strArr); - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } - } - elseif (in_array (ord ($char), $this->nonWriteableChar)) - // Non writeable char : skip it - { - $this->debug ("Non writeable char : ".ord ($char)); - } - else - // Normal char : Add it to the string - { - $this->debug ("Normal char : ".ord ($char)); - $strArr = $this->mb_str_split ($string); - $firstArr = array_slice ($strArr, 0, $cursorPos - $minLength); - $lastArr = array_slice ($strArr, $cursorPos - $minLength); - $insertArr = array ($char); - $strArr = array_merge ($firstArr, $insertArr, $lastArr); - $string = implode ($strArr); - $cursorPos++; - $this->rewriteLine ($prompt.$string); - $this->moveCursor ($cursorPos); - } } - $this->debug ("End of readline '$string'"); - return $string; - } - /** Rewrite the line with the provided $text. - * Delete all the old data - * @param string $text The new text to use on line - */ - private function rewriteLine ($text) - { - $this->debug ("Call rewriteLine ($text)"); - if ($this->echoMode) + /** Rewrite the line with the provided $text. + * Delete all the old data + * @param string $text The new text to use on line + */ + private function rewriteLine($text) { - $this->clearLine (); - $this->lineContent = $text; - echo $this->lineContent; - $this->cursorPos = mb_strlen ($this->lineContent); + $this->debug("Call rewriteLine ($text)"); + if ($this->echoMode) { + $this->clearLine(); + $this->lineContent = $text; + echo $this->lineContent; + $this->cursorPos = mb_strlen($this->lineContent); + } } - } - /** Move the cursor on position $position. The first column is $cursorPos=1 - * @param integer $cursorPos The new position on line - */ - private function moveCursor ($cursorPos) - { - $this->debug ("Call moveCursor ($cursorPos)"); - if ($cursorPos < 1) - $this->consoleException ("MoveCursor lesser than one : $cursorPos"); - if ($this->echoMode) + /** Move the cursor on position $position. The first column is $cursorPos=1 + * @param integer $cursorPos The new position on line + */ + private function moveCursor($cursorPos) { - $oldLength = mb_strlen ($this->lineContent); - // 1. Calculate on which line the cursor is positionned - $cursorLine = 1 + floor ((-1+$this->cursorPos) / $this->termWidth); - // 2. Return the cursor to the first line - for ($i = $cursorLine ; $i > 1 ; $i--) - echo chr (27).chr (91).chr (49).chr (65)."\r"; - // 3. Down the cursor to the wanted line - $wantedLine = ceil ($cursorPos / $this->termWidth); - if ($wantedLine > 1) - { - for ($i = 1 ; $i < $wantedLine ; $i++) - echo "\r".chr (27).chr (91).chr (49).chr (66)."\r"; - } - // 4. Move the cursor on the last line - $needMovePos = -1 + $cursorPos - ($wantedLine - 1) * $this->termWidth; - echo "\r".str_repeat (chr (27).chr (91).chr (67), $needMovePos); - $this->cursorPos = $cursorPos; + $this->debug("Call moveCursor ($cursorPos)"); + if ($cursorPos < 1) { + $this->consoleException("MoveCursor lesser than one : $cursorPos"); + } + if ($this->echoMode) { + $oldLength = mb_strlen($this->lineContent); + // 1. Calculate on which line the cursor is positionned + $cursorLine = 1 + floor((-1 + $this->cursorPos) / $this->termWidth); + // 2. Return the cursor to the first line + for ($i = $cursorLine; $i > 1; $i--) { + echo chr(27) . chr(91) . chr(49) . chr(65) . "\r"; + } + // 3. Down the cursor to the wanted line + $wantedLine = ceil($cursorPos / $this->termWidth); + if ($wantedLine > 1) { + for ($i = 1; $i < $wantedLine; $i++) { + echo "\r" . chr(27) . chr(91) . chr(49) . chr(66) . "\r"; + } + } + // 4. Move the cursor on the last line + $needMovePos = -1 + $cursorPos - ($wantedLine - 1) * $this->termWidth; + echo "\r" . str_repeat(chr(27) . chr(91) . chr(67), $needMovePos); + $this->cursorPos = $cursorPos; + } } - } - /** Clear the existing line. - */ - public function clearLine () - { - $this->debug ("Call clearLine"); - $oldLength = mb_strlen ($this->lineContent); - // 1. Calculate on which line the cursor is positionned - $cursorLine = 1 + floor ((-1+$this->cursorPos) / $this->termWidth); - $lastLines = 1 + floor ((1+$oldLength) / $this->termWidth); - $this->debug ("==> clearLine : oldLength=$oldLength, ". + /** Clear the existing line. + */ + public function clearLine() + { + $this->debug("Call clearLine"); + $oldLength = mb_strlen($this->lineContent); + // 1. Calculate on which line the cursor is positionned + $cursorLine = 1 + floor((-1 + $this->cursorPos) / $this->termWidth); + $lastLines = 1 + floor((1 + $oldLength) / $this->termWidth); + $this->debug("==> clearLine : oldLength=$oldLength, " . "cursorLine=$cursorLine, lastLines=$lastLines"); - for ($i = $cursorLine ; $i < $lastLines ; $i++) - { - $this->debug ("==> clearLine : go Down (i=$i<$lastLines)"); - echo "\033[1B"; - } - // 3. Remove the lines from lastLines to line 1 - if ($lastLines > 1) - { - for ($i = $lastLines ; $i > 1 ; $i--) - { - $this->debug ("==> clearLine : Remove line up (i=$i<$lastLines)"); - echo "\r\033[K\033[1A\r"; - } - } - // 4. Clean the line 1 - $this->debug ("==> clearLine : Remove line 1"); - echo "\r\033[K"; - $this->lineContent = ""; - $this->cursorPos = 1; - } - - /** Clear all the screen and remove the scroll of the screen - */ - public function clearScreen () - { - echo "\033[2J\033[;H\033c"; - } - - /** Get the terminal Height - */ - public function getTermHeight () - { - return $this->termHeight; - } - - /** Get the terminal Width - */ - public function getTermWidth () - { - return $this->termWidth; - } - - /** Call a specific function when a completion key is pressed - * The function must get the partial text as first parameter, and must return - * an array with the possibilities - * If only one possibility is returned, the console will be immediately - * updated. - * @param string|bool $completionKeys The list of the completion keys. False - * unset the method - * @param callable $completionFunction The function called when one of the - * completion keys is pressed. - */ - public function completeFunction ($completionKeys, $completionFunction) - { - if (! is_string ($completionKeys) && ! is_boolean ($completionKeys)) - $this->consoleException ("Can not set the completionKeys : not a string"); - if ($completionKeys === true) - $this->consoleException ("Can not set the completionKeys : not false"); - if (! is_callable ($completionFunction)) - $this->consoleException ("Can not set the completionFunction : ". - "not a callable function"); - $this->completionKeys = $completionKeys; - $this->completionFunction = $completionFunction; - } - - /** Get the actual history in memory - */ - public function getHistory () - { - return $this->history; - } - - /** Clear the history - * This method do NOT write the empty history on disk - */ - public function clearHistory () - { - $this->history = array (); - return $this; - } - - /** Write the history to disk. - * @param string $historyFile The history file where the history is stored - */ - public function writeHistory ($historyFile) - { - if (file_exists ($historyFile)) - { - if (! is_writeable ($historyFile)) - $this->consoleException ("History file '$historyFile' ". - "is not writeable"); - $history = file_get_contents ($historyFile); - if ($history === false) - $this->consoleException ("History file '$historyFile' can not be read"); - $historyArr = explode ("\n", $history); - if (! isset ($historyArr[0]) || $historyArr[0] !== "__HISTORY__") - $this->consoleException ("History file '$historyFile' ". - "is not an history file : do not touch\n"); - } - elseif (! file_exists (dirname ($historyFile))) - $this->consoleException ("History file '$historyFile' ". - "can not be created: parent directory doesn't exists"); - elseif (! is_dir (dirname ($historyFile))) - $this->consoleException ("History file '$historyFile' ". - "can not be created: parent directory is not a directory"); - file_put_contents ($historyFile, "__HISTORY__\n"); - $history = ""; - foreach ($this->history as $time => $command) - $history .= "$time $command\n"; - file_put_contents ($historyFile, $history, FILE_APPEND|LOCK_EX); - return $this; - } - - /** Read the history from the disk - * If the file doesn't exists, return an empty array - * @param string $historyFile The history file where the history is stored - * @return the read history with timestamp as key and command as value - */ - public function readHistory ($historyFile) - { - if (! file_exists ($historyFile)) - { - $this->history = array (); - return array (); - } - if (! is_readable ($historyFile)) - $this->consoleException ("History file '$historyFile' can not be read"); - $history = file_get_contents ($historyFile); - if ($history === false) - $this->consoleException ("History file '$historyFile' can not be read"); - $historyArr = explode ("\n", $history); - if (! isset ($historyArr[0]) || $historyArr[0] !== "__HISTORY__") - $this->consoleException ("History file '$historyFile' ". - "is not an history file : do not touch\n"); - array_shift ($historyArr); - foreach ($historyArr as $line) - { - @list ($time, $command) = @explode (" ", $line, 2); - if ($time === null || $command === null || ! ctype_digit ($time)) - continue; - $this->history[$time] = $command; - } - return $this->history; - } - - /** Add a new entry in history. - * The new line can not be empty : it is not stored, but without error - * This method do NOT write the history on disk : you must use writeHistory - * @param string The new entry to add in history - */ - public function addHistory ($line) - { - if (! is_string ($line)) - $this->consoleException ("Can not add line to history : ". - "it is not a string"); - if (trim ($line) === "") - return $this; - $this->history[time()] = $line; - $this->history = array_slice ($this->history, -$this->historyMaxSize, null, - true); - return $this; - } - - /** Get/Set the maximum number of entries in the history - * If null, get the defined maximum number - * @param integer|null $historyMaxSize The maximum number of entries - */ - public function historyMaxSize ($historyMaxSize = null) - { - if ($historyMaxSize === null) - return $this->historyMaxSize; - if (intval ($historyMaxSize) < 1) - $this->consoleException ("Can not set the historyMaxSize : ". - "negative value provided"); - $this->historyMaxSize = intval ($historyMaxSize); - } - - /** Error management - * @param string $message The message to throw in the exception - */ - public function consoleException ($message) - { - throw new \Exception ($message, 500); - } - - /** Set the text color - * @param integer $colorNum The color number to use - */ - public function colorText ($colorNum) - { - if (! is_int ($colorNum)) - $this->consoleException ("ColorNum provided to colorText is not an ". - "integer"); - echo "\033[38;5;${colorNum}m"; - } - - /** Set the background text color - * @param integer $colorNum The color number to use - */ - public function colorBackgroundText ($colorNum) - { - if (! is_int ($colorNum)) - $this->consoleException ("ColorNum provided to colorBackgroundText not ". - "an integer"); - echo "\033[48;5;${colorNum}m"; - } - - /** Reset the colors - */ - public function colorReset () - { - echo "\033[0m"; - } - - /** Underline the text - * @param boolean $underline True to underline, false to remove the underline - */ - public function textUnderline ($underline) - { - if ($underline === false) - $underline = 2; - else - $underline = ""; - echo "\033[${underline}4m"; - } - - /** Bold the text - * @param boolean $bold True to bold, false to remove the bold - */ - public function textBold ($bold) - { - if ($bold === false) - $bold = 0; - else - $bold = 1; - echo "\033[${bold}m"; - } - - /** Return true if the TTY is enabled, or false if the program is called from pipe - */ - public function isTTY() - { - return !! $this->initSttyState; - } - - /** Tokenize the provided line and aggragate if there is single or double - * quotes. - * Trim the spaces - * @param string $line The line to tokenize - * @return array The tokens - */ - static public function tokenize ($line) - { - $tokens = array (); - $token = strtok (trim ($line),' '); - while ($token) - { - // find double quoted tokens - if ($token[0]=='"') { $token .= ' '.strtok('"').'"'; } - // find single quoted tokens - if ($token[0]=="'") { $token .= ' '.strtok("'")."'"; } - $tokens[] = $token; - $token = strtok(' '); - } - return $tokens; - } - - /** This function return an array with each char, but supports UTF-8 - * @param string $string The string to explode - * @param integer $split_length The number of chars in each split - * @return array - */ - private function mb_str_split ($string, $split_length = 1) - { - $res = array(); - for ($i = 0; $i < mb_strlen ($string); $i += $split_length) - $res[] = mb_substr ($string, $i, $split_length); - return $res; - } - - /** This function debug the data - * @param mixed $data The data to store - */ - private function debug ($data) - { - if ($this->debug === false) - return; - if (is_array ($data) || is_bool ($data)) - $data = var_export ($data, true); - file_put_contents ($this->debug, date ("H:i:s")." $data\n", FILE_APPEND); - } - - /** Look in the array which first chars of each possibilites are identical. - * @param array $completeArr The values to examine - * @return string the identical chars - */ - private function shortestIdenticalValues ($completeArr) - { - if (! is_array ($completeArr)) - return ""; - $minlen = 99999; - foreach ($completeArr as $val) - { - $minlen = min ($minlen, mb_strlen ($val)); - } - $identicalString = ""; - $sameCharLength = 1 ; - while ($sameCharLength <= $minlen) - { - $tmp = ""; - foreach ($completeArr as $val) - { - $part = mb_substr ($val, 0, $sameCharLength); - if ($tmp == "") - $tmp = $part; - if ($tmp !== $part) - { - break 2; + for ($i = $cursorLine; $i < $lastLines; $i++) { + $this->debug("==> clearLine : go Down (i=$i<$lastLines)"); + echo "\033[1B"; } - } - $identicalString = $tmp; - $sameCharLength++; + // 3. Remove the lines from lastLines to line 1 + if ($lastLines > 1) { + for ($i = $lastLines; $i > 1; $i--) { + $this->debug("==> clearLine : Remove line up (i=$i<$lastLines)"); + echo "\r\033[K\033[1A\r"; + } + } + // 4. Clean the line 1 + $this->debug("==> clearLine : Remove line 1"); + echo "\r\033[K"; + $this->lineContent = ""; + $this->cursorPos = 1; + } + + /** Clear all the screen and remove the scroll of the screen + */ + public function clearScreen() + { + echo "\033[2J\033[;H\033c"; + } + + /** Get the terminal Height + */ + public function getTermHeight() + { + return $this->termHeight; + } + + /** Get the terminal Width + */ + public function getTermWidth() + { + return $this->termWidth; + } + + /** Call a specific function when a completion key is pressed + * The function must get the partial text as first parameter, and must return + * an array with the possibilities + * If only one possibility is returned, the console will be immediately + * updated. + * @param string|bool $completionKeys The list of the completion keys. False + * unset the method + * @param callable $completionFunction The function called when one of the + * completion keys is pressed. + */ + public function completeFunction($completionKeys, $completionFunction) + { + if (! is_string($completionKeys) && ! is_boolean($completionKeys)) { + $this->consoleException("Can not set the completionKeys : not a string"); + } + if ($completionKeys === true) { + $this->consoleException("Can not set the completionKeys : not false"); + } + if (! is_callable($completionFunction)) { + $this->consoleException("Can not set the completionFunction : " . + "not a callable function"); + } + $this->completionKeys = $completionKeys; + $this->completionFunction = $completionFunction; + } + + /** Get the actual history in memory + */ + public function getHistory() + { + return $this->history; + } + + /** Clear the history + * This method do NOT write the empty history on disk + */ + public function clearHistory() + { + $this->history = array(); + return $this; + } + + /** Write the history to disk. + * @param string $historyFile The history file where the history is stored + */ + public function writeHistory($historyFile) + { + if (file_exists($historyFile)) { + if (! is_writeable($historyFile)) { + $this->consoleException("History file '$historyFile' " . + "is not writeable"); + } + $history = file_get_contents($historyFile); + if ($history === false) { + $this->consoleException("History file '$historyFile' can not be read"); + } + $historyArr = explode("\n", $history); + if (! isset($historyArr[0]) || $historyArr[0] !== "__HISTORY__") { + $this->consoleException("History file '$historyFile' " . + "is not an history file : do not touch\n"); + } + } elseif (! file_exists(dirname($historyFile))) { + $this->consoleException("History file '$historyFile' " . + "can not be created: parent directory doesn't exists"); + } elseif (! is_dir(dirname($historyFile))) { + $this->consoleException("History file '$historyFile' " . + "can not be created: parent directory is not a directory"); + } + file_put_contents($historyFile, "__HISTORY__\n"); + $history = ""; + foreach ($this->history as $time => $command) { + $history .= "$time $command\n"; + } + file_put_contents($historyFile, $history, FILE_APPEND | LOCK_EX); + return $this; + } + + /** Read the history from the disk + * If the file doesn't exists, return an empty array + * @param string $historyFile The history file where the history is stored + * @return the read history with timestamp as key and command as value + */ + public function readHistory($historyFile) + { + if (! file_exists($historyFile)) { + $this->history = array(); + return array(); + } + if (! is_readable($historyFile)) { + $this->consoleException("History file '$historyFile' can not be read"); + } + $history = file_get_contents($historyFile); + if ($history === false) { + $this->consoleException("History file '$historyFile' can not be read"); + } + $historyArr = explode("\n", $history); + if (! isset($historyArr[0]) || $historyArr[0] !== "__HISTORY__") { + $this->consoleException("History file '$historyFile' " . + "is not an history file : do not touch\n"); + } + array_shift($historyArr); + foreach ($historyArr as $line) { + @list($time, $command) = @explode(" ", $line, 2); + if ($time === null || $command === null || ! ctype_digit($time)) { + continue; + } + $this->history[$time] = $command; + } + return $this->history; + } + + /** Add a new entry in history. + * The new line can not be empty : it is not stored, but without error + * This method do NOT write the history on disk : you must use writeHistory + * @param string The new entry to add in history + */ + public function addHistory($line) + { + if (! is_string($line)) { + $this->consoleException("Can not add line to history : " . + "it is not a string"); + } + if (trim($line) === "") { + return $this; + } + $this->history[time()] = $line; + $this->history = array_slice( + $this->history, + -$this->historyMaxSize, + null, + true + ); + return $this; + } + + /** Get/Set the maximum number of entries in the history + * If null, get the defined maximum number + * @param integer|null $historyMaxSize The maximum number of entries + */ + public function historyMaxSize($historyMaxSize = null) + { + if ($historyMaxSize === null) { + return $this->historyMaxSize; + } + if (intval($historyMaxSize) < 1) { + $this->consoleException("Can not set the historyMaxSize : " . + "negative value provided"); + } + $this->historyMaxSize = intval($historyMaxSize); + } + + /** Error management + * @param string $message The message to throw in the exception + */ + public function consoleException($message) + { + throw new \Exception($message, 500); + } + + /** Set the text color + * @param integer $colorNum The color number to use + */ + public function colorText($colorNum) + { + if (! is_int($colorNum)) { + $this->consoleException("ColorNum provided to colorText is not an " . + "integer"); + } + echo "\033[38;5;${colorNum}m"; + } + + /** Set the background text color + * @param integer $colorNum The color number to use + */ + public function colorBackgroundText($colorNum) + { + if (! is_int($colorNum)) { + $this->consoleException("ColorNum provided to colorBackgroundText not " . + "an integer"); + } + echo "\033[48;5;${colorNum}m"; + } + + /** Reset the colors + */ + public function colorReset() + { + echo "\033[0m"; + } + + /** Underline the text + * @param boolean $underline True to underline, false to remove the underline + */ + public function textUnderline($underline) + { + if ($underline === false) { + $underline = 2; + } else { + $underline = ""; + } + echo "\033[${underline}4m"; + } + + /** Bold the text + * @param boolean $bold True to bold, false to remove the bold + */ + public function textBold($bold) + { + if ($bold === false) { + $bold = 0; + } else { + $bold = 1; + } + echo "\033[${bold}m"; + } + + /** Return true if the TTY is enabled, or false if the program is called from pipe + */ + public function isTTY() + { + return !! $this->initSttyState; + } + + /** Tokenize the provided line and aggragate if there is single or double + * quotes. + * Trim the spaces + * @param string $line The line to tokenize + * @return array The tokens + */ + public static function tokenize($line) + { + $tokens = array(); + $token = strtok(trim($line), ' '); + while ($token) { + // find double quoted tokens + if ($token[0] == '"') { + $token .= ' ' . strtok('"') . '"'; + } + // find single quoted tokens + if ($token[0] == "'") { + $token .= ' ' . strtok("'") . "'"; + } + $tokens[] = $token; + $token = strtok(' '); + } + return $tokens; + } + + /** This function return an array with each char, but supports UTF-8 + * @param string $string The string to explode + * @param integer $split_length The number of chars in each split + * @return array + */ + private function mb_str_split($string, $split_length = 1) + { + $res = array(); + for ($i = 0; $i < mb_strlen($string); $i += $split_length) { + $res[] = mb_substr($string, $i, $split_length); + } + return $res; + } + + /** This function debug the data + * @param mixed $data The data to store + */ + private function debug($data) + { + if ($this->debug === false) { + return; + } + if (is_array($data) || is_bool($data)) { + $data = var_export($data, true); + } + file_put_contents($this->debug, date("H:i:s") . " $data\n", FILE_APPEND); + } + + /** Look in the array which first chars of each possibilites are identical. + * @param array $completeArr The values to examine + * @return string the identical chars + */ + private function shortestIdenticalValues($completeArr) + { + if (! is_array($completeArr)) { + return ""; + } + $minlen = 99999; + foreach ($completeArr as $val) { + $minlen = min($minlen, mb_strlen($val)); + } + $identicalString = ""; + $sameCharLength = 1 ; + while ($sameCharLength <= $minlen) { + $tmp = ""; + foreach ($completeArr as $val) { + $part = mb_substr($val, 0, $sameCharLength); + if ($tmp == "") { + $tmp = $part; + } + if ($tmp !== $part) { + break 2; + } + } + $identicalString = $tmp; + $sameCharLength++; + } + return $identicalString; } - return $identicalString; - } } diff --git a/src/Convert.php b/src/Convert.php index 1de3ef6..24e2d43 100644 --- a/src/Convert.php +++ b/src/Convert.php @@ -1,4 +1,5 @@ @@ -11,149 +12,179 @@ namespace Domframework; */ class Convert { - /** Convert Date received in one format to another. - * If the provided string is not corresponding to the format, generate an - * exception or return the original string - * Format used http://php.net/manual/en/datetime.createfromformat.php - * Do not accept the locale ! The language of the dates is always in english - * @param string $inputDate The date to modify - * @param string $inputFormat The input format of the date - * @param string $outputFormat The output format of the date - * @param boolean|null $exception If set, generate an exception if the - * provided date is invalid - * @param string|null $inputTimezone The timezone used to read the input - * By default, Europe/Paris - * @param string|null $outputTimezone The timezone used to write the output - * By default, Europe/Paris - * @return string - */ - public static function convertDate ($inputDate, $inputFormat, $outputFormat, - $exception = true, - $inputTimezone = "Europe/Paris", - $outputTimezone = "Europe/Paris") - { - if (! is_string ($inputDate)) - throw new \Exception ("The date to convert is not a string", 500); - if (! is_string ($inputFormat)) - throw new \Exception ("The convert input format is not a string", 500); - if (! is_string ($outputFormat)) - throw new \Exception ("The convert output format is not a string", 500); - $date = \DateTime::CreateFromFormat ($inputFormat, $inputDate, - new \DateTimeZone ($inputTimezone)); - if ($date === false) - { - if ($exception === true) - throw new \Exception ( - "Invalid date provided or not matching the format", 500); - return $inputDate; - } - $errors = $date->getLastErrors(); - if ($errors["warning_count"] > 0 || $errors["error_count"] > 0) - { - if ($exception === true) - throw new \Exception ( - "Invalid date provided or not matching the format", 500); - return $inputDate; + /** Convert Date received in one format to another. + * If the provided string is not corresponding to the format, generate an + * exception or return the original string + * Format used http://php.net/manual/en/datetime.createfromformat.php + * Do not accept the locale ! The language of the dates is always in english + * @param string $inputDate The date to modify + * @param string $inputFormat The input format of the date + * @param string $outputFormat The output format of the date + * @param boolean|null $exception If set, generate an exception if the + * provided date is invalid + * @param string|null $inputTimezone The timezone used to read the input + * By default, Europe/Paris + * @param string|null $outputTimezone The timezone used to write the output + * By default, Europe/Paris + * @return string + */ + public static function convertDate( + $inputDate, + $inputFormat, + $outputFormat, + $exception = true, + $inputTimezone = "Europe/Paris", + $outputTimezone = "Europe/Paris" + ) { + if (! is_string($inputDate)) { + throw new \Exception("The date to convert is not a string", 500); + } + if (! is_string($inputFormat)) { + throw new \Exception("The convert input format is not a string", 500); + } + if (! is_string($outputFormat)) { + throw new \Exception("The convert output format is not a string", 500); + } + $date = \DateTime::CreateFromFormat( + $inputFormat, + $inputDate, + new \DateTimeZone($inputTimezone) + ); + if ($date === false) { + if ($exception === true) { + throw new \Exception( + "Invalid date provided or not matching the format", + 500 + ); + } + return $inputDate; + } + $errors = $date->getLastErrors(); + if ($errors["warning_count"] > 0 || $errors["error_count"] > 0) { + if ($exception === true) { + throw new \Exception( + "Invalid date provided or not matching the format", + 500 + ); + } + return $inputDate; + } + + $date->setTimezone(new \DateTimeZone($outputTimezone)); + return $date->format($outputFormat); } - $date->setTimezone(new \DateTimeZone ($outputTimezone)); - return $date->format ($outputFormat); - } - - /** Convert the first char to capital and the rest of the sentence in - * lowercase (like ucfirst, but UTF8 compliant) - * @param string $str The string to convert - */ - public static function ucfirst ($str) - { - if (! function_exists ("mb_strtoupper")) - throw new \Exception ("PHP don't have the MB Support. Please add it !", - 500); - $a = mb_strtoupper (mb_substr ($str, 0, 1, 'UTF-8'), 'UTF-8'); - return $a . mb_substr ($str, 1, null, 'UTF-8'); - } - - /** Convert the first char of each word of a sentence to capital. The word - * delimiter can be provided. - * The sentence is in UTF-8. - * The sentence is converted to lowercase before doing the action (in - * contrary of the original PHP function) - * @param string $str The string to convert - * @param string $delimiters The delimiters (by default " \t\r\n\f\v") - * @return string - */ - public static function ucwords ($str, $delimiters = " \t\r\n\f\v") - { - if (! function_exists ("mb_strtolower")) - throw new \Exception ("PHP don't have the MB Support. Please add it !", - 500); - $str = mb_strtolower ($str, "utf-8"); - $res = ""; - foreach (preg_split ("#([".preg_quote ($delimiters)."]+)#", $str, -1, - PREG_SPLIT_DELIM_CAPTURE) as $tok) + /** Convert the first char to capital and the rest of the sentence in + * lowercase (like ucfirst, but UTF8 compliant) + * @param string $str The string to convert + */ + public static function ucfirst($str) { - $res .= Convert::ucfirst ($tok); + if (! function_exists("mb_strtoupper")) { + throw new \Exception( + "PHP don't have the MB Support. Please add it !", + 500 + ); + } + $a = mb_strtoupper(mb_substr($str, 0, 1, 'UTF-8'), 'UTF-8'); + return $a . mb_substr($str, 1, null, 'UTF-8'); } - return $res; - } - /** Convert the provided float to human readable format - * Example : 1440000 => 1.44MB - * @param float|integer $value The number to convert - * @param integer|null $decimals The number of decimal (2 by default) - * @param integer|null $power (1000 by default or 1024) - * @param string|null $unit The Unit displayed after the multiplier (B for - * Bytes by default) - */ - public static function humanSize ($value, $decimals = 2, $power = 1000, - $unit = "B") - { - if (! is_integer ($value) && ! is_float ($value)) - throw new \Exception ("convert::humanSize value not numerical : ". - gettype ($value), 500); - if (! is_integer ($decimals)) - throw new \Exception ("convert::humanSize decimal not integer : ". - gettype ($decimals), 500); - if ($decimals < 0) - throw new \Exception ("convert::humanSize decimal value negative", 500); - if ($power !== 1000 && $power !== 1024) - throw new \Exception ("convert::humanSize power value !== 1000 and 1024". - " : ".var_export ($power, true), 500); - $size = array ( - -8 => 'y', // yocto - -7 => 'z', // zepto - -6 => 'a', // atto - -5 => 'f', // femto - -4 => 'p', // pico - -3 => 'n', // nano - -2 => 'u', // micro - -1 => 'm', // milli - 0 => '', - 1 => 'k', // kilo - 2 => 'M', // mega - 3 => 'G', // giga - 4 => 'T', // tera - 5 => 'P', // peta - 6 => 'E', // exa - 7 => 'Z', // zetta - 8 => 'Y');// yotta - for ($factor = 8 ; $factor > -8 ; $factor--) + /** Convert the first char of each word of a sentence to capital. The word + * delimiter can be provided. + * The sentence is in UTF-8. + * The sentence is converted to lowercase before doing the action (in + * contrary of the original PHP function) + * @param string $str The string to convert + * @param string $delimiters The delimiters (by default " \t\r\n\f\v") + * @return string + */ + public static function ucwords($str, $delimiters = " \t\r\n\f\v") { - if (abs ($value) >= pow ($power, $factor)) - break; + if (! function_exists("mb_strtolower")) { + throw new \Exception( + "PHP don't have the MB Support. Please add it !", + 500 + ); + } + $str = mb_strtolower($str, "utf-8"); + $res = ""; + foreach ( + preg_split( + "#([" . preg_quote($delimiters) . "]+)#", + $str, + -1, + PREG_SPLIT_DELIM_CAPTURE + ) as $tok + ) { + $res .= Convert::ucfirst($tok); + } + return $res; } - if ($value == 0) - { - $display = 0; - $factor = 0; - } - elseif ($factor > 0) - $display = $value / pow ($power, $factor); - elseif ($factor < 0) - $display = $value * pow ($power, -1 * $factor); - else - $display = $value; - return sprintf ("%.${decimals}f", $display).$size[$factor].$unit; - } + /** Convert the provided float to human readable format + * Example : 1440000 => 1.44MB + * @param float|integer $value The number to convert + * @param integer|null $decimals The number of decimal (2 by default) + * @param integer|null $power (1000 by default or 1024) + * @param string|null $unit The Unit displayed after the multiplier (B for + * Bytes by default) + */ + public static function humanSize( + $value, + $decimals = 2, + $power = 1000, + $unit = "B" + ) { + if (! is_integer($value) && ! is_float($value)) { + throw new \Exception("convert::humanSize value not numerical : " . + gettype($value), 500); + } + if (! is_integer($decimals)) { + throw new \Exception("convert::humanSize decimal not integer : " . + gettype($decimals), 500); + } + if ($decimals < 0) { + throw new \Exception("convert::humanSize decimal value negative", 500); + } + if ($power !== 1000 && $power !== 1024) { + throw new \Exception("convert::humanSize power value !== 1000 and 1024" . + " : " . var_export($power, true), 500); + } + $size = array( + -8 => 'y', // yocto + -7 => 'z', // zepto + -6 => 'a', // atto + -5 => 'f', // femto + -4 => 'p', // pico + -3 => 'n', // nano + -2 => 'u', // micro + -1 => 'm', // milli + 0 => '', + 1 => 'k', // kilo + 2 => 'M', // mega + 3 => 'G', // giga + 4 => 'T', // tera + 5 => 'P', // peta + 6 => 'E', // exa + 7 => 'Z', // zetta + 8 => 'Y');// yotta + for ($factor = 8; $factor > -8; $factor--) { + if (abs($value) >= pow($power, $factor)) { + break; + } + } + if ($value == 0) { + $display = 0; + $factor = 0; + } elseif ($factor > 0) { + $display = $value / pow($power, $factor); + } elseif ($factor < 0) { + $display = $value * pow($power, -1 * $factor); + } else { + $display = $value; + } + + return sprintf("%.${decimals}f", $display) . $size[$factor] . $unit; + } } diff --git a/src/Csrf.php b/src/Csrf.php index a7e90f9..f6d0f7b 100644 --- a/src/Csrf.php +++ b/src/Csrf.php @@ -1,4 +1,5 @@ @@ -14,156 +15,166 @@ namespace Domframework; */ class Csrf { - /** Allow to disable the csrf protection - */ - public $csrf = TRUE; - /** This hidden field name in HTML - */ - public $field = "CSRF_TOKEN"; - /** The created token - */ - private $csrfToken = ""; - /** Timeout of the CSRF token : 3600s by default (maximum time allowed to - * enter information in form and submit) */ - private $csrfTimeout = 3600; + /** Allow to disable the csrf protection + */ + public $csrf = true; + /** This hidden field name in HTML + */ + public $field = "CSRF_TOKEN"; + /** The created token + */ + private $csrfToken = ""; + /** Timeout of the CSRF token : 3600s by default (maximum time allowed to + * enter information in form and submit) */ + private $csrfTimeout = 3600; - /** Manage the singleton - */ - public function __construct () - { - if (isset ($GLOBALS["domframework"]["csrf"])) + /** Manage the singleton + */ + public function __construct() { - $this->csrfToken = $GLOBALS["domframework"]["csrf"]->csrfToken; - $this->field = $GLOBALS["domframework"]["csrf"]->field; - $this->csrfTimeout = $GLOBALS["domframework"]["csrf"]->csrfTimeout; + if (isset($GLOBALS["domframework"]["csrf"])) { + $this->csrfToken = $GLOBALS["domframework"]["csrf"]->csrfToken; + $this->field = $GLOBALS["domframework"]["csrf"]->field; + $this->csrfTimeout = $GLOBALS["domframework"]["csrf"]->csrfTimeout; + } else { + $GLOBALS["domframework"]["csrf"] = $this; + } } - else + + /** Get / Set the status of the CSRF protection + * @param boolean|null $val The value to set/get if null + */ + public function csrfState($val = null) { - $GLOBALS["domframework"]["csrf"] = $this; + if ($val === null) { + return $this->csrf; + } + $this->csrf = !! $val; + $GLOBALS["domframework"]["csrf"] = $this; + return $this; } - } - /** Get / Set the status of the CSRF protection - * @param boolean|null $val The value to set/get if null - */ - public function csrfState ($val = null) - { - if ($val === null) - return $this->csrf; - $this->csrf = !! $val; - $GLOBALS["domframework"]["csrf"] = $this; - return $this; - } - - /** Get / Set the name of the field in HTML - * @param string|null $val The value to set/get if null - */ - public function field ($val = null) - { - if ($val === null) - return $this->field; - $this->field = $val; - $GLOBALS["domframework"]["csrf"] = $this; - return $this; - } - - /** This function return the token - */ - public function createToken () - { - $l = 30; // Number of chars in token - $c = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - for ($s = '', - $cl = strlen($c)-1, $i = 0; $i < $l; $s .= $c[mt_rand(0, $cl)], - ++$i); - $this->csrfToken = $s; - $_SESSION["domframework"]["csrf"][$this->csrfToken] = microtime (TRUE); - $GLOBALS["domframework"]["csrf"] = $this; - return $this->csrfToken; - } - - /** Check if the provided token is the right token, defined last displayed - * page - * @param string $tokenFromUser The value csrf the user's token - */ - public function checkToken ($tokenFromUser) - { - if ($this->csrf === FALSE ) - return TRUE; - // Migrate from unique format to multiple CSRF tokens format - // The new format is : array (token => the last used time) - if (isset ($_SESSION["domframework"]["csrf"]["csrf"]) && - isset ($_SESSION["domframework"]["csrf"]["csrfStart"])) + /** Get / Set the name of the field in HTML + * @param string|null $val The value to set/get if null + */ + public function field($val = null) { - $_SESSION["domframework"]["csrf"] = array ( - $_SESSION["domframework"]["csrf"]["csrf"] => - $_SESSION["domframework"]["csrf"]["csrfStart"] - ); - unset ($_SESSION["domframework"]["csrf"]["csrfStart"]); + if ($val === null) { + return $this->field; + } + $this->field = $val; + $GLOBALS["domframework"]["csrf"] = $this; + return $this; } - if (! isset ($_SESSION["domframework"]["csrf"])) - { - throw new \Exception (dgettext ("domframework", - "No previous CSRF token found in session ". - "(maybe a new session after expiration ?) : abort"), 406); - } - if (! key_exists ($tokenFromUser, $_SESSION["domframework"]["csrf"])) - { - throw new \Exception (dgettext ("domframework", - "Invalid CSRF token provided"), 406); - } - if (($_SESSION["domframework"]["csrf"][$tokenFromUser] + $this->csrfTimeout) - < microtime (TRUE)) - { - throw new \Exception (dgettext ("domframework", - "Obsolete CSRF token provided"), 406); - } - // Clean expired tokens (2 times the $this->csrfTimeout) - foreach ($_SESSION["domframework"]["csrf"] as $token => $timeout) - { - if ($timeout + 2 * $this->csrfTimeout < time ()) - unset ($_SESSION["domframework"]["csrf"][$token]); - } - return TRUE; - } - /** Return the CSRF token in a hidden field - */ - public function displayFormCSRF () - { - if ($this->csrfToken == "") - $this->createToken (); - $res = "csrfToken = $s; + $_SESSION["domframework"]["csrf"][$this->csrfToken] = microtime(true); + $GLOBALS["domframework"]["csrf"] = $this; + return $this->csrfToken; + } - /** Return the token if exists or create a new one if needed - */ - public function getToken () - { - if ($this->csrfToken === "") - $this->createToken (); - return $this->csrfToken; - } + /** Check if the provided token is the right token, defined last displayed + * page + * @param string $tokenFromUser The value csrf the user's token + */ + public function checkToken($tokenFromUser) + { + if ($this->csrf === false) { + return true; + } + // Migrate from unique format to multiple CSRF tokens format + // The new format is : array (token => the last used time) + if ( + isset($_SESSION["domframework"]["csrf"]["csrf"]) && + isset($_SESSION["domframework"]["csrf"]["csrfStart"]) + ) { + $_SESSION["domframework"]["csrf"] = array( + $_SESSION["domframework"]["csrf"]["csrf"] => + $_SESSION["domframework"]["csrf"]["csrfStart"] + ); + unset($_SESSION["domframework"]["csrf"]["csrfStart"]); + } + if (! isset($_SESSION["domframework"]["csrf"])) { + throw new \Exception(dgettext( + "domframework", + "No previous CSRF token found in session " . + "(maybe a new session after expiration ?) : abort" + ), 406); + } + if (! key_exists($tokenFromUser, $_SESSION["domframework"]["csrf"])) { + throw new \Exception(dgettext( + "domframework", + "Invalid CSRF token provided" + ), 406); + } + if ( + ($_SESSION["domframework"]["csrf"][$tokenFromUser] + $this->csrfTimeout) + < microtime(true) + ) { + throw new \Exception(dgettext( + "domframework", + "Obsolete CSRF token provided" + ), 406); + } + // Clean expired tokens (2 times the $this->csrfTimeout) + foreach ($_SESSION["domframework"]["csrf"] as $token => $timeout) { + if ($timeout + 2 * $this->csrfTimeout < time()) { + unset($_SESSION["domframework"]["csrf"][$token]); + } + } + return true; + } - /** Add more time to existing CSRF token - * @param string $tokenFromUser The existing token - */ - public function extendToken ($tokenFromUser) - { - $this->checkToken ($tokenFromUser); - $_SESSION["domframework"]["csrf"][$tokenFromUser] = microtime (TRUE); - return true; - } + /** Return the CSRF token in a hidden field + */ + public function displayFormCSRF() + { + if ($this->csrfToken == "") { + $this->createToken(); + } + $res = "checkToken ($tokenFromUser); - unset ($_SESSION["domframework"]["csrf"][$tokenFromUser]); - return true; - } + /** Return the token if exists or create a new one if needed + */ + public function getToken() + { + if ($this->csrfToken === "") { + $this->createToken(); + } + return $this->csrfToken; + } + + /** Add more time to existing CSRF token + * @param string $tokenFromUser The existing token + */ + public function extendToken($tokenFromUser) + { + $this->checkToken($tokenFromUser); + $_SESSION["domframework"]["csrf"][$tokenFromUser] = microtime(true); + return true; + } + + /** Check an existing token, then delete it + * @param string $tokenFromUser The existing token + */ + public function checkThenDeleteToken($tokenFromUser) + { + $this->checkToken($tokenFromUser); + unset($_SESSION["domframework"]["csrf"][$tokenFromUser]); + return true; + } } diff --git a/src/Daemon.php b/src/Daemon.php index 615e241..3a39368 100644 --- a/src/Daemon.php +++ b/src/Daemon.php @@ -1,4 +1,5 @@ @@ -12,166 +13,193 @@ namespace Domframework; */ class Daemon { - /** Set the directory to store the PID of the daemon - */ - private $runDir = "/var/run"; + /** Set the directory to store the PID of the daemon + */ + private $runDir = "/var/run"; - /** The constructor check if /proc is mounted - */ - public function __construct () - { - if (! file_exists ("/proc")) - throw new \Exception ("Can't manage daemon: /proc doesn't exists", 500); - } + /** The constructor check if /proc is mounted + */ + public function __construct() + { + if (! file_exists("/proc")) { + throw new \Exception("Can't manage daemon: /proc doesn't exists", 500); + } + } - /** Get/set the directory to store the PID of the daemon - * @param string|null $val The directory - */ - public function runDir ($val = null) - { - if ($val === null) - return $this->runDir; - if (! is_string ($val)) - throw new \Exception ("Can not set daemon runDir: not a string", 500); - $this->runDir = "$val"; - } + /** Get/set the directory to store the PID of the daemon + * @param string|null $val The directory + */ + public function runDir($val = null) + { + if ($val === null) { + return $this->runDir; + } + if (! is_string($val)) { + throw new \Exception("Can not set daemon runDir: not a string", 500); + } + $this->runDir = "$val"; + } - /** Start the callable method. The terminal is closed. All the displayed - * messages from the child are silently dropped. - * If some parameters are provided, the called child method will receive them - * This function fork and return the child PID - * @param string $name The name of daemon to start. - * @param callable $callable The callback method to use in child - * @param mixed|null $params The params to provide to child method - * @return The child PID - */ - public function start ($name, $callable, $params = array ()) - { - $file = new file (); - if (! $file->is_writeable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not writeable", - $this->runDir), 500); - if (! $file->is_readable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not readable", - $this->runDir), 500); - if ($file->file_exists ($this->runDir."/$name.pid")) + /** Start the callable method. The terminal is closed. All the displayed + * messages from the child are silently dropped. + * If some parameters are provided, the called child method will receive them + * This function fork and return the child PID + * @param string $name The name of daemon to start. + * @param callable $callable The callback method to use in child + * @param mixed|null $params The params to provide to child method + * @return The child PID + */ + public function start($name, $callable, $params = array()) { - $pid = trim ($file->file_get_contents ($this->runDir."/$name.pid")); - if (file_exists ("/proc/$pid")) - throw new \Exception (sprintf ( - "Can't start the daemon: already running with PID %d", $pid), 500); + $file = new file(); + if (! $file->is_writeable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not writeable", + $this->runDir + ), 500); + } + if (! $file->is_readable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not readable", + $this->runDir + ), 500); + } + if ($file->file_exists($this->runDir . "/$name.pid")) { + $pid = trim($file->file_get_contents($this->runDir . "/$name.pid")); + if (file_exists("/proc/$pid")) { + throw new \Exception(sprintf( + "Can't start the daemon: already running with PID %d", + $pid + ), 500); + } + } + $fork = new fork(); + $pid = $fork->startDetachedChild($name, $callable, $params); + file_put_contents($this->runDir . "/$name.pid", $pid); + return $pid; } - $fork = new fork (); - $pid = $fork->startDetachedChild ($name, $callable, $params); - file_put_contents ($this->runDir."/$name.pid", $pid); - return $pid; - } - /** Stop a $name daemon - * @param string $name The name of daemon to stop. The name must be the same - * as the name used in the start method - * @param integer $maxWaitStop The waiting maximum time after SIGTERM before - * sending SIGKILL - * @param integer $maxWaitKill The waiting maximum time after SIGKILL before - * raising an error - */ - public function stop ($name, $maxWaitStop = 3, $maxWaitKill = 3) - { - $file = new file (); - if (! $file->is_writeable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not writeable", - $this->runDir), 500); - if (! $file->is_readable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not readable", - $this->runDir), 500); - if (! $file->file_exists ($this->runDir."/$name.pid")) - throw new \Exception (sprintf ( - "PID file %s not found : can't stop the daemon", - $this->runDir."/$name.pid"), 500); - $pid = $file->file_get_contents ($this->runDir."/$name.pid"); - if (! file_exists ("/proc/$pid")) + /** Stop a $name daemon + * @param string $name The name of daemon to stop. The name must be the same + * as the name used in the start method + * @param integer $maxWaitStop The waiting maximum time after SIGTERM before + * sending SIGKILL + * @param integer $maxWaitKill The waiting maximum time after SIGKILL before + * raising an error + */ + public function stop($name, $maxWaitStop = 3, $maxWaitKill = 3) { - $file->unlink ($this->runDir."/$name.pid"); - throw new \Exception ( - "Can't stop daemon $name. There is no process with the PID $pid", - 500); + $file = new file(); + if (! $file->is_writeable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not writeable", + $this->runDir + ), 500); + } + if (! $file->is_readable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not readable", + $this->runDir + ), 500); + } + if (! $file->file_exists($this->runDir . "/$name.pid")) { + throw new \Exception(sprintf( + "PID file %s not found : can't stop the daemon", + $this->runDir . "/$name.pid" + ), 500); + } + $pid = $file->file_get_contents($this->runDir . "/$name.pid"); + if (! file_exists("/proc/$pid")) { + $file->unlink($this->runDir . "/$name.pid"); + throw new \Exception( + "Can't stop daemon $name. There is no process with the PID $pid", + 500 + ); + } + posix_kill($pid, SIGTERM); + usleep(10000); + $startWait = time(); + while (time() < $startWait + $maxWaitStop) { + // If the child is zombie and is connected to me, pcntl_waitpid allow it + // to be destroyed to close correctely the parent + pcntl_waitpid($pid, $status, WNOHANG); + if (! file_exists("/proc/$pid")) { + $file->unlink($this->runDir . "/$name.pid"); + return true; + } + usleep(100000); + echo "."; + } + posix_kill($pid, SIGKILL); + $startWait = time(); + while (time() < $startWait + $maxWaitKill) { + if (! file_exists("/proc/$pid")) { + $file->unlink($this->runDir . "/$name.pid"); + return true; + } + usleep(100000); + echo "X"; + } + throw new \Exception("Can't stop and can't kill the process $pid", 500); } - posix_kill ($pid, SIGTERM); - usleep (10000); - $startWait = time (); - while (time () < $startWait + $maxWaitStop) - { - // If the child is zombie and is connected to me, pcntl_waitpid allow it - // to be destroyed to close correctely the parent - pcntl_waitpid ($pid, $status, WNOHANG); - if (! file_exists ("/proc/$pid")) - { - $file->unlink ($this->runDir."/$name.pid"); - return true; - } - usleep (100000); - echo "."; - } - posix_kill ($pid, SIGKILL); - $startWait = time (); - while (time () < $startWait + $maxWaitKill) - { - if (! file_exists ("/proc/$pid")) - { - $file->unlink ($this->runDir."/$name.pid"); - return true; - } - usleep (100000); - echo "X"; - } - throw new \Exception ("Can't stop and can't kill the process $pid", 500); - } - /** Status of a daemon - * @param string $name The name of daemon to have status. The name must be - * the same as the name used in the start method - */ - public function status ($name) - { - $file = new file (); - if (! $file->is_writeable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not writeable", - $this->runDir), 500); - if (! $file->is_readable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not readable", - $this->runDir), 500); - if (! $file->file_exists ($this->runDir."/$name.pid")) - return "The daemon is be stopped"; - $pid = $file->file_get_contents ($this->runDir."/$name.pid"); - if (! file_exists ("/proc/$pid")) + /** Status of a daemon + * @param string $name The name of daemon to have status. The name must be + * the same as the name used in the start method + */ + public function status($name) { - $file->unlink ($this->runDir."/$name.pid"); - return "The daemon is stopped, but the PID file was remaining. Delete"; + $file = new file(); + if (! $file->is_writeable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not writeable", + $this->runDir + ), 500); + } + if (! $file->is_readable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not readable", + $this->runDir + ), 500); + } + if (! $file->file_exists($this->runDir . "/$name.pid")) { + return "The daemon is be stopped"; + } + $pid = $file->file_get_contents($this->runDir . "/$name.pid"); + if (! file_exists("/proc/$pid")) { + $file->unlink($this->runDir . "/$name.pid"); + return "The daemon is stopped, but the PID file was remaining. Delete"; + } + return "The daemon is running on PID $pid\n"; } - return "The daemon is running on PID $pid\n"; - } - /** Send a HUP Signal to the daemon - * @param string $name The name of daemon to HUP. The name must be - * the same as the name used in the start method - */ - public function reload ($name) - { - $file = new file (); - if (! $file->is_writeable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not writeable", - $this->runDir), 500); - if (! $file->is_readable ($this->runDir)) - throw new \Exception (sprintf ("Run Directory '%s' is not readable", - $this->runDir), 500); - if (! $file->file_exists ($this->runDir."/$name.pid")) - return "The daemon is be stopped"; - $pid = $file->file_get_contents ($this->runDir."/$name.pid"); - if (! file_exists ("/proc/$pid")) + /** Send a HUP Signal to the daemon + * @param string $name The name of daemon to HUP. The name must be + * the same as the name used in the start method + */ + public function reload($name) { - $file->unlink ($this->runDir."/$name.pid"); - return "The daemon is stopped, but the PID file was remaining. Delete"; + $file = new file(); + if (! $file->is_writeable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not writeable", + $this->runDir + ), 500); + } + if (! $file->is_readable($this->runDir)) { + throw new \Exception(sprintf( + "Run Directory '%s' is not readable", + $this->runDir + ), 500); + } + if (! $file->file_exists($this->runDir . "/$name.pid")) { + return "The daemon is be stopped"; + } + $pid = $file->file_get_contents($this->runDir . "/$name.pid"); + if (! file_exists("/proc/$pid")) { + $file->unlink($this->runDir . "/$name.pid"); + return "The daemon is stopped, but the PID file was remaining. Delete"; + } + return posix_kill($pid, SIGHUP); } - return posix_kill ($pid, SIGHUP); - } } diff --git a/src/Dbjson.php b/src/Dbjson.php index b7bfa06..03a1f69 100644 --- a/src/Dbjson.php +++ b/src/Dbjson.php @@ -1,4 +1,5 @@ @@ -23,416 +24,457 @@ namespace Domframework; */ class Dbjson { - /** The DSN of the connection */ - private $dsn = ""; - /** The database file */ - private $dbfile = ""; - /** The lock file */ - private $dbfileLock = ""; - /** The last Insert Id */ - private $lastInsertId = 0; - /** The database content */ - private $db; + /** The DSN of the connection */ + private $dsn = ""; + /** The database file */ + private $dbfile = ""; + /** The lock file */ + private $dbfileLock = ""; + /** The last Insert Id */ + private $lastInsertId = 0; + /** The database content */ + private $db; - /** The constructor - * @param string $dsn The DSN of the connection - */ - public function __construct ($dsn) - { - if (! function_exists ("openssl_random_pseudo_bytes")) - throw new \Exception ("Function openssl_random_pseudo_bytes missing", - 500); - $pos = strpos ($dsn, "://"); - if ($pos === false) - throw new \Exception (dgettext ("domframework", - "No DSN provided to dbjson"), 500); - if (substr ($dsn, 0, $pos) !== "dbjson") - throw new \Exception (dgettext ("domframework", - "Invalid database type provided in dbjson"), 500); - $this->dbfile = substr ($dsn, $pos+3); - $directory = dirname ($this->dbfile); - if (! file_exists ($directory)) - @mkdir ($directory, 0777, true); - if (! file_exists ($directory)) - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' doesn't exists"), $directory), 500); - if (! file_exists ($this->dbfile)) + /** The constructor + * @param string $dsn The DSN of the connection + */ + public function __construct($dsn) { - if (! is_readable ($directory)) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Directory '%s' not writeable and dbfile '%s' not exists"), - $directory, $this->dbfile), 500); - touch ($this->dbfile); - } - if (! is_readable ($this->dbfile)) - throw new \Exception(sprintf (dgettext ("domframework", - "File '%s' not readable"), $this->dbfile), 500); - if (! is_writeable ($this->dbfile)) - throw new \Exception(sprintf (dgettext ("domframework", - "File '%s' not readable"), $this->dbfile), 500); - $this->dsn = $dsn; - $this->dbfile = $this->dbfile; - } - - /** Store one document in database - * @param string $collection The collection name - * @param array $document The document to insert - * @return integer return The number of document inserted in the database - */ - public function insertOne ($collection, $document) - { - $uniqueKey = $this->uniqueKey (); - $this->lockEX (); - $this->db = $this->readDB (); - $this->db[$collection]["content"][$uniqueKey] = array_merge ( - array ("_id"=>$uniqueKey), - $document); - $this->writeDB (); - $this->lockUN (); - return 1; - } - - /** Store multiple documents in database - * @param string $collection The collection name - * @param array $documents array(array ()) - * @return integer The number of documents inserted in the database - */ - public function insertMany ($collection, $documents) - { - foreach ($documents as $document) - if (! is_array ($document)) - throw new \Exception ("insertMany need an array of array", 406); - $this->lockEX (); - $this->db = $this->readDB (); - foreach ($documents as $document) - { - $uniqueKey = $this->uniqueKey (); - $this->db[$collection]["content"][$uniqueKey] = array_merge ( - array ("_id"=>$uniqueKey), - $document); - } - $this->writeDB (); - $this->db = null; - $this->lockUN (); - return count ($documents); - } - - /** Look at the documents matching $filter (all by default). - * Then return only the $fields (all by default). - * The field _id is always returned - * Return $limit maximum documents (no limit by default) - * @param string $collection The collection name - * @param array $filter The filter to apply to found the documents - * @param array|string $fields The fields to display (* for all, empty array - * for none) - * @param integer $limit The number of documents to display - * @return array The documents matching the parameters - */ - public function find ($collection, $filter = array (), $fields = "*", - $limit = null) - { - $this->lockSH (); - $this->db = $this->readDB (); - // Get the keys of the documents based on the filter - $keys = $this->filter ($collection, $filter); - $res = array (); - foreach ($keys as $key) - { - // Limit the fields - $tmp = array (); - if ($fields === "*") - $tmp = $this->db[$collection]["content"][$key]; - elseif (is_array ($fields)) - { - if (! in_array ("_id", $fields)) - array_unshift ($fields, "_id"); - foreach ($fields as $field) - { - if (array_key_exists ($field, - $this->db[$collection]["content"][$key])) - $tmp[$field] = $this->db[$collection]["content"][$key][$field]; + if (! function_exists("openssl_random_pseudo_bytes")) { + throw new \Exception( + "Function openssl_random_pseudo_bytes missing", + 500 + ); } - } - else - throw new \Exception ("Invalid field list provided", 500); - $res[$key] = $tmp; - // Limit the number of results - if ($limit !== null && count ($res) >= $limit) - break; - } - $this->lockUN (); - $this->db = null; - return $res; - } - - /** Update some existing documents. Do not change the _id keys - * @param string $collection The collection name - * @param array $filter The filter to apply to found the documents - * @param array $document The data to update - * @return integer The number of modified documents - * To unset a field, add in the document array a "_unset"=>array("field)" - */ - public function update ($collection, $filter, $document) - { - $this->lockEX (); - $this->db = $this->readDB (); - // Get the keys of the documents based on the filter - $keys = $this->filter ($collection, $filter); - $unset = array (); - if (array_key_exists ("_unset", $document)) - { - $unset = $document["_unset"]; - unset ($document["_unset"]); - } - foreach ($keys as $key) - { - // Merge the new document with the old - $tmp = $this->db[$collection]["content"][$key]; - // We need to merge the old and the new document. - // If there is an array in the document, it is overwrited - foreach ($document as $k=>$v) - { - if (is_array ($v)) - { - if (isset ($tmp[$k])) - $tmp[$k] = array_merge ($tmp[$k], $v); - else - $tmp[$k] = $v; + $pos = strpos($dsn, "://"); + if ($pos === false) { + throw new \Exception(dgettext( + "domframework", + "No DSN provided to dbjson" + ), 500); } - else - { - $tmp[$k] = $v; + if (substr($dsn, 0, $pos) !== "dbjson") { + throw new \Exception(dgettext( + "domframework", + "Invalid database type provided in dbjson" + ), 500); } - } - $this->db[$collection]["content"][$key] = $tmp; - // Remove the needed unset fields - foreach ($unset as $field) - if (array_key_exists ($field, - $this->db[$collection]["content"][$key])) - unset ($this->db[$collection]["content"][$key][$field]); - } - $this->writeDB (); - $this->lockUN (); - $this->db = null; - return count ($keys); - } - - /** Replace some existing documents. Do not change the _id keys - * @param string $collection The collection name - * @param array $filter The filter to apply to found the documents - * @param array $document The data to update - * @return integer The number of modified documents - */ - public function replace ($collection, $filter, $document) - { - $this->lockEX (); - $this->db = $this->readDB (); - // Get the keys of the documents based on the filter - $keys = $this->filter ($collection, $filter); - foreach ($keys as $key) - { - $tmp = $this->db[$collection]["content"][$key]; - $replace = array (); - $replace["_id"] = $tmp["_id"]; - $replace = array_merge ($replace, $document); - $this->db[$collection]["content"][$key] = $replace; - } - $this->writeDB (); - $this->lockUN (); - $this->db = null; - return count ($keys); - } - - /** Delete the first document matching the filter - * @param string $collection The collection name - * @param array $filter The filter to found the documents - * @return integer The number of deleted documents - */ - public function deleteOne ($collection, $filter) - { - $this->lockEX (); - $this->db = $this->readDB (); - // Get the keys of the documents based on the filter - $keys = $this->filter ($collection, $filter); - if (count ($keys) === 0) - return 0; - reset ($keys); - $key = reset ($keys); - unset ($this->db[$collection]["content"][$key]); - $this->writeDB (); - $this->lockUN (); - $this->db = null; - return 1; - - } - - /** Delete all the documents matching the filter - * @param string $collection The collection name - * @param array $filter The filter to apply to found the documents - * @return integer The number of deleted documents - */ - public function deleteMany ($collection, $filter) - { - $this->lockEX (); - $this->db = $this->readDB (); - // Get the keys of the documents based on the filter - $keys = $this->filter ($collection, $filter); - foreach ($keys as $key) - unset ($this->db[$collection]["content"][$key]); - $this->writeDB (); - $this->lockUN (); - $this->db = null; - return count ($keys); - } - - /** Look for the keys corresponding to the filter in the collection - * Don't manage the locks ! - * @param string $collection The collection name - * @param array $filter The filter to apply to found the documents - * - A filter is an array containing the fields and the values to found - * array () <== Look for all the documents (no - * filter) - * array ("key"=>"val") <== Look for the key equal val - * array ("key=>array ("val", "<=")) <== Look for the key lighter or - * equal than val - * array ("key"=>"val", "key2"=>"val2") <== Look for two parameters - * array ("key"=>array ("val", "=="), - * "key2"=>array ("val2", "==")) <== Look for two complex parameters - * Here is the comparison types available : ==, - * @return array the keys matching the filter - */ - public function filter ($collection, $filter) - { - if ($this->db === null) - $this->db = $this->readDB (); - $keys = array (); - if (! array_key_exists ($collection, $this->db)) - $this->db[$collection]["content"] = array (); - foreach ($this->db[$collection]["content"] as $key=>$document) - { - if ($filter === array ()) - { - $keys[] = $key; - continue; - } - $matchFilter = false; - foreach ($filter as $fkey=>$fvals) - { - if (is_array ($fvals)) - { - // $fvals = array ("key=>array ("val", "<=")) - if (array_key_exists ($fkey, $document)) - { - if ($fvals[1] !== "==" && - $fvals[1] !== "<=" && - $fvals[1] !== ">=" && - $fvals[1] !== "<" && - $fvals[1] !== ">" && - $fvals[1] !== "exists" && - $fvals[1] !== "not exists" && - $fvals[1] !== "in_array") - throw new \Exception ("Invalid filter operator provided", 500); - if ($fvals[1] === "==" && $document[$fkey] === $fvals[0]) - $matchFilter = true; - elseif ($fvals[1] === "<=" && $document[$fkey] <= $fvals[0]) - $matchFilter = true; - elseif ($fvals[1] === ">=" && $document[$fkey] >= $fvals[0]) - $matchFilter = true; - elseif ($fvals[1] === "<" && $document[$fkey] < $fvals[0]) - $matchFilter = true; - elseif ($fvals[1] === ">" && $document[$fkey] > $fvals[0]) - $matchFilter = true; - elseif (strtolower ($fvals[1]) === "exists" && - array_key_exists ($fkey, $document)) - $matchFilter = true; - elseif (strtolower ($fvals[1]) === "not exists" && - ! array_key_exists ($fkey, $document)) - $matchFilter = true; - elseif (strtolower ($fvals[1]) === "in_array" && - in_array ($fvals[0], $document[$fkey])) - $matchFilter = true; - else - { - $matchFilter = false; - break; + $this->dbfile = substr($dsn, $pos + 3); + $directory = dirname($this->dbfile); + if (! file_exists($directory)) { + @mkdir($directory, 0777, true); + } + if (! file_exists($directory)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Directory '%s' doesn't exists" + ), $directory), 500); + } + if (! file_exists($this->dbfile)) { + if (! is_readable($directory)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' not writeable and dbfile '%s' not exists" + ), + $directory, + $this->dbfile + ), 500); } - } + touch($this->dbfile); } - else - { - // $fvals = array ("key"=>"val") - if (array_key_exists ($fkey, $document) && - $document[$fkey] === $fvals) - $matchFilter = true; - else - { - $matchFilter = false; - break; - } + if (! is_readable($this->dbfile)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "File '%s' not readable" + ), $this->dbfile), 500); } - } - if ($matchFilter === true) - $keys[] = $key; + if (! is_writeable($this->dbfile)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "File '%s' not readable" + ), $this->dbfile), 500); + } + $this->dsn = $dsn; + $this->dbfile = $this->dbfile; } - return $keys; - } - /** Generate a unique key - * @return string the Unique key generated - */ - private function uniqueKey () - { - $data = openssl_random_pseudo_bytes(16); - $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 - $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 - return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); - } - - /** Exclusive lock the database file */ - private function lockEX () - { - $this->dbfileLock = fopen ($this->dbfile, "rt"); - if (flock ($this->dbfileLock, LOCK_EX) === false) - throw new \Exception ("Can't get exclusive lock on dbfile", 500); - } - - /** Shared lock the database file */ - private function lockSH () - { - $this->dbfileLock = fopen ($this->dbfile, "rt"); - if (flock ($this->dbfileLock, LOCK_SH) === false) - throw new \Exception ("Can't get shared lock on dbfile", 500); - } - - /** Unlock the database file */ - private function lockUN () - { - if ($this->dbfileLock !== null) + /** Store one document in database + * @param string $collection The collection name + * @param array $document The document to insert + * @return integer return The number of document inserted in the database + */ + public function insertOne($collection, $document) { - flock ($this->dbfileLock, LOCK_UN); - fclose ($this->dbfileLock); - $this->dbfileLock = null; + $uniqueKey = $this->uniqueKey(); + $this->lockEX(); + $this->db = $this->readDB(); + $this->db[$collection]["content"][$uniqueKey] = array_merge( + array("_id" => $uniqueKey), + $document + ); + $this->writeDB(); + $this->lockUN(); + return 1; } - } - /** Read the dbfile and return an array containing the data. This function - * don't do locks ! - * @return array The database content from the dbfile - */ - private function readDB () - { - $res = json_decode (file_get_contents ($this->dbfile), true); - if ($res === null) - $res = array (); - return $res; - } + /** Store multiple documents in database + * @param string $collection The collection name + * @param array $documents array(array ()) + * @return integer The number of documents inserted in the database + */ + public function insertMany($collection, $documents) + { + foreach ($documents as $document) { + if (! is_array($document)) { + throw new \Exception("insertMany need an array of array", 406); + } + } + $this->lockEX(); + $this->db = $this->readDB(); + foreach ($documents as $document) { + $uniqueKey = $this->uniqueKey(); + $this->db[$collection]["content"][$uniqueKey] = array_merge( + array("_id" => $uniqueKey), + $document + ); + } + $this->writeDB(); + $this->db = null; + $this->lockUN(); + return count($documents); + } - /** Write the dbfile with the provided data. This function don't do locks ! - * @return bool True if the recording is OK, false if there is a problem - */ - private function writeDB () - { - return !! file_put_contents ($this->dbfile, json_encode ($this->db)); - } + /** Look at the documents matching $filter (all by default). + * Then return only the $fields (all by default). + * The field _id is always returned + * Return $limit maximum documents (no limit by default) + * @param string $collection The collection name + * @param array $filter The filter to apply to found the documents + * @param array|string $fields The fields to display (* for all, empty array + * for none) + * @param integer $limit The number of documents to display + * @return array The documents matching the parameters + */ + public function find( + $collection, + $filter = array(), + $fields = "*", + $limit = null + ) { + $this->lockSH(); + $this->db = $this->readDB(); + // Get the keys of the documents based on the filter + $keys = $this->filter($collection, $filter); + $res = array(); + foreach ($keys as $key) { + // Limit the fields + $tmp = array(); + if ($fields === "*") { + $tmp = $this->db[$collection]["content"][$key]; + } elseif (is_array($fields)) { + if (! in_array("_id", $fields)) { + array_unshift($fields, "_id"); + } + foreach ($fields as $field) { + if ( + array_key_exists( + $field, + $this->db[$collection]["content"][$key] + ) + ) { + $tmp[$field] = $this->db[$collection]["content"][$key][$field]; + } + } + } else { + throw new \Exception("Invalid field list provided", 500); + } + $res[$key] = $tmp; + // Limit the number of results + if ($limit !== null && count($res) >= $limit) { + break; + } + } + $this->lockUN(); + $this->db = null; + return $res; + } + + /** Update some existing documents. Do not change the _id keys + * @param string $collection The collection name + * @param array $filter The filter to apply to found the documents + * @param array $document The data to update + * @return integer The number of modified documents + * To unset a field, add in the document array a "_unset"=>array("field)" + */ + public function update($collection, $filter, $document) + { + $this->lockEX(); + $this->db = $this->readDB(); + // Get the keys of the documents based on the filter + $keys = $this->filter($collection, $filter); + $unset = array(); + if (array_key_exists("_unset", $document)) { + $unset = $document["_unset"]; + unset($document["_unset"]); + } + foreach ($keys as $key) { + // Merge the new document with the old + $tmp = $this->db[$collection]["content"][$key]; + // We need to merge the old and the new document. + // If there is an array in the document, it is overwrited + foreach ($document as $k => $v) { + if (is_array($v)) { + if (isset($tmp[$k])) { + $tmp[$k] = array_merge($tmp[$k], $v); + } else { + $tmp[$k] = $v; + } + } else { + $tmp[$k] = $v; + } + } + $this->db[$collection]["content"][$key] = $tmp; + // Remove the needed unset fields + foreach ($unset as $field) { + if ( + array_key_exists( + $field, + $this->db[$collection]["content"][$key] + ) + ) { + unset($this->db[$collection]["content"][$key][$field]); + } + } + } + $this->writeDB(); + $this->lockUN(); + $this->db = null; + return count($keys); + } + + /** Replace some existing documents. Do not change the _id keys + * @param string $collection The collection name + * @param array $filter The filter to apply to found the documents + * @param array $document The data to update + * @return integer The number of modified documents + */ + public function replace($collection, $filter, $document) + { + $this->lockEX(); + $this->db = $this->readDB(); + // Get the keys of the documents based on the filter + $keys = $this->filter($collection, $filter); + foreach ($keys as $key) { + $tmp = $this->db[$collection]["content"][$key]; + $replace = array(); + $replace["_id"] = $tmp["_id"]; + $replace = array_merge($replace, $document); + $this->db[$collection]["content"][$key] = $replace; + } + $this->writeDB(); + $this->lockUN(); + $this->db = null; + return count($keys); + } + + /** Delete the first document matching the filter + * @param string $collection The collection name + * @param array $filter The filter to found the documents + * @return integer The number of deleted documents + */ + public function deleteOne($collection, $filter) + { + $this->lockEX(); + $this->db = $this->readDB(); + // Get the keys of the documents based on the filter + $keys = $this->filter($collection, $filter); + if (count($keys) === 0) { + return 0; + } + reset($keys); + $key = reset($keys); + unset($this->db[$collection]["content"][$key]); + $this->writeDB(); + $this->lockUN(); + $this->db = null; + return 1; + } + + /** Delete all the documents matching the filter + * @param string $collection The collection name + * @param array $filter The filter to apply to found the documents + * @return integer The number of deleted documents + */ + public function deleteMany($collection, $filter) + { + $this->lockEX(); + $this->db = $this->readDB(); + // Get the keys of the documents based on the filter + $keys = $this->filter($collection, $filter); + foreach ($keys as $key) { + unset($this->db[$collection]["content"][$key]); + } + $this->writeDB(); + $this->lockUN(); + $this->db = null; + return count($keys); + } + + /** Look for the keys corresponding to the filter in the collection + * Don't manage the locks ! + * @param string $collection The collection name + * @param array $filter The filter to apply to found the documents + * - A filter is an array containing the fields and the values to found + * array () <== Look for all the documents (no + * filter) + * array ("key"=>"val") <== Look for the key equal val + * array ("key=>array ("val", "<=")) <== Look for the key lighter or + * equal than val + * array ("key"=>"val", "key2"=>"val2") <== Look for two parameters + * array ("key"=>array ("val", "=="), + * "key2"=>array ("val2", "==")) <== Look for two complex parameters + * Here is the comparison types available : ==, + * @return array the keys matching the filter + */ + public function filter($collection, $filter) + { + if ($this->db === null) { + $this->db = $this->readDB(); + } + $keys = array(); + if (! array_key_exists($collection, $this->db)) { + $this->db[$collection]["content"] = array(); + } + foreach ($this->db[$collection]["content"] as $key => $document) { + if ($filter === array()) { + $keys[] = $key; + continue; + } + $matchFilter = false; + foreach ($filter as $fkey => $fvals) { + if (is_array($fvals)) { + // $fvals = array ("key=>array ("val", "<=")) + if (array_key_exists($fkey, $document)) { + if ( + $fvals[1] !== "==" && + $fvals[1] !== "<=" && + $fvals[1] !== ">=" && + $fvals[1] !== "<" && + $fvals[1] !== ">" && + $fvals[1] !== "exists" && + $fvals[1] !== "not exists" && + $fvals[1] !== "in_array" + ) { + throw new \Exception("Invalid filter operator provided", 500); + } + if ($fvals[1] === "==" && $document[$fkey] === $fvals[0]) { + $matchFilter = true; + } elseif ($fvals[1] === "<=" && $document[$fkey] <= $fvals[0]) { + $matchFilter = true; + } elseif ($fvals[1] === ">=" && $document[$fkey] >= $fvals[0]) { + $matchFilter = true; + } elseif ($fvals[1] === "<" && $document[$fkey] < $fvals[0]) { + $matchFilter = true; + } elseif ($fvals[1] === ">" && $document[$fkey] > $fvals[0]) { + $matchFilter = true; + } elseif ( + strtolower($fvals[1]) === "exists" && + array_key_exists($fkey, $document) + ) { + $matchFilter = true; + } elseif ( + strtolower($fvals[1]) === "not exists" && + ! array_key_exists($fkey, $document) + ) { + $matchFilter = true; + } elseif ( + strtolower($fvals[1]) === "in_array" && + in_array($fvals[0], $document[$fkey]) + ) { + $matchFilter = true; + } else { + $matchFilter = false; + break; + } + } + } else { + // $fvals = array ("key"=>"val") + if ( + array_key_exists($fkey, $document) && + $document[$fkey] === $fvals + ) { + $matchFilter = true; + } else { + $matchFilter = false; + break; + } + } + } + if ($matchFilter === true) { + $keys[] = $key; + } + } + return $keys; + } + + /** Generate a unique key + * @return string the Unique key generated + */ + private function uniqueKey() + { + $data = openssl_random_pseudo_bytes(16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + } + + /** Exclusive lock the database file */ + private function lockEX() + { + $this->dbfileLock = fopen($this->dbfile, "rt"); + if (flock($this->dbfileLock, LOCK_EX) === false) { + throw new \Exception("Can't get exclusive lock on dbfile", 500); + } + } + + /** Shared lock the database file */ + private function lockSH() + { + $this->dbfileLock = fopen($this->dbfile, "rt"); + if (flock($this->dbfileLock, LOCK_SH) === false) { + throw new \Exception("Can't get shared lock on dbfile", 500); + } + } + + /** Unlock the database file */ + private function lockUN() + { + if ($this->dbfileLock !== null) { + flock($this->dbfileLock, LOCK_UN); + fclose($this->dbfileLock); + $this->dbfileLock = null; + } + } + + /** Read the dbfile and return an array containing the data. This function + * don't do locks ! + * @return array The database content from the dbfile + */ + private function readDB() + { + $res = json_decode(file_get_contents($this->dbfile), true); + if ($res === null) { + $res = array(); + } + return $res; + } + + /** Write the dbfile with the provided data. This function don't do locks ! + * @return bool True if the recording is OK, false if there is a problem + */ + private function writeDB() + { + return !! file_put_contents($this->dbfile, json_encode($this->db)); + } } diff --git a/src/Dblayer.php b/src/Dblayer.php index 28c269c..443db7a 100644 --- a/src/Dblayer.php +++ b/src/Dblayer.php @@ -1,4 +1,5 @@ @@ -40,1604 +41,1882 @@ Optionnaly, you can add the /** Permit abstraction on the differents SQL databases available */ class Dblayer { - /** The table name to use */ - public $table = null; - /** The tableprefix text to prepend to table name (Should finish by _) - Just allow chars ! */ - public $tableprefix = ""; - /** The fields with the definition of type, and special parameters */ - public $fields = array (); - /** The primary field */ - public $primary = null; - /** An array to define the unique fields (or array of unique fields) */ - public $unique = null; - /** An array to define the foreign keys of the field */ - public $foreign = array (); - /** Debug of the SQL */ - public $debug = FALSE; - /** The connecting DSN */ - private $dsn = null; - /** The field group delimiter */ - private $sep = ""; - /** Titles */ - public $titles = array (); + /** The table name to use */ + public $table = null; + /** The tableprefix text to prepend to table name (Should finish by _) + Just allow chars ! */ + public $tableprefix = ""; + /** The fields with the definition of type, and special parameters */ + public $fields = array(); + /** The primary field */ + public $primary = null; + /** An array to define the unique fields (or array of unique fields) */ + public $unique = null; + /** An array to define the foreign keys of the field */ + public $foreign = array(); + /** Debug of the SQL */ + public $debug = false; + /** The connecting DSN */ + private $dsn = null; + /** The field group delimiter */ + private $sep = ""; + /** Titles */ + public $titles = array(); - /** Define the name of the method to use to verify each entry */ - public $verifyOneFunc; - /** Define the name of the method to use to verify all entries */ - public $verifyAllFunc; - /** Define the name of the method of hook before read */ - public $hookprereadFunc; - /** Define the name of the method of hook after read */ - public $hookpostreadFunc; - /** Define the name of the method of hook before insert */ - public $hookpreinsertFunc; - /** Define the name of the method of hook after insert */ - public $hookpostinsertFunc; - /** Define the name of the method of hook before update */ - public $hookpreupdateFunc; - /** Define the name of the method of hook after update */ - public $hookpostupdateFunc; - /** Define the name of the method of hook before delete */ - public $hookpredeleteFunc; - /** Define the name of the method of hook after delete */ - public $hookpostdeleteFunc; + /** Define the name of the method to use to verify each entry */ + public $verifyOneFunc; + /** Define the name of the method to use to verify all entries */ + public $verifyAllFunc; + /** Define the name of the method of hook before read */ + public $hookprereadFunc; + /** Define the name of the method of hook after read */ + public $hookpostreadFunc; + /** Define the name of the method of hook before insert */ + public $hookpreinsertFunc; + /** Define the name of the method of hook after insert */ + public $hookpostinsertFunc; + /** Define the name of the method of hook before update */ + public $hookpreupdateFunc; + /** Define the name of the method of hook after update */ + public $hookpostupdateFunc; + /** Define the name of the method of hook before delete */ + public $hookpredeleteFunc; + /** Define the name of the method of hook after delete */ + public $hookpostdeleteFunc; - /** The verify unitary stack - @param string $field The name of the field to test - @param string $val The value of the field to test */ - public function verifyOne ($field, $val) {} - /** The verify global stack - @param array $data The associative array of contents */ - public function verifyAll ($data) {} - - // 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 - SQLite3 : PRAGMA TABLE_INFO('yourtable'); - MYSQL : SHOW COLUMNS FROM yourtable;*/ - - // TODO !! - /** Allow to modify tables if the definition is changed - Attention : SQLite don't supports adding Foreign keys without deleting all - the table, and re-import the data (http://www.sqlite.org/omitted.html) */ - - /** Limit to one instance of the connection to the same database */ - // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ - private static $instance = array (); - - /** - * Connection to the database engine - * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format - * @param string $dsn PDO Data Source Name - * @param string|null $username Username to connect - * @param string|null $password Password to connect - * @param string|null $driver_options Driver options to the database - */ - public function __construct ($dsn, $username=null, $password=null, - $driver_options=null) - { - $this->verifyOneFunc = array ($this, "verifyOne"); - $this->verifyAllFunc = array ($this, "verifyAll"); - $this->hookprereadFunc = array ($this, "hookpreread"); - $this->hookpostreadFunc = array ($this, "hookpostread"); - $this->hookpreinsertFunc = array ($this, "hookpreinsert"); - $this->hookpostinsertFunc = array ($this, "hookpostinsert"); - $this->hookpreupdateFunc = array ($this, "hookpreupdate"); - $this->hookpostupdateFunc = array ($this, "hookpostupdate"); - $this->hookpredeleteFunc = array ($this, "hookpredelete"); - $this->hookpostdeleteFunc = array ($this, "hookpostdelete"); - - $driver = @explode (":", $dsn); - if (! isset ($driver[0])) - throw new \Exception (dgettext ("domframework", "No valid DSN provided"), - 500); - if (! in_array ($driver[0], pdo_drivers ())) - throw new \Exception (sprintf (dgettext ("domframework", - "Driver PDO '%s' not available in PHP"), - $driver[0]), 500); - // Force specifics initialisations - $this->dsn = $dsn; - switch ($driver[0]) + /** The verify unitary stack + @param string $field The name of the field to test + @param string $val The value of the field to test */ + public function verifyOne($field, $val) { - case "sqlite": - // Look at the right to write in database and in the directory - $file = substr ($dsn, 7); - if (! is_writeable (dirname ($file))) - throw new \Exception (dgettext ("domframework", - "The directory for SQLite database is write protected"), - 500); - if (file_exists ($file) && ! is_writeable ($file)) - throw new \Exception (dgettext ("domframework", - "The SQLite database file is write protected"), - 500); - if (function_exists ("posix_getuid") && - file_exists ($file) && - fileowner ($file) === posix_getuid ()) - chmod ($file, 0666); + } + /** The verify global stack + @param array $data The associative array of contents */ + public function verifyAll($data) + { + } + + // 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 + SQLite3 : PRAGMA TABLE_INFO('yourtable'); + MYSQL : SHOW COLUMNS FROM yourtable;*/ + + // TODO !! + /** Allow to modify tables if the definition is changed + Attention : SQLite don't supports adding Foreign keys without deleting all + the table, and re-import the data (http://www.sqlite.org/omitted.html) */ + + /** Limit to one instance of the connection to the same database */ + // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ + private static $instance = array(); + + /** + * Connection to the database engine + * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format + * @param string $dsn PDO Data Source Name + * @param string|null $username Username to connect + * @param string|null $password Password to connect + * @param string|null $driver_options Driver options to the database + */ + public function __construct( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + $this->verifyOneFunc = array($this, "verifyOne"); + $this->verifyAllFunc = array($this, "verifyAll"); + $this->hookprereadFunc = array($this, "hookpreread"); + $this->hookpostreadFunc = array($this, "hookpostread"); + $this->hookpreinsertFunc = array($this, "hookpreinsert"); + $this->hookpostinsertFunc = array($this, "hookpostinsert"); + $this->hookpreupdateFunc = array($this, "hookpreupdate"); + $this->hookpostupdateFunc = array($this, "hookpostupdate"); + $this->hookpredeleteFunc = array($this, "hookpredelete"); + $this->hookpostdeleteFunc = array($this, "hookpostdelete"); + + $driver = @explode(":", $dsn); + if (! isset($driver[0])) { + throw new \Exception( + dgettext("domframework", "No valid DSN provided"), + 500 + ); + } + if (! in_array($driver[0], pdo_drivers())) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Driver PDO '%s' not available in PHP" + ), + $driver[0] + ), 500); + } + // Force specifics initialisations + $this->dsn = $dsn; + switch ($driver[0]) { + case "sqlite": + // Look at the right to write in database and in the directory + $file = substr($dsn, 7); + if (! is_writeable(dirname($file))) { + throw new \Exception( + dgettext( + "domframework", + "The directory for SQLite database is write protected" + ), + 500 + ); + } + if (file_exists($file) && ! is_writeable($file)) { + throw new \Exception( + dgettext( + "domframework", + "The SQLite database file is write protected" + ), + 500 + ); + } + if ( + function_exists("posix_getuid") && + file_exists($file) && + fileowner($file) === posix_getuid() + ) { + chmod($file, 0666); + } // Print the instances of PDO objects stored : // var_dump (self::$instance); - if (! array_key_exists ($this->dsn, self::$instance)) - { - if ($this->debug) echo "CONNECT TO DATABASE\n"; - try - { - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); - } - catch (\Exception $e) - { - throw new \Exception ("PDO error : ".$e->getMessage(), 500); - } - } + if (! array_key_exists($this->dsn, self::$instance)) { + if ($this->debug) { + echo "CONNECT TO DATABASE\n"; + } + try { + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + throw new \Exception("PDO error : " . $e->getMessage(), 500); + } + } // Force ForeignKeys support (disabled by default) - self::$instance[$this->dsn]->exec ("PRAGMA foreign_keys = ON"); - $this->sep = "`"; - break; - case "mysql": - if (! array_key_exists ($this->dsn, self::$instance)) - { - if ($this->debug) echo "CONNECT TO DATABASE\n"; - try - { - $driver_options[\PDO::MYSQL_ATTR_FOUND_ROWS] = 1; - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); - } - catch (\Exception $e) - { - throw new \Exception ("PDO error : ".$e->getMessage(), 500); - } - } + self::$instance[$this->dsn]->exec("PRAGMA foreign_keys = ON"); + $this->sep = "`"; + break; + case "mysql": + if (! array_key_exists($this->dsn, self::$instance)) { + if ($this->debug) { + echo "CONNECT TO DATABASE\n"; + } + try { + $driver_options[\PDO::MYSQL_ATTR_FOUND_ROWS] = 1; + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + throw new \Exception("PDO error : " . $e->getMessage(), 500); + } + } - // Set the coding to UTF8 - self::$instance[$this->dsn]->exec ("SET CHARACTER SET utf8"); - $this->sep = "`"; - break; - case "pgsql": - if (! array_key_exists ($this->dsn, self::$instance)) - { - if ($this->debug) echo "CONNECT TO DATABASE\n"; - try - { - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); - } - catch (\Exception $e) - { - throw new \Exception ("PDO error : ".$e->getMessage(), 500); - } - } + // Set the coding to UTF8 + self::$instance[$this->dsn]->exec("SET CHARACTER SET utf8"); + $this->sep = "`"; + break; + case "pgsql": + if (! array_key_exists($this->dsn, self::$instance)) { + if ($this->debug) { + echo "CONNECT TO DATABASE\n"; + } + try { + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + throw new \Exception("PDO error : " . $e->getMessage(), 500); + } + } - // Set the coding to UTF8 - self::$instance[$this->dsn]->exec ("SET NAMES 'utf8'"); - $this->sep = "\""; - break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown PDO driver provided"), 500); + // Set the coding to UTF8 + self::$instance[$this->dsn]->exec("SET NAMES 'utf8'"); + $this->sep = "\""; + break; + default: + throw new \Exception(dgettext( + "domframework", + "Unknown PDO driver provided" + ), 500); + } + return self::$instance[$this->dsn]; } - return self::$instance[$this->dsn]; - } - /** - * Return the connected database name from DSN used to connect - */ - public function databasename () - { - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - $vals = explode (";", substr (strstr ($this->dsn, ":"), 1)); - $dsnExplode = array (); - foreach ($vals as $val) + /** + * Return the connected database name from DSN used to connect + */ + public function databasename() { - @list ($k, $v) = explode ("=", $val); - $dsnExplode[$k] = $v; + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + $vals = explode(";", substr(strstr($this->dsn, ":"), 1)); + $dsnExplode = array(); + foreach ($vals as $val) { + @list($k, $v) = explode("=", $val); + $dsnExplode[$k] = $v; + } + if (isset($dsnExplode["dbname"])) { + return $dsnExplode["dbname"]; + } + return null; } - if (isset ($dsnExplode["dbname"])) - return $dsnExplode["dbname"]; - return NULL; - } - /** - * Return all the tables available in the database - */ - public function listTables () - { - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) + /** + * Return all the tables available in the database + */ + public function listTables() { - case "sqlite": - $req = "SELECT name FROM sqlite_master WHERE type='table'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d["name"]; - break; - case "mysql": - $req = "SELECT TABLE_NAME + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + case "sqlite": + $req = "SELECT name FROM sqlite_master WHERE type='table'"; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d["name"]; + } + break; + case "mysql": + $req = "SELECT TABLE_NAME FROM information_schema.tables - WHERE TABLE_SCHEMA='".$this->databasename()."'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d["TABLE_NAME"]; - break; - case "pgsql": - $req = "SELECT * + WHERE TABLE_SCHEMA='" . $this->databasename() . "'"; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d["TABLE_NAME"]; + } + break; + case "pgsql": + $req = "SELECT * FROM pg_tables WHERE schemaname = 'public'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d["tablename"]; - break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown database driver in listTables"), 500); - } - return $res; - } - - /** - * Verify if the provided data can be inserted/updated in the database. - * @param array $data An array containing the data to verify with keys - * @param mixed|null $updatekey the key to update - * @return array an array with the errors in array($key=>array($priority,$message)) - */ - public function verify ($data, $updatekey=false) - { - if ($this->debug) echo "== Entering verify\n"; - $errors = array (); - foreach ($this->fields as $key=>$params) - { - if ($this->debug) echo " verify ($key)\n"; - if ($updatekey === false) - { - // Don't check if there is an update : the database is already filled - // For autoincrement, in INSERT mode, force the value to null - if (in_array ("autoincrement", $params)) - $data[$key] = null; - if (in_array ("not null", $params) && !array_key_exists ($key, $data)) - { - $errors[$key] = array ("error", sprintf (dgettext ("domframework", - "Mandatory field '%s' not provided"), - $key)); - continue; - } - if (in_array ("not null", $params) && $data[$key] === "") - { - $errors[$key] = array ("error", sprintf (dgettext ("domframework", - "Mandatory field '%s' is empty"), - $key)); - continue; - } - } - - // Do not verify the non provided data (if they are not mandatory) - if (!array_key_exists ($key, $data)) - continue; - - // Verify the fields, if $verify is defined, before doing insertion - $verify = call_user_func ($this->verifyOneFunc, $key, $data[$key]); - if (is_array ($verify) && count ($verify)) - { - $errors[$key] = array ($verify[0], $verify[1]); - //." ". dgettext ("domframework","in")." ".$key); - continue; - } - - // Check for type inconsistencies if the value is provided - if (is_null ($data[$key])) - { - // Skipped the removed autoincrement keys - continue; - } - elseif (! is_string ($data[$key]) && ! is_integer ($data[$key])) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "Errors in consistency : '%s' is not an integer or a string [is %s]"), - $key, gettype ($data[$key]))); - continue; - } - elseif ($data[$key] !== "" && $params[0] === "integer") - { - if (strspn ($data[$key], "0123456789") !== strlen ($data[$key])) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "Errors in consistency : '%s' is not an integer"), - $key)); - continue; - } - } - elseif ($data[$key] !== "" && $params[0] === "varchar") - { - if (! isset ($params[1])) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "The length of varchar field '%s' is not provided"), - $key)); - continue; - } - if (mb_strlen ($data[$key]) > $params[1]) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "Errors in consistency : '%s' data is too long"), - $key)); - continue; - } - } - elseif ($data[$key] !== "" && $params[0] === "datetime") - { - // The date format must be in ANSI SQL : YYYY-MM-DD HH:MM:SS - $d = \DateTime::createFromFormat("Y-m-d H:i:s", $data[$key]); - if (!$d || $d->format("Y-m-d H:i:s") !== $data[$key]) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "Incorrect datetime provided for field '%s'"), - $key)); - continue; - } - } - elseif ($data[$key] !== "" && $params[0] === "date") - { - // The date format must be in ANSI SQL : YYYY-MM-DD - $d = \DateTime::createFromFormat("Y-m-d", $data[$key]); - if (!$d || $d->format("Y-m-d") !== $data[$key]) - { - $errors[$key] = array ("error", sprintf ( - dgettext ("domframework", - "Incorrect date provided for field '%s'"), - $key)); - continue; - } - } - elseif ($data[$key] !== "") - { - $errors[$key] = array ("error", sprintf (dgettext ("domframework", - "Unknown field type for '%s'"), $key)); - continue; - } - else - { - // Nothing to do if the value is empty : just save it - } - } - - if ($this->debug) echo " verify inconsistency\n"; - // Check for inconsistency - $verify = call_user_func ($this->verifyAllFunc, $data); - if (is_null ($verify)) - $verify = array (); - $allErrors = array_merge ($errors, $verify); - if (count ($allErrors)) - return $allErrors; - - $dataOK = array (); - foreach ($this->fields as $field=>$desc) - { - if (array_key_exists ($field, $data)) - $dataOK[$field] = $data[$field]; - } - - if ($updatekey !== false) - { - if ($this->debug) echo " verify in updatekey\n"; - // Check if the unique constrain is valid before doing the insertion - // 1. Read the actual state - $before = $this->read (array (array ($this->primary, $updatekey))); - if (count ($before) === 0) - return array ("error", dgettext ("domframework", - "Entry to modify unavailable")); - $before = reset ($before); - // 2. Map the proposal entries into the before state - $after = $before; - foreach ($dataOK as $field=>$val) - $after[$field] = $val; - } - else - { - if ($this->debug) echo " verify NO updatekey\n"; - $after = $dataOK; - - } - // Check if the unique constrain is valid before doing the insertion - if ($this->unique === null && $this->primary !== null) - $this->unique = array ($this->primary); - // TODO : If Unique is not defined nor primary - // FIXME : If unique is defined, could I test if the primary key is defined - // in a parameter of the unique and if it is not add it automatically - foreach ($this->unique as $k=>$columns) - { - if ($this->primary === null) - { - return array (dgettext ("domframework", - "No field primary defined for tests in primary")); - } - - if (is_array ($columns)) - { - // Multiple columns in unique - if ($this->debug) echo " verify unique multiple $k\n"; - $select = array (); - if ($updatekey !== false) - $select[] = array ($this->primary, $updatekey, "!="); - foreach ($columns as $col) - { - if (!array_key_exists ($col, $after)) continue; - $select[] = array ($col, $after[$col]); - } - // If there is only the primary key, there is no chance to have a - // conflict - // Before updating, check if the new values are not creating an error - $rc = $this->read ($select, array ($this->primary)); - if (count ($rc) > 0) - { - $errors[] = array ("error", dgettext ("domframework", - "An entry with these values already exists")); - continue; - } - } - else - { - // One column in unique - if ($this->debug) echo " verify unique one column $k\n"; - if (!array_key_exists ($columns, $after)) continue; - $select = array (); - if ($updatekey !== false) - { - // This line have a problem to update a tuple with the same values - // if ($columns === $this->primary) - $select[] = array ($this->primary, $updatekey, "!="); - } - $select[] = array ($columns, $after[$columns]); - $rc = $this->read ($select, - array ($this->primary)); - if (count ($rc) > 0) - { - $errors[] = array ("error", dgettext ("domframework", - "An entry with this value already exists")); - continue; - } - } - } - - // Check if the foreign keys constrains are valid before doing the insertion - foreach ($this->foreign as $foreign=>$d) - { - if ($updatekey === false) - { - // Before doing the insert, check the foreign keys. In update, they are - // not mandatory and are not checked for existancy. - if ($this->debug) echo " verify foreign $foreign\n"; - if (! isset ($data[$foreign])) - { - $errors[] = array ("error", sprintf (dgettext ("domframework", - "The foreign column '%s' is not provided"), - $foreign)); - return $errors; - } - if (! isset ($data[$foreign][0])) - { - $errors[] = array ("error", sprintf (dgettext ("domframework", - "The field type for column '%s' is not provided"), - $foreign)); - return $errors; - continue; - } - } - else - { - if (! array_key_exists ($foreign, $d)) - continue; - } - $table = $d[0]; - $column = $d[1]; - $req = "SELECT $this->sep$column$this->sep ". - "FROM $this->sep$this->tableprefix$table$this->sep ". - "WHERE $this->sep$column$this->sep=:".md5 ($column); - if ($this->debug) echo "DEBUG : $req\n"; - $st = self::$instance[$this->dsn]->prepare ($req); - $val = $data[$foreign]; - $key = $column; - if ($this->debug) echo "DEBUG BIND : ".$this->fields[$foreign][0]."\n"; - if ($this->debug) echo "DEBUG BIND : $column(".md5 ($column)."->". - var_export ($val, TRUE)."\n"; - if ($val === null) - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_NULL); - elseif ($this->fields[$foreign][0] === "integer") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_INT); - elseif ($this->fields[$foreign][0] === "varchar") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - elseif ($this->fields[$foreign][0] === "datetime") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - elseif ($this->fields[$foreign][0] === "date") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - else - { - throw new \Exception ("TO BE DEVELOPPED : ".$this->fields[$foreign][0], - 500); - } - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d; - if (count ($res) === 0) - { - $errors[] = array ("error", sprintf (dgettext ("domframework", - "The foreign key '%s' doesn't exists"), - $column)); - continue; - } - } - return $errors; - } - - /** Insert a new line of data in the table. Datas must be an indexed array - * @param array $data Datas to be recorded (column=>value) - */ - public function insert ($data) - { - if ($this->debug) echo "== Entering insert\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to insert in the table"), - 500); - if ($this->unique === null) - throw new \Exception (dgettext ("domframework", - "Unique fields of table are not defined"), 500); - if (! is_array ($this->unique)) - throw new \Exception (dgettext ("domframework", - "The unique configuration is not an array"), 500); - if (!is_array ($data)) - throw new \Exception (dgettext ("domframework", - "The data provided to create are not array"), - 405); - foreach ($this->fields as $key=>$params) - { - if (in_array ("autoincrement", $params)) - $data[$key] = null; - } - if (!in_array ($this->primary, $this->unique)) - $this->unique[] = $this->primary; - $dataOK = array (); - $errors = $this->verify ($data); - if (count ($errors) !== 0) - { - $errors = reset ($errors); - if (! is_array ($errors)) - $errors = array (0=>"error", 1=>$errors); - throw new \Exception ($errors[1], 405); - } - foreach ($this->fields as $field=>$desc) - { - if (isset ($data[$field])) - $dataOK[$field] = $data[$field]; - } - $binds = array_keys ($dataOK); - array_walk ($binds, function(&$value, $key) { - $value = md5 ($value); - }); - $dataOK = call_user_func ($this->hookpreinsertFunc, $dataOK); - $req = "INSERT INTO $this->sep$this->tableprefix$this->table$this->sep "; - $req .= "($this->sep". - implode ("$this->sep,$this->sep", array_keys ($dataOK)). - "$this->sep)"; - $req .= " VALUES "; - $req .= "(:".implode (",:", $binds).")"; - if ($this->debug) echo "DEBUG : $req\n"; - $st = self::$instance[$this->dsn]->prepare ($req); - foreach ($dataOK as $key=>$val) - { - if ($this->debug) echo "DEBUG BIND : $key(".md5 ($key).")->". - var_export ($val, TRUE)."\n"; - if ($val === null) - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_NULL); - elseif ($this->fields[$key][0] === "integer") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_INT); - elseif ($this->fields[$key][0] === "varchar") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - elseif ($this->fields[$key][0] === "datetime") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - elseif ($this->fields[$key][0] === "date") - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - else - throw new \Exception ("TO BE DEVELOPPED : ".$this->fields[$key][0], - 500); - } - - try - { - $st->execute (); - } - catch (\Exception $e) - { - echo "dblayer execute exception : ".$e->getMessage()."\n"; - exit; - } - if (key_exists ($this->primary, $data) && - ! in_array ("autoincrement", $this->fields[$this->primary]) && - $data[$this->primary] !== null) - $lastID = $data[$this->primary]; - elseif (key_exists ($this->primary, $data) && - in_array ("autoincrement", $this->fields[$this->primary]) && - $data[$this->primary] !== null) - $lastID = $data[$this->primary]; - else - $lastID = self::$instance[$this->dsn]->lastInsertId(); - $lastID = call_user_func ($this->hookpostinsertFunc, $dataOK, $lastID); - return $lastID; - } - - /** - * Read the table content based on a select filter, ordered by order - * operator and the associated select value - * @param array|null $select Rows to select with - * $select = array (array ($key, $val, $operator), ...) - * $key=>column, $val=>value to found, $operator=>'LIKE', =... - * @param array|null $display Columns displayed - * $display = array ($col1, $col2...); - * @param array|null $order Sort the columns by orientation - * $order = array (array ($key, $orientation), ...) - * $key=>column, $orientation=ASC/DESC - * @param boolean|null $whereOr The WHERE parameters are separated by OR - * instead of AND - * @param array|null $foreignSelect Add a filter on foreign keys - * @return array array ([0] => array (column=>value, column=>value),); - */ - public function read ($select=null, $display=null, $order=null, - $whereOr=false, $foreignSelect=null) - { - if ($this->debug) echo "== Entering read\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to read the table"), 500); - if ($select !== null && !is_array ($select)) - throw new \Exception (dgettext ("domframework", - "Select information provided is not an array"), - 405); - if ($display !== null && !is_array ($display)) - throw new \Exception (dgettext ("domframework", - "Display information provided is not an array"), - 405); - if ($order !== null && !is_array ($order)) - throw new \Exception (dgettext ("domframework", - "Order information provided is not an array"), - 405); - if ($display !== null) - { - foreach ($display as $f) - { - if (!in_array ($f, array_keys ($this->fields))) - throw new \Exception (sprintf (dgettext ("domframework", - "Field '%s' not allowed"), $f), 500); - } - } - else - { - $display = array_keys ($this->fields); - } - - $foreignSelectCols = array (); - if ($foreignSelect !== null) - { - foreach ($foreignSelect as $s) - $foreignSelectCols[] = $s[0]; - } - call_user_func_array ($this->hookprereadFunc, - array (&$select, &$display, &$order, - &$whereOr, &$foreignSelect)); - $req = "SELECT $this->sep"; - $req .= implode ("$this->sep,$this->sep", $display); - $req .= "$this->sep "; - $req .= "FROM $this->sep$this->tableprefix$this->table$this->sep"; - if ($select !== null || $foreignSelect !== null) - { - $req .= " WHERE ("; - } - if ($select !== null) - { - // TODO Allow a field=>value in plus of array("field","value") - foreach ($select as $n=>$s) - { - if (! is_array ($s)) - throw new \Exception ("Select not an array for element $n", 500); - // The foreign keys can not be in the select too (conflict) - if (in_array ($s[0],$foreignSelectCols)) - continue; - if (! array_key_exists (0, $s)) - throw new \Exception ("Select field for key $n not provided", 406); - if (! array_key_exists (1, $s)) - throw new \Exception ("Select value for key $n not provided", 406); - if ($n > 0) - { - if ($whereOr === false) - $req .= " AND"; - else - $req .= " OR "; - } - if (!isset ($s[2])) - $s[2] = "="; - if (!isset ($s[0])) - throw new \Exception (sprintf (dgettext ("domframework", - "Select not found for id=%d"), $n), 500); - // The double-quotes are added for sqlite to escape the column if its - // name is 'group' - // Don't put single quotes : don't work with SQLite - // TODO : Test for PostgreSQL (Tested for SQLite and MySQL) - if ($s[1] !== null) - $req .= " $this->sep".$s[0]."$this->sep ".$s[2]." :". - md5 ($s[0].$s[1]); - else - $req .= " $this->sep".$s[0]."$this->sep IS NULL"; - } - $req .=")"; - } - if ($select !== null && $foreignSelect !== null) - $req .= " AND ("; - if ($foreignSelect !== null) - { - // TODO Allow a field=>value in plus of array("field","value") - foreach ($foreignSelect as $n=>$s) - { - if (! array_key_exists (0, $s)) - throw new \Exception ("Foreign field for key $n not provided", 406); - if (! array_key_exists (1, $s)) - throw new \Exception ("Foreign value for key $n not provided", 406); - if ($n > 0) - { - $req .= " AND"; - } - if (!isset ($s[2])) - $s[2] = "="; - $req .= " $this->sep".$s[0]."$this->sep ".$s[2]." :".md5 ($s[0].$s[1]); - } - $req .=")"; - } - - if ($order !== null) - { - $req .= " ORDER BY "; - foreach ($order as $n=>$o) - { - if ($n > 0) - $req .= ","; - $req .= $this->sep.$o[0].$this->sep; - if (isset ($o[1]) && strtoupper ($o[1]) === "DESC") - $req .= " DESC"; - else - $req .= " ASC"; - } - } - - if ($this->debug) echo "DEBUG : $req\n"; - try - { - $st = self::$instance[$this->dsn]->prepare ($req); - } - catch (\Exception $e) - { - if ($this->debug) echo "DEBUG : PREPARE ERROR ! Return FALSE". - $e->getMessage()."\n"; - throw new \Exception ($e->getMessage(), 500); - } - - if ($select !== NULL) - { - foreach ($select as $s) - { - if ($s[1] === null) - continue; - if ($this->debug) - echo "DEBUG BIND : ".$s[0]."(".md5 ($s[0].$s[1]).")->". - var_export ($s[1], TRUE)."\n"; - $st->bindValue (":".md5 ($s[0].$s[1]), $s[1]); - } - } - if ($foreignSelect !== null) - { - foreach ($foreignSelect as $s) - { - if ($this->debug) - echo "DEBUG BIND : ".$s[0]."(".md5 ($s[0].$s[1]).")->". - var_export ($s[1], TRUE)."\n"; - $st->bindValue (":".md5 ($s[0].$s[1]), $s[1]); - } - } - - $rc = $st->execute (); - if ($rc === false) - { - if ($this->debug) echo "DEBUG : EXECUTE ERROR ! Return FALSE\n"; - } - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d; - $res = call_user_func ($this->hookpostreadFunc, $res); - return $res; - } - - /** - * Update the key tuple with the provided data - * Return the number of rows modified - * @param string|integer $updatekey The key applied on primary key to be - * updated - * @param array $data The values to be updated - * @return integer the number of lines modified - */ - public function update ($updatekey, $data) - { - if ($this->debug) echo "== Entering update\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to update in the table"), - 500); - if (count ($this->fields) === 0) - throw new \Exception (dgettext ("domframework", "No Field defined"), 500); - if ($this->primary === null) - throw new \Exception (dgettext ("domframework", "No Primary defined"), - 500); - if (count ($data) === 0) - throw new \Exception (dgettext ("domframework", - "No data to update provided"), 500); - $dataOK = array (); - $errors = $this->verify ($data, $updatekey); - if (count ($errors) !== 0) - { - if (is_array ($errors)) - { - if (isset ($errors[0][1])) - throw new \Exception ($errors[0][1], 405); - $err = reset ($errors); - throw new \Exception ($err[1], 405); - } - throw new \Exception ($errors[1], 405); - } - foreach ($this->fields as $field=>$desc) - { - if (array_key_exists ($field, $data)) - $dataOK[$field] = $data[$field]; - } - - $dataOK = call_user_func ($this->hookpreupdateFunc, $updatekey, $dataOK); - $req = "UPDATE $this->sep".$this->tableprefix."$this->table$this->sep SET "; - $i = 0; - foreach ($dataOK as $key=>$val) - { - if ($i>0) $req .= ","; - $req .= "$this->sep$key$this->sep=:".md5 ($key); - $i++; - } - - $req .= " WHERE $this->sep$this->primary$this->sep=:". - md5 ("PRIMARY".$this->primary); - if ($this->debug) echo "DEBUG : $req\n"; - $st = self::$instance[$this->dsn]->prepare ($req); - // Add the primary key to field list temporaly. It will permit to update the - // primary key - $fields = $this->fields; - $dataOK["PRIMARY".$this->primary] = $updatekey; - $fields["PRIMARY".$this->primary] = $this->fields[$this->primary]; - foreach ($dataOK as $key=>$val) - { - if ($this->debug) echo "DEBUG BIND : $key(".md5 ($key).")->". - var_export ($val, TRUE)." "; - if ($val === null) - { - if ($this->debug) echo "(null)\n"; - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_NULL); - } - elseif ($fields[$key][0] === "integer") - { - if ($this->debug) echo "(integer)\n"; - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_INT); - } - elseif ($fields[$key][0] === "varchar") - { - if ($this->debug) echo "(varchar)\n"; - $st->bindValue (":".md5 ($key), "$val", \PDO::PARAM_STR); - } - elseif ($fields[$key][0] === "datetime") - { - if ($this->debug) echo "(datetime)\n"; - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - } - elseif ($fields[$key][0] === "date") - { - if ($this->debug) echo "(date)\n"; - $st->bindValue (":".md5 ($key), $val, \PDO::PARAM_STR); - } - else - { - if ($this->debug) echo "(UNKNOWN)\n"; - throw new \Exception ("TO BE DEVELOPPED : ".$fields[$key][0], 500); - } - } - - $st->execute (); - $nbLinesUpdated = $st->rowCount (); - $nbLinesUpdated = call_user_func ($this->hookpostupdateFunc, $updatekey, - $dataOK, $nbLinesUpdated); - return $nbLinesUpdated; - } - - /** Delete a tuple identified by its primary key - * Return the number of deleted rows (can be 0 !) - * @param string|integer $deletekey The key of primary key to be deleted - */ - public function delete ($deletekey) - { - if ($this->debug) echo "== Entering delete\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to delete in the table"), - 500); - $deletekey = call_user_func ($this->hookpredeleteFunc, $deletekey); - $req = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep "; - $req .= "WHERE $this->primary = :primary"; - $st = self::$instance[$this->dsn]->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); - try - { - $st->execute (); - } - catch (\Exception $e) - { - throw new \Exception ($e->getMessage (), 500); - } - $nbLinesDeleted = $st->rowCount(); - $nbLinesDeleted = call_user_func ($this->hookpostdeleteFunc, $deletekey, - $nbLinesDeleted); - return $nbLinesDeleted; - } - - /** Translation of fieldsi - */ - public function titles () - { - if ($this->debug) echo "== Entering titles\n"; - if (count ($this->fields) === 0) - throw new \Exception (dgettext ("domframework", "No Field defined"), 500); - $arr = array (); - if (count ($this->titles) !== 0) - { - foreach ($this->titles as $field=>$v) - $arr[$field] = $field; - } - else - { - foreach ($this->fields as $field=>$v) - $arr[$field] = $field; - } - return $arr; - } - - /** Drop the table - */ - public function dropTable () - { - if ($this->debug) echo "== Entering dropTables\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to drop the table"), 500); - $sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep"; - if ($this->debug) - echo "$sql\n"; - return self::$instance[$this->dsn]->exec ($sql); - } - - /** Create the table defined by the differents fields. - * Define the SQL syntax based on SQL engines - * $table = "dns zones"; - * $fields = array ( - * "id"=>array ("integer", "not null", "autoincrement"), - * "zo ne"=>array ("varchar", "255", "not null"), - * "vie wname"=>array ("varchar", "255"), - * "view clients"=>array ("varchar", "255"), - * "comme nt"=>array ("varchar", "1024"), - * "opendate"=>array ("datetime", "not null"), - * "closedate"=>array ("datetime"), - * ); - * $primary = "id"; - * $unique = array ("id", array ("zo ne", "vie wname")); - * $foreign = array ("zone"=>"table.field",...); - */ - public function createTable () - { - if ($this->debug) echo "== Entering createTable\n"; - if ($this->sep === "") - throw new \Exception (dgettext ("domframework", "Database not connected"), - 500); - if (count ($this->fields) === 0) - throw new \Exception (dgettext ("domframework", "No Field defined"), 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to create the table"), 500); - switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) - { - case "sqlite": - $sql = "CREATE TABLE IF NOT EXISTS ". - "$this->sep$this->tableprefix$this->table$this->sep ". - "(\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "$this->sep$field$this->sep "; - // Type of field : in $params[0] - if (!isset ($params[0])) - throw new \Exception (sprintf ( - dgettext ("domframework", - "No database type defined for field '%s'"), - $field), 500); - - switch ($params[0]) - { - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - if (!isset ($params[1])) - throw new \Exception (sprintf (dgettext ("domframework", - "No Size provided for varchar field '%s'"), - $field), 500); - $sql .= "VARCHAR(".$params[1].")"; - $params = array_slice ($params, 2); - break; - case "datetime": - $sql .= "DATETIME"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - default: - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown type '%s' provided for field '%s'"), - $params[0], $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; - case "autoincrement": $sql .= " AUTOINCREMENT";break; - default: - throw new \Exception (sprintf (dgettext ("domframework", - "Unknown additionnal parameter for field '%s'"), - $field), 500); - } - } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - if (!is_array ($this->unique)) - throw new \Exception (dgettext ("domframework", - "The Unique field definition is not an array"), - 500); - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE ($this->sep"; - if (is_array ($u)) - $sql .=implode ("$this->sep,$this->sep", $u); - else - $sql .= $u; - $sql .="$this->sep)"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) ". - "REFERENCES $this->sep".$k[0]."$this->sep($this->sep". - $k[1]."$this->sep)"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - $i++; - } - $sql .=")"; - break; - case "mysql": - $sql = "CREATE TABLE IF NOT EXISTS ". - "$this->sep$this->tableprefix$this->table$this->sep ". - "(\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "$this->sep$field$this->sep "; - // Type of field : in $params[0] - if (!isset ($params[0])) - throw new \Exception (dgettext ("domframework", - "No database type defined for field"), 500); - switch ($params[0]) - { - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - if (!isset ($params[1])) - throw new \Exception (dgettext ("domframework", - "No Size provided for varchar field"), 500); - $sql .= "VARCHAR(".$params[1].")"; - $params = array_slice ($params, 2); - break; - case "datetime": - $sql .= "DATETIME"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - default: - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown type provided for field '%s'"), - $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; - case "autoincrement": $sql .= " AUTO_INCREMENT";break; - default: - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown additionnal parameter for field '%s'"), - $field), 500); - } - } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE ($this->sep"; - if (is_array ($u)) - $sql .=implode ("$this->sep,$this->sep", $u); - else - $sql .= $u; - $sql .="$this->sep)"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) ". - "REFERENCES $this->sep".$k[0]."$this->sep($this->sep". - $k[1]."$this->sep)"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - if ($i > 0) - $sql .= ","; - $i++; - } - $sql .=") ENGINE=InnoDB DEFAULT CHARSET=utf8;"; - break; - case "pgsql": - $sql = "CREATE TABLE IF NOT EXISTS ". - "\"$this->tableprefix$this->table\" (\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "\"$field\" "; - if (in_array ("autoincrement", $params)) - $sql .= "SERIAL"; - else - { - // Type of field : in $params[0] - if (!isset ($params[0])) - throw new \Exception (sprintf ( - dgettext ("domframework", - "No database type defined for field '%s'"), - $field), 500); - switch ($params[0]) - { - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - if (!isset ($params[1])) - throw new \Exception (sprintf ( - dgettext ("domframework", - "No Size provided for varchar field '%s'"), - $field), 500); - $sql .= "VARCHAR(".$params[1].")"; - $params = array_slice ($params, 2); - break; - case "datetime": - $sql .= "timestamp with time zone"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - default: - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown type provided for field '%s'"), - $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d["tablename"]; + } + break; default: - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown additionnal parameter for field '%s'"), - $field), 500); - } - } + throw new \Exception(dgettext( + "domframework", + "Unknown database driver in listTables" + ), 500); } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE (\""; - if (is_array ($u)) - $sql .=implode ("\",\"", $u); - else - $sql .= $u; - $sql .="\")"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $sql .= ",\n FOREIGN KEY(\"$field\") REFERENCES \"".$k[0]."\"(\"". - $k[1]."\")"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - if ($i > 0) - $sql .= ","; - $i++; - } - $sql .=")"; - break; - default: - throw new \Exception (dgettext ("domframework", - "PDO Engine not supported in dbLayer"), 500); + return $res; } - if ($this->debug) - echo "$sql\n"; - return self::$instance[$this->dsn]->exec ($sql); - } + /** + * Verify if the provided data can be inserted/updated in the database. + * @param array $data An array containing the data to verify with keys + * @param mixed|null $updatekey the key to update + * @return array an array with the errors in array($key=>array($priority,$message)) + */ + public function verify($data, $updatekey = false) + { + if ($this->debug) { + echo "== Entering verify\n"; + } + $errors = array(); + foreach ($this->fields as $key => $params) { + if ($this->debug) { + echo " verify ($key)\n"; + } + if ($updatekey === false) { + // Don't check if there is an update : the database is already filled + // For autoincrement, in INSERT mode, force the value to null + if (in_array("autoincrement", $params)) { + $data[$key] = null; + } + if (in_array("not null", $params) && !array_key_exists($key, $data)) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Mandatory field '%s' not provided" + ), + $key + )); + continue; + } + if (in_array("not null", $params) && $data[$key] === "") { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Mandatory field '%s' is empty" + ), + $key + )); + continue; + } + } - /** This function permit to send a SQL request to the database to do a SELECT - * Return the an array with the data - * @param string $sql A valid SQL request to be execute - */ - public function directRead ($sql) - { - if ($this->debug) echo "== Entering directRead\n"; - if ($this->debug) - echo "$sql\n"; - $st = self::$instance[$this->dsn]->prepare ($sql); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d; - return $res; - } + // Do not verify the non provided data (if they are not mandatory) + if (!array_key_exists($key, $data)) { + continue; + } - /** This function disconnect the database. It is normally only used in phpunit - * unit tests - */ - public function disconnect () - { - unset (self::$instance[$this->dsn]); - } + // Verify the fields, if $verify is defined, before doing insertion + $verify = call_user_func($this->verifyOneFunc, $key, $data[$key]); + if (is_array($verify) && count($verify)) { + $errors[$key] = array($verify[0], $verify[1]); + //." ". dgettext ("domframework","in")." ".$key); + continue; + } - /** The prepare method - * @param string $statement The valid template to be replaced - * @param array|null $driver_options The replacement to be done - */ - public function prepare ($statement, $driver_options = array()) - { - return self::$instance[$this->dsn]->prepare ($statement, $driver_options); - } + // Check for type inconsistencies if the value is provided + if (is_null($data[$key])) { + // Skipped the removed autoincrement keys + continue; + } elseif (! is_string($data[$key]) && ! is_integer($data[$key])) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Errors in consistency : '%s' is not an integer or a string [is %s]" + ), + $key, + gettype($data[$key]) + )); + continue; + } elseif ($data[$key] !== "" && $params[0] === "integer") { + if (strspn($data[$key], "0123456789") !== strlen($data[$key])) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Errors in consistency : '%s' is not an integer" + ), + $key + )); + continue; + } + } elseif ($data[$key] !== "" && $params[0] === "varchar") { + if (! isset($params[1])) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "The length of varchar field '%s' is not provided" + ), + $key + )); + continue; + } + if (mb_strlen($data[$key]) > $params[1]) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Errors in consistency : '%s' data is too long" + ), + $key + )); + continue; + } + } elseif ($data[$key] !== "" && $params[0] === "datetime") { + // The date format must be in ANSI SQL : YYYY-MM-DD HH:MM:SS + $d = \DateTime::createFromFormat("Y-m-d H:i:s", $data[$key]); + if (!$d || $d->format("Y-m-d H:i:s") !== $data[$key]) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Incorrect datetime provided for field '%s'" + ), + $key + )); + continue; + } + } elseif ($data[$key] !== "" && $params[0] === "date") { + // The date format must be in ANSI SQL : YYYY-MM-DD + $d = \DateTime::createFromFormat("Y-m-d", $data[$key]); + if (!$d || $d->format("Y-m-d") !== $data[$key]) { + $errors[$key] = array("error", sprintf( + dgettext( + "domframework", + "Incorrect date provided for field '%s'" + ), + $key + )); + continue; + } + } elseif ($data[$key] !== "") { + $errors[$key] = array("error", sprintf(dgettext( + "domframework", + "Unknown field type for '%s'" + ), $key)); + continue; + } else { + // Nothing to do if the value is empty : just save it + } + } - /** Start a new Transaction - */ - public function beginTransaction () - { - return self::$instance[$this->dsn]->beginTransaction (); - } + if ($this->debug) { + echo " verify inconsistency\n"; + } + // Check for inconsistency + $verify = call_user_func($this->verifyAllFunc, $data); + if (is_null($verify)) { + $verify = array(); + } + $allErrors = array_merge($errors, $verify); + if (count($allErrors)) { + return $allErrors; + } - /** Commit (validate) a transaction - */ - public function commit () - { - return self::$instance[$this->dsn]->commit (); - } + $dataOK = array(); + foreach ($this->fields as $field => $desc) { + if (array_key_exists($field, $data)) { + $dataOK[$field] = $data[$field]; + } + } - /** RollBack a transaction - */ - public function rollback () - { - return self::$instance[$this->dsn]->rollback (); - } + if ($updatekey !== false) { + if ($this->debug) { + echo " verify in updatekey\n"; + } + // Check if the unique constrain is valid before doing the insertion + // 1. Read the actual state + $before = $this->read(array(array($this->primary, $updatekey))); + if (count($before) === 0) { + return array("error", dgettext( + "domframework", + "Entry to modify unavailable" + )); + } + $before = reset($before); + // 2. Map the proposal entries into the before state + $after = $before; + foreach ($dataOK as $field => $val) { + $after[$field] = $val; + } + } else { + if ($this->debug) { + echo " verify NO updatekey\n"; + } + $after = $dataOK; + } + // Check if the unique constrain is valid before doing the insertion + if ($this->unique === null && $this->primary !== null) { + $this->unique = array($this->primary); + } + // TODO : If Unique is not defined nor primary + // FIXME : If unique is defined, could I test if the primary key is defined + // in a parameter of the unique and if it is not add it automatically + foreach ($this->unique as $k => $columns) { + if ($this->primary === null) { + return array(dgettext( + "domframework", + "No field primary defined for tests in primary" + )); + } - /** Hook preread - * This hook is run before selecting the data in the database, after the - * verification - * @param array|null &$select Rows to select with - * $select = array (array ($key, $val, $operator), ...) - * $key=>column, $val=>value to found, $operator=>'LIKE', =... - * @param array|null &$display Columns displayed - * $display = array ($col1, $col2...); - * @param array|null &$order Sort the columns by orientation - * $order = array (array ($key, $orientation), ...) - * $key=>column, $orientation=ASC/DESC - * @param boolean|null &$whereOr The WHERE parameters are separated by OR - * instead of AND - * @param array|null &$foreignSelect Add a filter on foreign keys - */ - public function hookpreread (&$select, &$display, &$order, &$whereOr, - &$foreignSelect) - { + if (is_array($columns)) { + // Multiple columns in unique + if ($this->debug) { + echo " verify unique multiple $k\n"; + } + $select = array(); + if ($updatekey !== false) { + $select[] = array($this->primary, $updatekey, "!="); + } + foreach ($columns as $col) { + if (!array_key_exists($col, $after)) { + continue; + } + $select[] = array($col, $after[$col]); + } + // If there is only the primary key, there is no chance to have a + // conflict + // Before updating, check if the new values are not creating an error + $rc = $this->read($select, array($this->primary)); + if (count($rc) > 0) { + $errors[] = array("error", dgettext( + "domframework", + "An entry with these values already exists" + )); + continue; + } + } else { + // One column in unique + if ($this->debug) { + echo " verify unique one column $k\n"; + } + if (!array_key_exists($columns, $after)) { + continue; + } + $select = array(); + if ($updatekey !== false) { + // This line have a problem to update a tuple with the same values + // if ($columns === $this->primary) + $select[] = array($this->primary, $updatekey, "!="); + } + $select[] = array($columns, $after[$columns]); + $rc = $this->read( + $select, + array($this->primary) + ); + if (count($rc) > 0) { + $errors[] = array("error", dgettext( + "domframework", + "An entry with this value already exists" + )); + continue; + } + } + } - } + // Check if the foreign keys constrains are valid before doing the insertion + foreach ($this->foreign as $foreign => $d) { + if ($updatekey === false) { + // Before doing the insert, check the foreign keys. In update, they are + // not mandatory and are not checked for existancy. + if ($this->debug) { + echo " verify foreign $foreign\n"; + } + if (! isset($data[$foreign])) { + $errors[] = array("error", sprintf( + dgettext( + "domframework", + "The foreign column '%s' is not provided" + ), + $foreign + )); + return $errors; + } + if (! isset($data[$foreign][0])) { + $errors[] = array("error", sprintf( + dgettext( + "domframework", + "The field type for column '%s' is not provided" + ), + $foreign + )); + return $errors; + continue; + } + } else { + if (! array_key_exists($foreign, $d)) { + continue; + } + } + $table = $d[0]; + $column = $d[1]; + $req = "SELECT $this->sep$column$this->sep " . + "FROM $this->sep$this->tableprefix$table$this->sep " . + "WHERE $this->sep$column$this->sep=:" . md5($column); + if ($this->debug) { + echo "DEBUG : $req\n"; + } + $st = self::$instance[$this->dsn]->prepare($req); + $val = $data[$foreign]; + $key = $column; + if ($this->debug) { + echo "DEBUG BIND : " . $this->fields[$foreign][0] . "\n"; + } + if ($this->debug) { + echo "DEBUG BIND : $column(" . md5($column) . "->" . + var_export($val, true) . "\n"; + } + if ($val === null) { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_NULL); + } elseif ($this->fields[$foreign][0] === "integer") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_INT); + } elseif ($this->fields[$foreign][0] === "varchar") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } elseif ($this->fields[$foreign][0] === "datetime") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } elseif ($this->fields[$foreign][0] === "date") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } else { + throw new \Exception( + "TO BE DEVELOPPED : " . $this->fields[$foreign][0], + 500 + ); + } + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d; + } + if (count($res) === 0) { + $errors[] = array("error", sprintf( + dgettext( + "domframework", + "The foreign key '%s' doesn't exists" + ), + $column + )); + continue; + } + } + return $errors; + } - /** - * Hook postread - * This hook is run after selecting the data. - * @param array $data the data selected by the select - * @return array The data modified by the hook - */ - public function hookpostread ($data) - { - return $data; - } + /** Insert a new line of data in the table. Datas must be an indexed array + * @param array $data Datas to be recorded (column=>value) + */ + public function insert($data) + { + if ($this->debug) { + echo "== Entering insert\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if ($this->table === null) { + throw new \Exception( + dgettext( + "domframework", + "No table name defined to insert in the table" + ), + 500 + ); + } + if ($this->unique === null) { + throw new \Exception(dgettext( + "domframework", + "Unique fields of table are not defined" + ), 500); + } + if (! is_array($this->unique)) { + throw new \Exception(dgettext( + "domframework", + "The unique configuration is not an array" + ), 500); + } + if (!is_array($data)) { + throw new \Exception( + dgettext( + "domframework", + "The data provided to create are not array" + ), + 405 + ); + } + foreach ($this->fields as $key => $params) { + if (in_array("autoincrement", $params)) { + $data[$key] = null; + } + } + if (!in_array($this->primary, $this->unique)) { + $this->unique[] = $this->primary; + } + $dataOK = array(); + $errors = $this->verify($data); + if (count($errors) !== 0) { + $errors = reset($errors); + if (! is_array($errors)) { + $errors = array(0 => "error", 1 => $errors); + } + throw new \Exception($errors[1], 405); + } + foreach ($this->fields as $field => $desc) { + if (isset($data[$field])) { + $dataOK[$field] = $data[$field]; + } + } + $binds = array_keys($dataOK); + array_walk($binds, function (&$value, $key) { + $value = md5($value); + }); + $dataOK = call_user_func($this->hookpreinsertFunc, $dataOK); + $req = "INSERT INTO $this->sep$this->tableprefix$this->table$this->sep "; + $req .= "($this->sep" . + implode("$this->sep,$this->sep", array_keys($dataOK)) . + "$this->sep)"; + $req .= " VALUES "; + $req .= "(:" . implode(",:", $binds) . ")"; + if ($this->debug) { + echo "DEBUG : $req\n"; + } + $st = self::$instance[$this->dsn]->prepare($req); + foreach ($dataOK as $key => $val) { + if ($this->debug) { + echo "DEBUG BIND : $key(" . md5($key) . ")->" . + var_export($val, true) . "\n"; + } + if ($val === null) { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_NULL); + } elseif ($this->fields[$key][0] === "integer") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_INT); + } elseif ($this->fields[$key][0] === "varchar") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } elseif ($this->fields[$key][0] === "datetime") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } elseif ($this->fields[$key][0] === "date") { + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } else { + throw new \Exception( + "TO BE DEVELOPPED : " . $this->fields[$key][0], + 500 + ); + } + } - /** - * Hook preinsert - * This hook is run before inserting a new data in the database, after the - * verification - * @param array $data the data to insert in the database - * @return array the modified data - */ - public function hookpreinsert ($data) - { - return $data; - } + try { + $st->execute(); + } catch (\Exception $e) { + echo "dblayer execute exception : " . $e->getMessage() . "\n"; + exit; + } + if ( + key_exists($this->primary, $data) && + ! in_array("autoincrement", $this->fields[$this->primary]) && + $data[$this->primary] !== null + ) { + $lastID = $data[$this->primary]; + } elseif ( + key_exists($this->primary, $data) && + in_array("autoincrement", $this->fields[$this->primary]) && + $data[$this->primary] !== null + ) { + $lastID = $data[$this->primary]; + } else { + $lastID = self::$instance[$this->dsn]->lastInsertId(); + } + $lastID = call_user_func($this->hookpostinsertFunc, $dataOK, $lastID); + return $lastID; + } - /** - * Hook postinsert - * This hook is run after successfuly insert a new data in the database - * @param array $data the data selected by the select - * @param integer $lastID the insert identifier - * @return integer the modified lastID - */ - public function hookpostinsert ($data, $lastID) - { - return $lastID; - } + /** + * Read the table content based on a select filter, ordered by order + * operator and the associated select value + * @param array|null $select Rows to select with + * $select = array (array ($key, $val, $operator), ...) + * $key=>column, $val=>value to found, $operator=>'LIKE', =... + * @param array|null $display Columns displayed + * $display = array ($col1, $col2...); + * @param array|null $order Sort the columns by orientation + * $order = array (array ($key, $orientation), ...) + * $key=>column, $orientation=ASC/DESC + * @param boolean|null $whereOr The WHERE parameters are separated by OR + * instead of AND + * @param array|null $foreignSelect Add a filter on foreign keys + * @return array array ([0] => array (column=>value, column=>value),); + */ + public function read( + $select = null, + $display = null, + $order = null, + $whereOr = false, + $foreignSelect = null + ) { + if ($this->debug) { + echo "== Entering read\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if ($this->table === null) { + throw new \Exception(dgettext( + "domframework", + "No table name defined to read the table" + ), 500); + } + if ($select !== null && !is_array($select)) { + throw new \Exception( + dgettext( + "domframework", + "Select information provided is not an array" + ), + 405 + ); + } + if ($display !== null && !is_array($display)) { + throw new \Exception( + dgettext( + "domframework", + "Display information provided is not an array" + ), + 405 + ); + } + if ($order !== null && !is_array($order)) { + throw new \Exception( + dgettext( + "domframework", + "Order information provided is not an array" + ), + 405 + ); + } + if ($display !== null) { + foreach ($display as $f) { + if (!in_array($f, array_keys($this->fields))) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Field '%s' not allowed" + ), $f), 500); + } + } + } else { + $display = array_keys($this->fields); + } - /** - * Hook preupdate - * This hook is run before updating a data in the database, after the - * verification - * @param string $updatekey the key to be modify - * @param array $data the data selected by the select - * @return array the modified data - */ - public function hookpreupdate ($updatekey, $data) - { - return $data; - } + $foreignSelectCols = array(); + if ($foreignSelect !== null) { + foreach ($foreignSelect as $s) { + $foreignSelectCols[] = $s[0]; + } + } + call_user_func_array( + $this->hookprereadFunc, + array(&$select, &$display, &$order, + &$whereOr, &$foreignSelect) + ); + $req = "SELECT $this->sep"; + $req .= implode("$this->sep,$this->sep", $display); + $req .= "$this->sep "; + $req .= "FROM $this->sep$this->tableprefix$this->table$this->sep"; + if ($select !== null || $foreignSelect !== null) { + $req .= " WHERE ("; + } + if ($select !== null) { + // TODO Allow a field=>value in plus of array("field","value") + foreach ($select as $n => $s) { + if (! is_array($s)) { + throw new \Exception("Select not an array for element $n", 500); + } + // The foreign keys can not be in the select too (conflict) + if (in_array($s[0], $foreignSelectCols)) { + continue; + } + if (! array_key_exists(0, $s)) { + throw new \Exception("Select field for key $n not provided", 406); + } + if (! array_key_exists(1, $s)) { + throw new \Exception("Select value for key $n not provided", 406); + } + if ($n > 0) { + if ($whereOr === false) { + $req .= " AND"; + } else { + $req .= " OR "; + } + } + if (!isset($s[2])) { + $s[2] = "="; + } + if (!isset($s[0])) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Select not found for id=%d" + ), $n), 500); + } + // The double-quotes are added for sqlite to escape the column if its + // name is 'group' + // Don't put single quotes : don't work with SQLite + // TODO : Test for PostgreSQL (Tested for SQLite and MySQL) + if ($s[1] !== null) { + $req .= " $this->sep" . $s[0] . "$this->sep " . $s[2] . " :" . + md5($s[0] . $s[1]); + } else { + $req .= " $this->sep" . $s[0] . "$this->sep IS NULL"; + } + } + $req .= ")"; + } + if ($select !== null && $foreignSelect !== null) { + $req .= " AND ("; + } + if ($foreignSelect !== null) { + // TODO Allow a field=>value in plus of array("field","value") + foreach ($foreignSelect as $n => $s) { + if (! array_key_exists(0, $s)) { + throw new \Exception("Foreign field for key $n not provided", 406); + } + if (! array_key_exists(1, $s)) { + throw new \Exception("Foreign value for key $n not provided", 406); + } + if ($n > 0) { + $req .= " AND"; + } + if (!isset($s[2])) { + $s[2] = "="; + } + $req .= " $this->sep" . $s[0] . "$this->sep " . $s[2] . " :" . md5($s[0] . $s[1]); + } + $req .= ")"; + } - /** - * Hook postupdate - * This hook is run after successfuly update a data in the database - * @param string $updatekey the key which was modified - * @param array $data the data selected by the select - * @param integer $nbLinesUpdated The number of modified lines - * @return integer the modified $nbLinesUpdated - */ - public function hookpostupdate ($updatekey, $data, $nbLinesUpdated) - { - return $nbLinesUpdated; - } + if ($order !== null) { + $req .= " ORDER BY "; + foreach ($order as $n => $o) { + if ($n > 0) { + $req .= ","; + } + $req .= $this->sep . $o[0] . $this->sep; + if (isset($o[1]) && strtoupper($o[1]) === "DESC") { + $req .= " DESC"; + } else { + $req .= " ASC"; + } + } + } - /** - * Hook predelete - * This hook is run before deleting a data in the database - * @param string $deletekey The key to be removed - * @return string the modified $deletekey - */ - public function hookpredelete ($deletekey) - { - return $deletekey; - } + if ($this->debug) { + echo "DEBUG : $req\n"; + } + try { + $st = self::$instance[$this->dsn]->prepare($req); + } catch (\Exception $e) { + if ($this->debug) { + echo "DEBUG : PREPARE ERROR ! Return FALSE" . + $e->getMessage() . "\n"; + } + throw new \Exception($e->getMessage(), 500); + } - /** - * Hook postdelete - * This hook is run after successfuly deleting a data in the database - * @param string $deletekey The removed key - * @param integer $nbLinesDeleted The number of deleted lines - * @return integer $nbLinesUpdated - */ - public function hookpostdelete ($deletekey, $nbLinesDeleted) - { - return $nbLinesDeleted; - } + if ($select !== null) { + foreach ($select as $s) { + if ($s[1] === null) { + continue; + } + if ($this->debug) { + echo "DEBUG BIND : " . $s[0] . "(" . md5($s[0] . $s[1]) . ")->" . + var_export($s[1], true) . "\n"; + } + $st->bindValue(":" . md5($s[0] . $s[1]), $s[1]); + } + } + if ($foreignSelect !== null) { + foreach ($foreignSelect as $s) { + if ($this->debug) { + echo "DEBUG BIND : " . $s[0] . "(" . md5($s[0] . $s[1]) . ")->" . + var_export($s[1], true) . "\n"; + } + $st->bindValue(":" . md5($s[0] . $s[1]), $s[1]); + } + } - /////////////////// - /// SETTERS /// - /////////////////// - /** Set the table property - * @param string $table The table name to use - */ - public function tableSet ($table) - { - $this->table = $table; - return $this; - } + $rc = $st->execute(); + if ($rc === false) { + if ($this->debug) { + echo "DEBUG : EXECUTE ERROR ! Return FALSE\n"; + } + } + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d; + } + $res = call_user_func($this->hookpostreadFunc, $res); + return $res; + } - /** Set the tableprefix property - * @param string $tableprefix The prefix to add in table names - */ - public function tableprefixSet ($tableprefix) - { - $this->tableprefix = $tableprefix; - return $this; - } + /** + * Update the key tuple with the provided data + * Return the number of rows modified + * @param string|integer $updatekey The key applied on primary key to be + * updated + * @param array $data The values to be updated + * @return integer the number of lines modified + */ + public function update($updatekey, $data) + { + if ($this->debug) { + echo "== Entering update\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if ($this->table === null) { + throw new \Exception( + dgettext( + "domframework", + "No table name defined to update in the table" + ), + 500 + ); + } + if (count($this->fields) === 0) { + throw new \Exception(dgettext("domframework", "No Field defined"), 500); + } + if ($this->primary === null) { + throw new \Exception( + dgettext("domframework", "No Primary defined"), + 500 + ); + } + if (count($data) === 0) { + throw new \Exception(dgettext( + "domframework", + "No data to update provided" + ), 500); + } + $dataOK = array(); + $errors = $this->verify($data, $updatekey); + if (count($errors) !== 0) { + if (is_array($errors)) { + if (isset($errors[0][1])) { + throw new \Exception($errors[0][1], 405); + } + $err = reset($errors); + throw new \Exception($err[1], 405); + } + throw new \Exception($errors[1], 405); + } + foreach ($this->fields as $field => $desc) { + if (array_key_exists($field, $data)) { + $dataOK[$field] = $data[$field]; + } + } - /** Set the fields property - * @param array $fields Set the definition of the fields - */ - public function fieldsSet ($fields) - { - $this->fields = $fields; - return $this; - } + $dataOK = call_user_func($this->hookpreupdateFunc, $updatekey, $dataOK); + $req = "UPDATE $this->sep" . $this->tableprefix . "$this->table$this->sep SET "; + $i = 0; + foreach ($dataOK as $key => $val) { + if ($i > 0) { + $req .= ","; + } + $req .= "$this->sep$key$this->sep=:" . md5($key); + $i++; + } - /** Set the primary property - * @param string $primary The primary field - */ - public function primarySet ($primary) - { - $this->primary = $primary; - return $this; - } + $req .= " WHERE $this->sep$this->primary$this->sep=:" . + md5("PRIMARY" . $this->primary); + if ($this->debug) { + echo "DEBUG : $req\n"; + } + $st = self::$instance[$this->dsn]->prepare($req); + // Add the primary key to field list temporaly. It will permit to update the + // primary key + $fields = $this->fields; + $dataOK["PRIMARY" . $this->primary] = $updatekey; + $fields["PRIMARY" . $this->primary] = $this->fields[$this->primary]; + foreach ($dataOK as $key => $val) { + if ($this->debug) { + echo "DEBUG BIND : $key(" . md5($key) . ")->" . + var_export($val, true) . " "; + } + if ($val === null) { + if ($this->debug) { + echo "(null)\n"; + } + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_NULL); + } elseif ($fields[$key][0] === "integer") { + if ($this->debug) { + echo "(integer)\n"; + } + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_INT); + } elseif ($fields[$key][0] === "varchar") { + if ($this->debug) { + echo "(varchar)\n"; + } + $st->bindValue(":" . md5($key), "$val", \PDO::PARAM_STR); + } elseif ($fields[$key][0] === "datetime") { + if ($this->debug) { + echo "(datetime)\n"; + } + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } elseif ($fields[$key][0] === "date") { + if ($this->debug) { + echo "(date)\n"; + } + $st->bindValue(":" . md5($key), $val, \PDO::PARAM_STR); + } else { + if ($this->debug) { + echo "(UNKNOWN)\n"; + } + throw new \Exception("TO BE DEVELOPPED : " . $fields[$key][0], 500); + } + } - /** Set the unique property - * @param array $unique The array of the unique contraints - */ - public function uniqueSet ($unique) - { - $this->unique = $unique; - return $this; - } + $st->execute(); + $nbLinesUpdated = $st->rowCount(); + $nbLinesUpdated = call_user_func( + $this->hookpostupdateFunc, + $updatekey, + $dataOK, + $nbLinesUpdated + ); + return $nbLinesUpdated; + } - /** Set the foreign property - * @param array $foreign The foreign array - */ - public function foreignSet ($foreign) - { - $this->foreign = $foreign; - return $this; - } + /** Delete a tuple identified by its primary key + * Return the number of deleted rows (can be 0 !) + * @param string|integer $deletekey The key of primary key to be deleted + */ + public function delete($deletekey) + { + if ($this->debug) { + echo "== Entering delete\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if ($this->table === null) { + throw new \Exception( + dgettext( + "domframework", + "No table name defined to delete in the table" + ), + 500 + ); + } + $deletekey = call_user_func($this->hookpredeleteFunc, $deletekey); + $req = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep "; + $req .= "WHERE $this->primary = :primary"; + $st = self::$instance[$this->dsn]->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); + try { + $st->execute(); + } catch (\Exception $e) { + throw new \Exception($e->getMessage(), 500); + } + $nbLinesDeleted = $st->rowCount(); + $nbLinesDeleted = call_user_func( + $this->hookpostdeleteFunc, + $deletekey, + $nbLinesDeleted + ); + return $nbLinesDeleted; + } - /** Set the debug property - * @param integer $debug The debug value - */ - public function debugSet ($debug) - { - $this->debug = $debug; - return $this; - } + /** Translation of fieldsi + */ + public function titles() + { + if ($this->debug) { + echo "== Entering titles\n"; + } + if (count($this->fields) === 0) { + throw new \Exception(dgettext("domframework", "No Field defined"), 500); + } + $arr = array(); + if (count($this->titles) !== 0) { + foreach ($this->titles as $field => $v) { + $arr[$field] = $field; + } + } else { + foreach ($this->fields as $field => $v) { + $arr[$field] = $field; + } + } + return $arr; + } - /** Set the dsn property - * @param string $dsn The DSN to use - */ - public function dsnSet ($dsn) - { - $this->dsn = $dsn; - return $this; - } + /** Drop the table + */ + public function dropTable() + { + if ($this->debug) { + echo "== Entering dropTables\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if ($this->table === null) { + throw new \Exception(dgettext( + "domframework", + "No table name defined to drop the table" + ), 500); + } + $sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep"; + if ($this->debug) { + echo "$sql\n"; + } + return self::$instance[$this->dsn]->exec($sql); + } - /** Set the titles property - * @param array $titles The titles of the fields - */ - public function titlesSet ($titles) - { - $this->titles = $titles; - return $this; - } + /** Create the table defined by the differents fields. + * Define the SQL syntax based on SQL engines + * $table = "dns zones"; + * $fields = array ( + * "id"=>array ("integer", "not null", "autoincrement"), + * "zo ne"=>array ("varchar", "255", "not null"), + * "vie wname"=>array ("varchar", "255"), + * "view clients"=>array ("varchar", "255"), + * "comme nt"=>array ("varchar", "1024"), + * "opendate"=>array ("datetime", "not null"), + * "closedate"=>array ("datetime"), + * ); + * $primary = "id"; + * $unique = array ("id", array ("zo ne", "vie wname")); + * $foreign = array ("zone"=>"table.field",...); + */ + public function createTable() + { + if ($this->debug) { + echo "== Entering createTable\n"; + } + if ($this->sep === "") { + throw new \Exception( + dgettext("domframework", "Database not connected"), + 500 + ); + } + if (count($this->fields) === 0) { + throw new \Exception(dgettext("domframework", "No Field defined"), 500); + } + if ($this->table === null) { + throw new \Exception(dgettext( + "domframework", + "No table name defined to create the table" + ), 500); + } + switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + case "sqlite": + $sql = "CREATE TABLE IF NOT EXISTS " . + "$this->sep$this->tableprefix$this->table$this->sep " . + "(\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "$this->sep$field$this->sep "; + // Type of field : in $params[0] + if (!isset($params[0])) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "No database type defined for field '%s'" + ), + $field + ), 500); + } + switch ($params[0]) { + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + if (!isset($params[1])) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "No Size provided for varchar field '%s'" + ), + $field + ), 500); + } + $sql .= "VARCHAR(" . $params[1] . ")"; + $params = array_slice($params, 2); + break; + case "datetime": + $sql .= "DATETIME"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown type '%s' provided for field '%s'" + ), + $params[0], + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + case "autoincrement": + $sql .= " AUTOINCREMENT"; + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown additionnal parameter for field '%s'" + ), + $field + ), 500); + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + if (!is_array($this->unique)) { + throw new \Exception( + dgettext( + "domframework", + "The Unique field definition is not an array" + ), + 500 + ); + } + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE ($this->sep"; + if (is_array($u)) { + $sql .= implode("$this->sep,$this->sep", $u); + } else { + $sql .= $u; + } + $sql .= "$this->sep)"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) " . + "REFERENCES $this->sep" . $k[0] . "$this->sep($this->sep" . + $k[1] . "$this->sep)"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + $i++; + } + $sql .= ")"; + break; + case "mysql": + $sql = "CREATE TABLE IF NOT EXISTS " . + "$this->sep$this->tableprefix$this->table$this->sep " . + "(\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "$this->sep$field$this->sep "; + // Type of field : in $params[0] + if (!isset($params[0])) { + throw new \Exception(dgettext( + "domframework", + "No database type defined for field" + ), 500); + } + switch ($params[0]) { + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + if (!isset($params[1])) { + throw new \Exception(dgettext( + "domframework", + "No Size provided for varchar field" + ), 500); + } + $sql .= "VARCHAR(" . $params[1] . ")"; + $params = array_slice($params, 2); + break; + case "datetime": + $sql .= "DATETIME"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown type provided for field '%s'" + ), + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + case "autoincrement": + $sql .= " AUTO_INCREMENT"; + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown additionnal parameter for field '%s'" + ), + $field + ), 500); + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE ($this->sep"; + if (is_array($u)) { + $sql .= implode("$this->sep,$this->sep", $u); + } else { + $sql .= $u; + } + $sql .= "$this->sep)"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) " . + "REFERENCES $this->sep" . $k[0] . "$this->sep($this->sep" . + $k[1] . "$this->sep)"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + if ($i > 0) { + $sql .= ","; + } + $i++; + } + $sql .= ") ENGINE=InnoDB DEFAULT CHARSET=utf8;"; + break; + case "pgsql": + $sql = "CREATE TABLE IF NOT EXISTS " . + "\"$this->tableprefix$this->table\" (\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "\"$field\" "; + if (in_array("autoincrement", $params)) { + $sql .= "SERIAL"; + } else { + // Type of field : in $params[0] + if (!isset($params[0])) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "No database type defined for field '%s'" + ), + $field + ), 500); + } + switch ($params[0]) { + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + if (!isset($params[1])) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "No Size provided for varchar field '%s'" + ), + $field + ), 500); + } + $sql .= "VARCHAR(" . $params[1] . ")"; + $params = array_slice($params, 2); + break; + case "datetime": + $sql .= "timestamp with time zone"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown type provided for field '%s'" + ), + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + default: + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown additionnal parameter for field '%s'" + ), + $field + ), 500); + } + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE (\""; + if (is_array($u)) { + $sql .= implode("\",\"", $u); + } else { + $sql .= $u; + } + $sql .= "\")"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $sql .= ",\n FOREIGN KEY(\"$field\") REFERENCES \"" . $k[0] . "\"(\"" . + $k[1] . "\")"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + if ($i > 0) { + $sql .= ","; + } + $i++; + } + $sql .= ")"; + break; + default: + throw new \Exception(dgettext( + "domframework", + "PDO Engine not supported in dbLayer" + ), 500); + } + + if ($this->debug) { + echo "$sql\n"; + } + return self::$instance[$this->dsn]->exec($sql); + } + + /** This function permit to send a SQL request to the database to do a SELECT + * Return the an array with the data + * @param string $sql A valid SQL request to be execute + */ + public function directRead($sql) + { + if ($this->debug) { + echo "== Entering directRead\n"; + } + if ($this->debug) { + echo "$sql\n"; + } + $st = self::$instance[$this->dsn]->prepare($sql); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d; + } + return $res; + } + + /** This function disconnect the database. It is normally only used in phpunit + * unit tests + */ + public function disconnect() + { + unset(self::$instance[$this->dsn]); + } + + /** The prepare method + * @param string $statement The valid template to be replaced + * @param array|null $driver_options The replacement to be done + */ + public function prepare($statement, $driver_options = array()) + { + return self::$instance[$this->dsn]->prepare($statement, $driver_options); + } + + /** Start a new Transaction + */ + public function beginTransaction() + { + return self::$instance[$this->dsn]->beginTransaction(); + } + + /** Commit (validate) a transaction + */ + public function commit() + { + return self::$instance[$this->dsn]->commit(); + } + + /** RollBack a transaction + */ + public function rollback() + { + return self::$instance[$this->dsn]->rollback(); + } + + /** Hook preread + * This hook is run before selecting the data in the database, after the + * verification + * @param array|null &$select Rows to select with + * $select = array (array ($key, $val, $operator), ...) + * $key=>column, $val=>value to found, $operator=>'LIKE', =... + * @param array|null &$display Columns displayed + * $display = array ($col1, $col2...); + * @param array|null &$order Sort the columns by orientation + * $order = array (array ($key, $orientation), ...) + * $key=>column, $orientation=ASC/DESC + * @param boolean|null &$whereOr The WHERE parameters are separated by OR + * instead of AND + * @param array|null &$foreignSelect Add a filter on foreign keys + */ + public function hookpreread( + &$select, + &$display, + &$order, + &$whereOr, + &$foreignSelect + ) { + } + + /** + * Hook postread + * This hook is run after selecting the data. + * @param array $data the data selected by the select + * @return array The data modified by the hook + */ + public function hookpostread($data) + { + return $data; + } + + /** + * Hook preinsert + * This hook is run before inserting a new data in the database, after the + * verification + * @param array $data the data to insert in the database + * @return array the modified data + */ + public function hookpreinsert($data) + { + return $data; + } + + /** + * Hook postinsert + * This hook is run after successfuly insert a new data in the database + * @param array $data the data selected by the select + * @param integer $lastID the insert identifier + * @return integer the modified lastID + */ + public function hookpostinsert($data, $lastID) + { + return $lastID; + } + + /** + * Hook preupdate + * This hook is run before updating a data in the database, after the + * verification + * @param string $updatekey the key to be modify + * @param array $data the data selected by the select + * @return array the modified data + */ + public function hookpreupdate($updatekey, $data) + { + return $data; + } + + /** + * Hook postupdate + * This hook is run after successfuly update a data in the database + * @param string $updatekey the key which was modified + * @param array $data the data selected by the select + * @param integer $nbLinesUpdated The number of modified lines + * @return integer the modified $nbLinesUpdated + */ + public function hookpostupdate($updatekey, $data, $nbLinesUpdated) + { + return $nbLinesUpdated; + } + + /** + * Hook predelete + * This hook is run before deleting a data in the database + * @param string $deletekey The key to be removed + * @return string the modified $deletekey + */ + public function hookpredelete($deletekey) + { + return $deletekey; + } + + /** + * Hook postdelete + * This hook is run after successfuly deleting a data in the database + * @param string $deletekey The removed key + * @param integer $nbLinesDeleted The number of deleted lines + * @return integer $nbLinesUpdated + */ + public function hookpostdelete($deletekey, $nbLinesDeleted) + { + return $nbLinesDeleted; + } + + /////////////////// + /// SETTERS /// + /////////////////// + /** Set the table property + * @param string $table The table name to use + */ + public function tableSet($table) + { + $this->table = $table; + return $this; + } + + /** Set the tableprefix property + * @param string $tableprefix The prefix to add in table names + */ + public function tableprefixSet($tableprefix) + { + $this->tableprefix = $tableprefix; + return $this; + } + + /** Set the fields property + * @param array $fields Set the definition of the fields + */ + public function fieldsSet($fields) + { + $this->fields = $fields; + return $this; + } + + /** Set the primary property + * @param string $primary The primary field + */ + public function primarySet($primary) + { + $this->primary = $primary; + return $this; + } + + /** Set the unique property + * @param array $unique The array of the unique contraints + */ + public function uniqueSet($unique) + { + $this->unique = $unique; + return $this; + } + + /** Set the foreign property + * @param array $foreign The foreign array + */ + public function foreignSet($foreign) + { + $this->foreign = $foreign; + return $this; + } + + /** Set the debug property + * @param integer $debug The debug value + */ + public function debugSet($debug) + { + $this->debug = $debug; + return $this; + } + + /** Set the dsn property + * @param string $dsn The DSN to use + */ + public function dsnSet($dsn) + { + $this->dsn = $dsn; + return $this; + } + + /** Set the titles property + * @param array $titles The titles of the fields + */ + public function titlesSet($titles) + { + $this->titles = $titles; + return $this; + } } /** POC : diff --git a/src/Dblayerauthzgroups.php b/src/Dblayerauthzgroups.php index a781a20..659896e 100644 --- a/src/Dblayerauthzgroups.php +++ b/src/Dblayerauthzgroups.php @@ -1,4 +1,5 @@ @@ -12,333 +13,413 @@ namespace Domframework; */ class Dblayerauthzgroups extends Dblayer { - /** The authzgroups object, connected to the database */ - public $authzgroups = null; - /** The module name for authzgroups */ - public $module = null; - /** The user name for authzgroups */ - public $user = null; - /** The auth information (email, lastname, firstname) */ - public $auth = null; - /** The default group(s) when creating a new object. Can be a string or an - array with multiple groups */ - public $createGroup = null; - /** The default right when creating a new object */ - public $createRight = "RW"; - /** Pre-Path in object authzgroups */ - public $path = ""; - /** Flag when primary key is added before search */ - private $primaryKeyAdded = false; + /** The authzgroups object, connected to the database */ + public $authzgroups = null; + /** The module name for authzgroups */ + public $module = null; + /** The user name for authzgroups */ + public $user = null; + /** The auth information (email, lastname, firstname) */ + public $auth = null; + /** The default group(s) when creating a new object. Can be a string or an + array with multiple groups */ + public $createGroup = null; + /** The default right when creating a new object */ + public $createRight = "RW"; + /** Pre-Path in object authzgroups */ + public $path = ""; + /** Flag when primary key is added before search */ + private $primaryKeyAdded = false; - //////////////////////// - /// MAIN METHODS /// - //////////////////////// - /** Hook preread - * This hook is run before selecting the data in the database, after the - * verification - * @param array|null &$select Rows to select with - * $select = array (array ($key, $val, $operator), ...) - * $key=>column, $val=>value to found, $operator=>'LIKE', =... - * @param array|null &$display Columns displayed - * $display = array ($col1, $col2...); - * @param array|null &$order Sort the columns by orientation - * $order = array (array ($key, $orientation), ...) - * $key=>column, $orientation=ASC/DESC - * @param boolean|null &$whereOr The WHERE parameters are separated by OR - * instead of AND - * @param array|null &$foreignSelect Add a filter on foreign keys - */ - public function hookpreread (&$select, &$display, &$order, &$whereOr, - &$foreignSelect) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - if ($display === null || ! in_array ($this->primary, $display)) - { - // Need the primary key to allow/deny access. Add it and remove the data - // after the access verification - $display[] = $this->primary; - $this->primaryKeyAdded = true; + //////////////////////// + /// MAIN METHODS /// + //////////////////////// + /** Hook preread + * This hook is run before selecting the data in the database, after the + * verification + * @param array|null &$select Rows to select with + * $select = array (array ($key, $val, $operator), ...) + * $key=>column, $val=>value to found, $operator=>'LIKE', =... + * @param array|null &$display Columns displayed + * $display = array ($col1, $col2...); + * @param array|null &$order Sort the columns by orientation + * $order = array (array ($key, $orientation), ...) + * $key=>column, $orientation=ASC/DESC + * @param boolean|null &$whereOr The WHERE parameters are separated by OR + * instead of AND + * @param array|null &$foreignSelect Add a filter on foreign keys + */ + public function hookpreread( + &$select, + &$display, + &$order, + &$whereOr, + &$foreignSelect + ) { + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + if ($display === null || ! in_array($this->primary, $display)) { + // Need the primary key to allow/deny access. Add it and remove the data + // after the access verification + $display[] = $this->primary; + $this->primaryKeyAdded = true; + } } - } - /** Hook postread - * This hook is run after selecting the data. Return only the allowed data to - * the user. It must have at least the RO flag. - * @param array $data the data selected by the select - * @return array The data modified by the hook - */ - public function hookpostread ($data) - { - // TODO : If foreign keys, do we check if the access is allowed too ? - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - $this->allowPath (); - foreach ($data as $key=>$line) + /** Hook postread + * This hook is run after selecting the data. Return only the allowed data to + * the user. It must have at least the RO flag. + * @param array $data the data selected by the select + * @return array The data modified by the hook + */ + public function hookpostread($data) { - try - { - $this->authzgroups->accessRight ($this->module, $this->user, - $this->path."/".$line[$this->primary]); - } - catch (\Exception $e) - { - unset ($data[$key]); - } - if ($this->primaryKeyAdded === true) - unset ($data[$key][$this->primary]); + // TODO : If foreign keys, do we check if the access is allowed too ? + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + $this->allowPath(); + foreach ($data as $key => $line) { + try { + $this->authzgroups->accessRight( + $this->module, + $this->user, + $this->path . "/" . $line[$this->primary] + ); + } catch (\Exception $e) { + unset($data[$key]); + } + if ($this->primaryKeyAdded === true) { + unset($data[$key][$this->primary]); + } + } + return $data; } - return $data; - } - /** Hook preinsert - * This hook is run before inserting a new data in the database, after the - * verification - * @param array $data the data to insert in the database - * @return the modified data - */ - public function hookpreinsert ($data) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - if ($this->createGroup === null) - throw new \Exception ("No createGroup defined for dblayerauthzgroups", - 500); - $this->allowPath (); - $this->authzgroups->accessWrite ($this->module, $this->user, $this->path); - return $data; - } + /** Hook preinsert + * This hook is run before inserting a new data in the database, after the + * verification + * @param array $data the data to insert in the database + * @return the modified data + */ + public function hookpreinsert($data) + { + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + if ($this->createGroup === null) { + throw new \Exception( + "No createGroup defined for dblayerauthzgroups", + 500 + ); + } + $this->allowPath(); + $this->authzgroups->accessWrite($this->module, $this->user, $this->path); + return $data; + } - /** Hook postinsert - * This hook is run after successfuly insert a new data in the database - * @param array $data The data stored in the database - * @param integer $lastID The lastID stored - * @return the modified lastID - */ - public function hookpostinsert ($data, $lastID) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - if ($this->createGroup === null) - throw new \Exception ("No createGroup defined for dblayerauthzgroups", - 500); - $this->authzgroups->objectAdd ($this->module, $this->path."/$lastID"); - if (is_array ($this->createGroup)) + /** Hook postinsert + * This hook is run after successfuly insert a new data in the database + * @param array $data The data stored in the database + * @param integer $lastID The lastID stored + * @return the modified lastID + */ + public function hookpostinsert($data, $lastID) { - foreach ($this->createGroup as $group) - { - $this->authzgroups->rightAdd ($this->module, $group, - $this->path."/$lastID", - $this->createRight); - } - } - elseif (is_string ($this->createGroup)) - { - $this->authzgroups->rightAdd ($this->module, $this->createGroup, - $this->path."/$lastID", $this->createRight); - } - else - { - throw new \Exception ("createGroup defined for dblayerauthzgroups is not ". + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + if ($this->createGroup === null) { + throw new \Exception( + "No createGroup defined for dblayerauthzgroups", + 500 + ); + } + $this->authzgroups->objectAdd($this->module, $this->path . "/$lastID"); + if (is_array($this->createGroup)) { + foreach ($this->createGroup as $group) { + $this->authzgroups->rightAdd( + $this->module, + $group, + $this->path . "/$lastID", + $this->createRight + ); + } + } elseif (is_string($this->createGroup)) { + $this->authzgroups->rightAdd( + $this->module, + $this->createGroup, + $this->path . "/$lastID", + $this->createRight + ); + } else { + throw new \Exception("createGroup defined for dblayerauthzgroups is not " . "an array or a string", 500); + } + return $lastID; } - return $lastID; - } - /** Hook preupdate - * This hook is run before updating a data in the database, after the - * verification - * @param integer $updatekey The key which will be updated - * @param array $data The data to store in the provided key - * @return the modified data - */ - public function hookpreupdate ($updatekey, $data) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - $this->allowPath (); - $this->authzgroups->accessWrite ($this->module, $this->user, $this->path); - $this->authzgroups->accessWrite ($this->module, $this->user, - $this->path."/$updatekey"); - return $data; - } - - /** Hook predelete - * This hook is run before deleting a data in the database - * @param string $deletekey The key to delete - * @return the modified $deletekey - */ - public function hookpredelete ($deletekey) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - $this->allowPath (); - $this->authzgroups->accessWrite ($this->module, $this->user, $this->path); - $this->authzgroups->accessWrite ($this->module, $this->user, - $this->path."/$deletekey"); - return $deletekey; - } - - /** Hook postdelete - * This hook is run after successfuly deleting a data in the database - * @param string $deletekey The key to delete - * @param integer $nbLinesDeleted The number of deleted lines - * @return $nbLinesUpdated - */ - public function hookpostdelete ($deletekey, $nbLinesDeleted) - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - $this->authzgroups->objectDel ($this->module, $this->path."/$deletekey"); - return $nbLinesDeleted; - } - - /** Return true if all the paths are allowed. Throw an exception elsewhere - */ - private function allowPath () - { - if ($this->module === null) - throw new \Exception ("No module defined for dblayerauthzgroups", 500); - if ($this->auth !== null && array_key_exists ("email", $this->auth) && - $this->user === null) - $this->user = $this->auth["email"]; - if ($this->user === null) - throw new \Exception ("No user defined for dblayerauthzgroups", 500); - if ($this->authzgroups === null) - throw new \Exception ("No authzgroups defined for dblayerauthzgroups", - 500); - if (substr ($this->path, -1) === "/") - $this->path = substr ($this->path, 0, -1); - $paths = explode ("/", $this->path); - $path = ""; - foreach ($paths as $pathTmp) + /** Hook preupdate + * This hook is run before updating a data in the database, after the + * verification + * @param integer $updatekey The key which will be updated + * @param array $data The data to store in the provided key + * @return the modified data + */ + public function hookpreupdate($updatekey, $data) { - $path .= "/$pathTmp"; - $path = str_replace ("//", "/", $path); - $this->authzgroups->accessRight ($this->module, $this->user, $path); + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + $this->allowPath(); + $this->authzgroups->accessWrite($this->module, $this->user, $this->path); + $this->authzgroups->accessWrite( + $this->module, + $this->user, + $this->path . "/$updatekey" + ); + return $data; } - return true; - } - /////////////////// - /// SETTERS /// - /////////////////// - /** Set the authzgroups property - * @param object $authzgroups The object of the authzgroups - */ - public function authzgroupsSet ($authzgroups) - { - $this->authzgroups = $authzgroups; - return $this; - } + /** Hook predelete + * This hook is run before deleting a data in the database + * @param string $deletekey The key to delete + * @return the modified $deletekey + */ + public function hookpredelete($deletekey) + { + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + $this->allowPath(); + $this->authzgroups->accessWrite($this->module, $this->user, $this->path); + $this->authzgroups->accessWrite( + $this->module, + $this->user, + $this->path . "/$deletekey" + ); + return $deletekey; + } - /** Set the module property - * @param string $module The module name to use - */ - public function moduleSet ($module) - { - $this->module = $module; - return $this; - } + /** Hook postdelete + * This hook is run after successfuly deleting a data in the database + * @param string $deletekey The key to delete + * @param integer $nbLinesDeleted The number of deleted lines + * @return $nbLinesUpdated + */ + public function hookpostdelete($deletekey, $nbLinesDeleted) + { + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + $this->authzgroups->objectDel($this->module, $this->path . "/$deletekey"); + return $nbLinesDeleted; + } - /** Set the auth property - * @param array $auth The auth array - */ - public function authSet ($auth) - { - $this->auth = $auth; - return $this; - } + /** Return true if all the paths are allowed. Throw an exception elsewhere + */ + private function allowPath() + { + if ($this->module === null) { + throw new \Exception("No module defined for dblayerauthzgroups", 500); + } + if ( + $this->auth !== null && array_key_exists("email", $this->auth) && + $this->user === null + ) { + $this->user = $this->auth["email"]; + } + if ($this->user === null) { + throw new \Exception("No user defined for dblayerauthzgroups", 500); + } + if ($this->authzgroups === null) { + throw new \Exception( + "No authzgroups defined for dblayerauthzgroups", + 500 + ); + } + if (substr($this->path, -1) === "/") { + $this->path = substr($this->path, 0, -1); + } + $paths = explode("/", $this->path); + $path = ""; + foreach ($paths as $pathTmp) { + $path .= "/$pathTmp"; + $path = str_replace("//", "/", $path); + $this->authzgroups->accessRight($this->module, $this->user, $path); + } + return true; + } - /** Set the user property - * @param string $user The user to authorize - */ - public function userSet ($user) - { - $this->user = $user; - return $this; - } + /////////////////// + /// SETTERS /// + /////////////////// + /** Set the authzgroups property + * @param object $authzgroups The object of the authzgroups + */ + public function authzgroupsSet($authzgroups) + { + $this->authzgroups = $authzgroups; + return $this; + } - /** Set the createGroup property - * @param array|string $createGroup The createGroup to set - */ - public function createGroupSet ($createGroup) - { - $this->createGroup = $createGroup; - return $this; - } + /** Set the module property + * @param string $module The module name to use + */ + public function moduleSet($module) + { + $this->module = $module; + return $this; + } - /** Set the createRight property - * @param string $createRight The right to create - */ - public function createRightSet ($createRight) - { - $this->createRight = $createRight; - return $this; - } + /** Set the auth property + * @param array $auth The auth array + */ + public function authSet($auth) + { + $this->auth = $auth; + return $this; + } - /** Set the path property - * @param string $path The pre-path to use - */ - public function pathSet ($path) - { - $this->path = $path; - return $this; - } + /** Set the user property + * @param string $user The user to authorize + */ + public function userSet($user) + { + $this->user = $user; + return $this; + } + + /** Set the createGroup property + * @param array|string $createGroup The createGroup to set + */ + public function createGroupSet($createGroup) + { + $this->createGroup = $createGroup; + return $this; + } + + /** Set the createRight property + * @param string $createRight The right to create + */ + public function createRightSet($createRight) + { + $this->createRight = $createRight; + return $this; + } + + /** Set the path property + * @param string $path The pre-path to use + */ + public function pathSet($path) + { + $this->path = $path; + return $this; + } } diff --git a/src/Dblayeroo.php b/src/Dblayeroo.php index ce392af..8028afa 100644 --- a/src/Dblayeroo.php +++ b/src/Dblayeroo.php @@ -1,4 +1,5 @@ @@ -11,846 +12,941 @@ namespace Domframework; */ class Dblayeroo { - /** The table name to use - */ - private $table = null; - /** The tableprefix text to prepend to table name (Should finish by _) - * Just allow chars ! - */ - private $tableprefix = ""; - /** The fields with the definition of type, and special parameters - */ - private $fields = array (); - /** The primary field - */ - private $primary = null; - /** An array to define the unique fields (or array of unique fields) - */ - private $unique = null; - /** An array to define the foreign keys of the field - */ - private $foreign = array (); - /** Debug of the SQL - */ - protected $debug = FALSE; - /** The connecting DSN - */ - private $dsn = null; - /** The driver to use - */ - private $driver = null; - /** The field group delimiter - */ - private $sep = ""; - /** Titles - */ - private $titles = array (); - /** The real types of each fields. The real types are different of the SQL - * types : a "mail" type is stored in a "VARCHAR(255)" in SQL. - * The real types are optional : if not set, there is no check. - * They are more strict than the SQL types - */ - private $realTypes = array (); + /** The table name to use + */ + private $table = null; + /** The tableprefix text to prepend to table name (Should finish by _) + * Just allow chars ! + */ + private $tableprefix = ""; + /** The fields with the definition of type, and special parameters + */ + private $fields = array(); + /** The primary field + */ + private $primary = null; + /** An array to define the unique fields (or array of unique fields) + */ + private $unique = null; + /** An array to define the foreign keys of the field + */ + private $foreign = array(); + /** Debug of the SQL + */ + protected $debug = false; + /** The connecting DSN + */ + private $dsn = null; + /** The driver to use + */ + private $driver = null; + /** The field group delimiter + */ + private $sep = ""; + /** Titles + */ + private $titles = array(); + /** The real types of each fields. The real types are different of the SQL + * types : a "mail" type is stored in a "VARCHAR(255)" in SQL. + * The real types are optional : if not set, there is no check. + * They are more strict than the SQL types + */ + private $realTypes = array(); - /** Limit to one instance of the connection to the same database - */ - // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ - private static $instance = array (); + /** Limit to one instance of the connection to the same database + */ + // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ + private static $instance = array(); - /** Store each executed requests meta data to analyze the times, number of - * requests, debugging - */ - private static $meta = array (); + /** Store each executed requests meta data to analyze the times, number of + * requests, debugging + */ + private static $meta = array(); - /** Connection to the database engine - * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format - * @param string $dsn PDO Data Source Name - * @param string|null $username Username to connect - * @param string|null $password Password to connect - * @param string|null $driver_options Driver options to the database - */ - public function __construct ($dsn, $username = null, $password = null, - $driver_options = null) - { - $this->connect ($dsn, $username, $password, $driver_options); - } + /** Connection to the database engine + * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format + * @param string $dsn PDO Data Source Name + * @param string|null $username Username to connect + * @param string|null $password Password to connect + * @param string|null $driver_options Driver options to the database + */ + public function __construct( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + $this->connect($dsn, $username, $password, $driver_options); + } - /** Connection to the database engine - * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format - * @param string $dsn PDO Data Source Name - * @param string|null $username Username to connect - * @param string|null $password Password to connect - * @param string|null $driver_options Driver options to the database - */ - public function connect ($dsn, $username = null, $password = null, - $driver_options = null) - { - if (! function_exists ("mb_strlen")) - throw new \Exception ("PHP don't have the MB Support. Please add it !", - 500); - $driver = @explode (":", $dsn); - if (! isset ($driver[0])) - $this->DBException (dgettext ("domframework", "No valid DSN provided")); - $driver[0] = strtolower ($driver[0]); - if (! in_array ($driver[0], pdo_drivers ())) - $this->DBException (sprintf (dgettext ("domframework", - "Driver PDO '%s' not available in PHP"), - $driver[0])); - $this->driver = $driver[0]; - // Force specifics initialisations - $this->dsn = $dsn; - switch ($driver[0]) - { - case "sqlite": - // Look at the right to write in database and in the directory - $file = substr ($dsn, 7); - if (! is_writeable (dirname ($file))) - $this->DBException (dgettext ("domframework", - "The directory for SQLite database is write protected")); - if (file_exists ($file) && ! is_writeable ($file)) - $this->DBException (dgettext ("domframework", - "The SQLite database file is write protected")); - if (function_exists ("posix_getuid") && - file_exists ($file) && - fileowner ($file) === posix_getuid ()) - chmod ($file, 0666); + /** Connection to the database engine + * See http://fr2.php.net/manual/en/pdo.construct.php for the $dsn format + * @param string $dsn PDO Data Source Name + * @param string|null $username Username to connect + * @param string|null $password Password to connect + * @param string|null $driver_options Driver options to the database + */ + public function connect( + $dsn, + $username = null, + $password = null, + $driver_options = null + ) { + if (! function_exists("mb_strlen")) { + throw new \Exception( + "PHP don't have the MB Support. Please add it !", + 500 + ); + } + $driver = @explode(":", $dsn); + if (! isset($driver[0])) { + $this->DBException(dgettext("domframework", "No valid DSN provided")); + } + $driver[0] = strtolower($driver[0]); + if (! in_array($driver[0], pdo_drivers())) { + $this->DBException(sprintf( + dgettext( + "domframework", + "Driver PDO '%s' not available in PHP" + ), + $driver[0] + )); + } + $this->driver = $driver[0]; + // Force specifics initialisations + $this->dsn = $dsn; + switch ($driver[0]) { + case "sqlite": + // Look at the right to write in database and in the directory + $file = substr($dsn, 7); + if (! is_writeable(dirname($file))) { + $this->DBException(dgettext( + "domframework", + "The directory for SQLite database is write protected" + )); + } + if (file_exists($file) && ! is_writeable($file)) { + $this->DBException(dgettext( + "domframework", + "The SQLite database file is write protected" + )); + } + if ( + function_exists("posix_getuid") && + file_exists($file) && + fileowner($file) === posix_getuid() + ) { + chmod($file, 0666); + } // Print the instances of PDO objects stored : // var_dump (self::$instance); - if (! array_key_exists ($this->dsn, self::$instance)) - { - $this->debugLog ("CONNECT TO SQLite DATABASE", 2); - try - { - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); - } - catch (\Exception $e) - { - $this->DBException ("PDO error : ".$e->getMessage ()); - } - } + if (! array_key_exists($this->dsn, self::$instance)) { + $this->debugLog("CONNECT TO SQLite DATABASE", 2); + try { + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + $this->DBException("PDO error : " . $e->getMessage()); + } + } // Force ForeignKeys support (disabled by default) - self::$instance[$this->dsn]->exec ("PRAGMA foreign_keys = ON"); - $this->sep = "`"; - if ($this->databasename () === null) - $this->DBException ("No Database provided in DSN"); - break; - case "mysql": - if (! array_key_exists ($this->dsn, self::$instance)) - { - $this->debugLog ("CONNECT TO MySQL DATABASE", 2); - try - { - $driver_options[\PDO::MYSQL_ATTR_FOUND_ROWS] = 1; - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); - } - catch (\Exception $e) - { - $this->DBException ("PDO error : ".$e->getMessage ()); - } - } + self::$instance[$this->dsn]->exec("PRAGMA foreign_keys = ON"); + $this->sep = "`"; + if ($this->databasename() === null) { + $this->DBException("No Database provided in DSN"); + } + break; + case "mysql": + if (! array_key_exists($this->dsn, self::$instance)) { + $this->debugLog("CONNECT TO MySQL DATABASE", 2); + try { + $driver_options[\PDO::MYSQL_ATTR_FOUND_ROWS] = 1; + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + $this->DBException("PDO error : " . $e->getMessage()); + } + } - // Set the coding to UTF8 - self::$instance[$this->dsn]->exec ("SET CHARACTER SET utf8"); - $this->sep = "`"; - if ($this->databasename () === null) - $this->DBException ("No Database provided in DSN"); + // Set the coding to UTF8 + self::$instance[$this->dsn]->exec("SET CHARACTER SET utf8"); + $this->sep = "`"; + if ($this->databasename() === null) { + $this->DBException("No Database provided in DSN"); + } // Force the GROUP_CONCAT value max to the max allowed from the server - $st = self::$instance[$this->dsn]->query ( - "SHOW VARIABLES LIKE 'max_allowed_packet'", \PDO::FETCH_COLUMN, 1); - $rows = $st->fetchAll (); - if (! isset ($rows[0])) - throw new \Exception ( - "Can't read the max_allowed_packet from the MySQL server", 500); - $max_allowed_packet = $rows[0]; - self::$instance[$this->dsn]->exec ( - "SET SESSION group_concat_max_len = $max_allowed_packet"); - break; - case "pgsql": - if (! array_key_exists ($this->dsn, self::$instance)) - { - $this->debugLog ("CONNECT TO PGSQL DATABASE", 2); - try - { - self::$instance[$this->dsn] = new \PDO ($dsn, $username, $password, - $driver_options); - self::$instance[$this->dsn]->setAttribute (\PDO::ATTR_ERRMODE, - \PDO::ERRMODE_EXCEPTION); + $st = self::$instance[$this->dsn]->query( + "SHOW VARIABLES LIKE 'max_allowed_packet'", + \PDO::FETCH_COLUMN, + 1 + ); + $rows = $st->fetchAll(); + if (! isset($rows[0])) { + throw new \Exception( + "Can't read the max_allowed_packet from the MySQL server", + 500 + ); + } + $max_allowed_packet = $rows[0]; + self::$instance[$this->dsn]->exec( + "SET SESSION group_concat_max_len = $max_allowed_packet" + ); + break; + case "pgsql": + if (! array_key_exists($this->dsn, self::$instance)) { + $this->debugLog("CONNECT TO PGSQL DATABASE", 2); + try { + self::$instance[$this->dsn] = new \PDO( + $dsn, + $username, + $password, + $driver_options + ); + self::$instance[$this->dsn]->setAttribute( + \PDO::ATTR_ERRMODE, + \PDO::ERRMODE_EXCEPTION + ); + } catch (\Exception $e) { + $this->DBException("PDO error : " . $e->getMessage()); + } + } + + // Set the coding to UTF8 + self::$instance[$this->dsn]->exec("SET NAMES 'utf8'"); + $this->sep = "\""; + if ($this->databasename() === null) { + $this->DBException("No Database provided in DSN"); + } + break; + default: + $this->DBException(dgettext( + "domframework", + "Unknown PDO driver provided" + )); } - catch (\Exception $e) - { - $this->DBException ("PDO error : ".$e->getMessage ()); + return self::$instance[$this->dsn]; + } + + /** This function disconnect the database. It is normally only used in phpunit + * unit tests + */ + public function disconnect() + { + unset(self::$instance[$this->dsn]); + self::$sortOrder = 0; + } + + /** Start a new Transaction + */ + public function beginTransaction() + { + self::$meta[] = array( + "command" => "BEGIN", + "sql" => "BEGIN TRANSACTION", + "sqltime" => 0, + "displayQuery" => "BEGIN TRANSACTION", + "nbrows" => 0, + ); + return self::$instance[$this->dsn]->beginTransaction(); + } + + /** Commit (validate) a transaction + */ + public function commit() + { + self::$meta[] = array( + "command" => "COMMIT", + "sql" => "COMMIT TRANSACTION", + "sqltime" => 0, + "displayQuery" => "COMMIT TRANSACTION", + "nbrows" => 0, + ); + return self::$instance[$this->dsn]->commit(); + } + + /** RollBack a transaction + */ + public function rollback() + { + self::$meta[] = array( + "command" => "ROLLBACK", + "sql" => "ROLLBACK TRANSACTION", + "sqltime" => 0, + "displayQuery" => "ROLLBACK TRANSACTION", + "nbrows" => 0, + ); + return self::$instance[$this->dsn]->rollback(); + } + + /** Return the connected database name from DSN used to connect + */ + public function databasename() + { + if ($this->sep === "") { + $this->DBException(dgettext("domframework", "Database not connected")); } - } - - // Set the coding to UTF8 - self::$instance[$this->dsn]->exec ("SET NAMES 'utf8'"); - $this->sep = "\""; - if ($this->databasename () === null) - $this->DBException ("No Database provided in DSN"); - break; - default: - $this->DBException (dgettext ("domframework", - "Unknown PDO driver provided")); + if ($this->driver === "sqlite") { + $dbFile = substr(strstr($this->dsn, ":"), 1); + if (trim($dbFile) !== "") { + return $dbFile; + } + return null; + } + $vals = explode(";", substr(strstr($this->dsn, ":"), 1)); + $dsnExplode = array(); + foreach ($vals as $val) { + @list($k, $v) = explode("=", $val); + $dsnExplode[$k] = $v; + } + if (isset($dsnExplode["dbname"])) { + return $dsnExplode["dbname"]; + } + return null; } - return self::$instance[$this->dsn]; - } - /** This function disconnect the database. It is normally only used in phpunit - * unit tests - */ - public function disconnect () - { - unset (self::$instance[$this->dsn]); - self::$sortOrder = 0; - } - - /** Start a new Transaction - */ - public function beginTransaction () - { - self::$meta[] = array ( - "command" => "BEGIN", - "sql" => "BEGIN TRANSACTION", - "sqltime" => 0, - "displayQuery" => "BEGIN TRANSACTION", - "nbrows" => 0, - ); - return self::$instance[$this->dsn]->beginTransaction (); - } - - /** Commit (validate) a transaction - */ - public function commit () - { - self::$meta[] = array ( - "command" => "COMMIT", - "sql" => "COMMIT TRANSACTION", - "sqltime" => 0, - "displayQuery" => "COMMIT TRANSACTION", - "nbrows" => 0, - ); - return self::$instance[$this->dsn]->commit (); - } - - /** RollBack a transaction - */ - public function rollback () - { - self::$meta[] = array ( - "command" => "ROLLBACK", - "sql" => "ROLLBACK TRANSACTION", - "sqltime" => 0, - "displayQuery" => "ROLLBACK TRANSACTION", - "nbrows" => 0, - ); - return self::$instance[$this->dsn]->rollback (); - } - - /** Return the connected database name from DSN used to connect - */ - public function databasename () - { - if ($this->sep === "") - $this->DBException (dgettext ("domframework", "Database not connected")); - if ($this->driver === "sqlite") + /** Return all the tables available in the database + */ + public function listTables() { - $dbFile = substr (strstr ($this->dsn, ":"), 1); - if (trim ($dbFile) !== "") - return $dbFile; - return null; - } - $vals = explode (";", substr (strstr ($this->dsn, ":"), 1)); - $dsnExplode = array (); - foreach ($vals as $val) - { - @list ($k, $v) = explode ("=", $val); - $dsnExplode[$k] = $v; - } - if (isset ($dsnExplode["dbname"])) - return $dsnExplode["dbname"]; - return NULL; - } - - /** Return all the tables available in the database - */ - public function listTables () - { - if ($this->sep === "") - $this->DBException (dgettext ("domframework", "Database not connected")); - switch (self::$instance[$this->dsn]->getAttribute (\PDO::ATTR_DRIVER_NAME)) - { - case "sqlite": - $req = "SELECT name FROM sqlite_master WHERE type='table'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - { - if ($d["name"] !== "sqlite_sequence") - $res[] = $d["name"]; - } - break; - case "mysql": - $req = "SELECT TABLE_NAME + if ($this->sep === "") { + $this->DBException(dgettext("domframework", "Database not connected")); + } + switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + case "sqlite": + $req = "SELECT name FROM sqlite_master WHERE type='table'"; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + if ($d["name"] !== "sqlite_sequence") { + $res[] = $d["name"]; + } + } + break; + case "mysql": + $req = "SELECT TABLE_NAME FROM information_schema.tables - WHERE TABLE_SCHEMA='".$this->databasename ()."'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d["TABLE_NAME"]; - break; - case "pgsql": - $req = "SELECT * + WHERE TABLE_SCHEMA='" . $this->databasename() . "'"; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d["TABLE_NAME"]; + } + break; + case "pgsql": + $req = "SELECT * FROM pg_tables WHERE schemaname = 'public'"; - $st = self::$instance[$this->dsn]->prepare ($req); - $st->execute (); - $res = array (); - while ($d = $st->fetch (\PDO::FETCH_ASSOC)) - $res[] = $d["tablename"]; - break; - default: - $this->DBException (dgettext ("domframework", - "Unknown database driver in listTables")); - } - natsort ($res); - return array_values ($res); - } - - /** Create the table defined by the differents fields. - * Define the SQL syntax based on SQL engines - * $table = "dns zones"; - * $fields = array ( - * "id"=>array ("integer", "not null", "autoincrement"), - * "zo ne"=>array ("varchar(255)", "not null"), - * "vie wname"=>array ("varchar(255)"), - * "view clients"=>array ("varchar(255)"), - * "comme nt"=>array ("varchar(1024)"), - * "opendate"=>array ("datetime", "not null"), - * "closedate"=>array ("datetime"), - * ); - * $primary = "id"; - * $unique = array ("id", array ("zo ne", "vie wname")); - * $foreign = array ("zone"=>"table.field", ...); - */ - public function createTable () - { - $this->debugLog ("Entering createTable", 2); - if ($this->sep === "") - $this->DBException (dgettext ("domframework", "Database not connected"), - 500); - if (count ($this->fields) === 0) - $this->DBException (dgettext ("domframework", "No Field defined"), 500); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to create the table"), 500); - switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) - { - case "sqlite": - $sql = "CREATE TABLE IF NOT EXISTS ". - "$this->sep$this->tableprefix$this->table$this->sep ". - "(\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "$this->sep$field$this->sep "; - switch ($this->fieldTypeLight ($field)) - { - case "blob": - $sql .= "BLOB"; - $params = array_slice ($params, 1); - break; - case "datetime": - $sql .= "DATETIME"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - case "float": - $sql .= "FLOAT"; - $params = array_slice ($params, 1); - break; - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - $length = $this->fieldLength ($field); - $sql .= "VARCHAR($length)"; - $params = array_slice ($params, 1); - break; - default: - $this->DBException (sprintf ( - dgettext ("domframework", - "Unknown type '%s' provided for field '%s'"), - $this->fieldTypeLight ($field), $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; - case "autoincrement": - if ($this->primary !== $field) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Field '%s' is autoincrement but not primary"), - $field), 500); - $sql .= " AUTOINCREMENT"; - break; - default: - $this->DBException (sprintf (dgettext ("domframework", - "Unknown additionnal parameter '%s' for field '%s'"), - $p, $field), 500); - } - } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - if (!is_array ($this->unique)) - $this->DBException (dgettext ("domframework", - "The Unique field definition is not an array"), - 500); - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE ($this->sep"; - if (is_array ($u)) - $sql .=implode ("$this->sep,$this->sep", $u); - else - $sql .= $u; - $sql .="$this->sep)"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $field = explode (",", $field); - $field = implode ($this->sep.",".$this->sep, $field); - $k[1] = explode (",", $k[1]); - $k[1] = implode ($this->sep.",".$this->sep, $k[1]); - $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) ". - "REFERENCES $this->sep".$k[0]."$this->sep($this->sep". - $k[1]."$this->sep)"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - $i++; - } - $sql .=")"; - break; - case "mysql": - $sql = "CREATE TABLE IF NOT EXISTS ". - "$this->sep$this->tableprefix$this->table$this->sep ". - "(\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "$this->sep$field$this->sep "; - switch ($this->fieldTypeLight ($field)) - { - case "blob": - $sql .= "BLOB"; - $params = array_slice ($params, 1); - break; - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - $length = $this->fieldLength ($field); - $sql .= "VARCHAR($length)"; - $params = array_slice ($params, 1); - break; - case "float": - $sql .= "FLOAT"; - $params = array_slice ($params, 1); - break; - case "datetime": - $sql .= "DATETIME"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - default: - $this->DBException (sprintf ( - dgettext ("domframework", - "Unknown type provided for field '%s'"), - $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; - case "autoincrement": - if ($this->primary !== $field) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Field '%s' is autoincrement but not primary"), - $field), 500); - $sql .= " AUTO_INCREMENT"; - break; - default: - $this->DBException (sprintf ( - dgettext ("domframework", - "Unknown additionnal '%s' parameter for field '%s'"), - $p, $field), 500); - } - } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE ($this->sep"; - if (is_array ($u)) - $sql .=implode ("$this->sep,$this->sep", $u); - else - $sql .= $u; - $sql .="$this->sep)"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $field = explode (",", $field); - $field = implode ($this->sep.",".$this->sep, $field); - $k[1] = explode (",", $k[1]); - $k[1] = implode ($this->sep.",".$this->sep, $k[1]); - $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) ". - "REFERENCES $this->sep".$k[0]."$this->sep($this->sep". - $k[1]."$this->sep)"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - $i++; - } - $sql .=") ENGINE=InnoDB DEFAULT CHARSET=utf8;"; - break; - case "pgsql": - $sql = "CREATE TABLE IF NOT EXISTS ". - "\"$this->tableprefix$this->table\" (\n"; - $i = 0; - foreach ($this->fields as $field=>$params) - { - if ($i > 0) - $sql .= ",\n"; - // Name of field - $sql .= "\"$field\" "; - if (in_array ("autoincrement", $params)) - { - if ($this->primary !== $field) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Field '%s' is autoincrement but not primary"), - $field), 500); - $sql .= "SERIAL"; - } - else - { - switch ($this->fieldTypeLight ($field)) - { - case "blob": - $sql .= "BLOB"; - $params = array_slice ($params, 1); - break; - case "integer": - $sql .= "INTEGER"; - $params = array_slice ($params, 1); - break; - case "varchar": - $length = $this->fieldLength ($field); - $sql .= "VARCHAR($length)"; - $params = array_slice ($params, 1); - break; - case "float": - $sql .= "FLOAT"; - $params = array_slice ($params, 1); - break; - case "datetime": - $sql .= "timestamp with time zone"; - $params = array_slice ($params, 1); - break; - case "date": - $sql .= "DATE"; - $params = array_slice ($params, 1); - break; - default: - $this->DBException (sprintf ( - dgettext ("domframework", - "Unknown type provided for field '%s'"), - $field), 500); - } - // Primary key - if ($this->primary === $field) - $sql .= " PRIMARY KEY"; - // Others parameters for field - // Sort to put the autoincrement field in front of params, if it is - // present - sort ($params); - foreach ($params as $p) - { - switch ($p) - { - case "not null": $sql .= " NOT NULL"; break; + $st = self::$instance[$this->dsn]->prepare($req); + $st->execute(); + $res = array(); + while ($d = $st->fetch(\PDO::FETCH_ASSOC)) { + $res[] = $d["tablename"]; + } + break; default: - $this->DBException (sprintf ( - dgettext ("domframework", - "Unknown additionnal parameter '%s' for field '%s'"), - $p, $field), 500); - } - } + $this->DBException(dgettext( + "domframework", + "Unknown database driver in listTables" + )); } - $i ++; - } - // Unique fields - if ($this->unique !== null) - { - foreach ($this->unique as $u) - { - $sql .= ",\n UNIQUE (\""; - if (is_array ($u)) - $sql .= implode ("\",\"", $u); - else - $sql .= $u; - $sql .="\")"; - } - } - // Foreign keys - $i = 0; - foreach ($this->foreign as $field=>$k) - { - $field = explode (",", $field); - $field = implode ($this->sep.",".$this->sep, $field); - $k[1] = explode (",", $k[1]); - $k[1] = implode ($this->sep.",".$this->sep, $k[1]); - $sql .= ",\n FOREIGN KEY(\"$field\") REFERENCES \"".$k[0]."\"(\"". - $k[1]."\")"; - if (isset ($k[2])) - $sql .= " ".$k[2]; - $i++; - } - $sql .=")"; - break; - default: - $this->DBException (dgettext ("domframework", - "PDO Engine not supported in dbLayeroo"), 500); + natsort($res); + return array_values($res); } - $this->debugLog ($sql, 1); - return self::$instance[$this->dsn]->exec ($sql); - } - - /** Drop the table - */ - public function dropTable () - { - $this->debugLog ("Entering dropTable ()", 2); - if ($this->sep === "") - $this->DBException (dgettext ("domframework", "Database not connected")); - if ($this->table === null) - throw new \Exception (dgettext ("domframework", - "No table name defined to drop the table"), 500); - $sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep"; - $this->debugLog ($sql, 1); - return self::$instance[$this->dsn]->exec ($sql); - } - - /** Get the informations about a table - * @param string $tableName The table to examine - */ - public function getTableSchema ($tableName) - { - $this->debugLog ("Entering getTableSchema (",$tableName,")", 2); - switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) + /** Create the table defined by the differents fields. + * Define the SQL syntax based on SQL engines + * $table = "dns zones"; + * $fields = array ( + * "id"=>array ("integer", "not null", "autoincrement"), + * "zo ne"=>array ("varchar(255)", "not null"), + * "vie wname"=>array ("varchar(255)"), + * "view clients"=>array ("varchar(255)"), + * "comme nt"=>array ("varchar(1024)"), + * "opendate"=>array ("datetime", "not null"), + * "closedate"=>array ("datetime"), + * ); + * $primary = "id"; + * $unique = array ("id", array ("zo ne", "vie wname")); + * $foreign = array ("zone"=>"table.field", ...); + */ + public function createTable() { - case "sqlite": - $st = self::$instance[$this->dsn]->prepare ( - "PRAGMA table_info($tableName)"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - $fields = array (); - $unique = array (); - $foreign = array (); - $primary = ""; - foreach ($content as $row) - { - $type = str_replace (" ", "", strtolower ($row["type"])); - $fields[$row["name"]][] = $type; - if ($row["notnull"] === "1") - $fields[$row["name"]][] = "not null"; - if ($row["pk"] === "1") - $primary = $row["name"]; - } - - $st = self::$instance[$this->dsn]->prepare ( - "PRAGMA index_list($tableName)"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $c) - { - $st = self::$instance[$this->dsn]->prepare ( - "PRAGMA index_info(".$c["name"].")"); - $st->execute (); - $content2 = $st->fetchAll (\PDO::FETCH_ASSOC); - if (count ($content2) > 1) - { - $index = array (); - foreach ($content2 as $c2) - { - $index[] = $c2["name"]; - } - $unique[$content2[0]["cid"]-1] = $index; + $this->debugLog("Entering createTable", 2); + if ($this->sep === "") { + $this->DBException( + dgettext("domframework", "Database not connected"), + 500 + ); } - elseif (count ($content2) === 1 && $content2[0]["cid"] >= 1) - { - $index = $content2[0]["name"]; - $unique[$content2[0]["cid"]-1] = $index; + if (count($this->fields) === 0) { + $this->DBException(dgettext("domframework", "No Field defined"), 500); } - } - ksort ($unique); - if (! in_array ($primary, $unique)) - $unique[] = $primary; - - try - { - $st = self::$instance[$this->dsn]->prepare ( - "SELECT * FROM sqlite_sequence WHERE name='$tableName'"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - if (count ($content) > 0 && $primary !== "") - $fields[$primary][] = "autoincrement"; - } - catch (\Exception $e) - { - // If no autoincrement key, the sqlite_sequence table doesn't exists - } - - $st = self::$instance[$this->dsn]->prepare ( - "PRAGMA foreign_key_list('$tableName')"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $for) - { - $tmp = array ($for["table"], $for["to"]); - $cascade = ""; - if ($for["on_update"] !== "NO ACTION") - $cascade .= "ON UPDATE ".$for["on_update"]; - if ($for["on_delete"] !== "NO ACTION") - $cascade .= "ON DELETE ".$for["on_delete"]; - if ($cascade !== "") - $tmp[] = $cascade; - $foreign[$for["from"]] = $tmp; - } - - $foreignUsed = array (); - foreach ($this->listTables () as $tbl) - { - $st = self::$instance[$this->dsn]->prepare ( - "PRAGMA foreign_key_list($tbl)"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $row) - { - if ($row["table"] !== $tableName) - continue; - $foreignUsed[$row["to"]][] = array ( - $tbl, $row["from"] - ); + if ($this->table === null) { + throw new \Exception(dgettext( + "domframework", + "No table name defined to create the table" + ), 500); } - } - return array ("table" => $tableName, + switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + case "sqlite": + $sql = "CREATE TABLE IF NOT EXISTS " . + "$this->sep$this->tableprefix$this->table$this->sep " . + "(\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "$this->sep$field$this->sep "; + switch ($this->fieldTypeLight($field)) { + case "blob": + $sql .= "BLOB"; + $params = array_slice($params, 1); + break; + case "datetime": + $sql .= "DATETIME"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + case "float": + $sql .= "FLOAT"; + $params = array_slice($params, 1); + break; + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + $length = $this->fieldLength($field); + $sql .= "VARCHAR($length)"; + $params = array_slice($params, 1); + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown type '%s' provided for field '%s'" + ), + $this->fieldTypeLight($field), + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + case "autoincrement": + if ($this->primary !== $field) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Field '%s' is autoincrement but not primary" + ), + $field + ), 500); + } + $sql .= " AUTOINCREMENT"; + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown additionnal parameter '%s' for field '%s'" + ), + $p, + $field + ), 500); + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + if (!is_array($this->unique)) { + $this->DBException( + dgettext( + "domframework", + "The Unique field definition is not an array" + ), + 500 + ); + } + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE ($this->sep"; + if (is_array($u)) { + $sql .= implode("$this->sep,$this->sep", $u); + } else { + $sql .= $u; + } + $sql .= "$this->sep)"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $field = explode(",", $field); + $field = implode($this->sep . "," . $this->sep, $field); + $k[1] = explode(",", $k[1]); + $k[1] = implode($this->sep . "," . $this->sep, $k[1]); + $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) " . + "REFERENCES $this->sep" . $k[0] . "$this->sep($this->sep" . + $k[1] . "$this->sep)"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + $i++; + } + $sql .= ")"; + break; + case "mysql": + $sql = "CREATE TABLE IF NOT EXISTS " . + "$this->sep$this->tableprefix$this->table$this->sep " . + "(\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "$this->sep$field$this->sep "; + switch ($this->fieldTypeLight($field)) { + case "blob": + $sql .= "BLOB"; + $params = array_slice($params, 1); + break; + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + $length = $this->fieldLength($field); + $sql .= "VARCHAR($length)"; + $params = array_slice($params, 1); + break; + case "float": + $sql .= "FLOAT"; + $params = array_slice($params, 1); + break; + case "datetime": + $sql .= "DATETIME"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown type provided for field '%s'" + ), + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + case "autoincrement": + if ($this->primary !== $field) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Field '%s' is autoincrement but not primary" + ), + $field + ), 500); + } + $sql .= " AUTO_INCREMENT"; + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown additionnal '%s' parameter for field '%s'" + ), + $p, + $field + ), 500); + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE ($this->sep"; + if (is_array($u)) { + $sql .= implode("$this->sep,$this->sep", $u); + } else { + $sql .= $u; + } + $sql .= "$this->sep)"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $field = explode(",", $field); + $field = implode($this->sep . "," . $this->sep, $field); + $k[1] = explode(",", $k[1]); + $k[1] = implode($this->sep . "," . $this->sep, $k[1]); + $sql .= ",\n FOREIGN KEY($this->sep$field$this->sep) " . + "REFERENCES $this->sep" . $k[0] . "$this->sep($this->sep" . + $k[1] . "$this->sep)"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + $i++; + } + $sql .= ") ENGINE=InnoDB DEFAULT CHARSET=utf8;"; + break; + case "pgsql": + $sql = "CREATE TABLE IF NOT EXISTS " . + "\"$this->tableprefix$this->table\" (\n"; + $i = 0; + foreach ($this->fields as $field => $params) { + if ($i > 0) { + $sql .= ",\n"; + } + // Name of field + $sql .= "\"$field\" "; + if (in_array("autoincrement", $params)) { + if ($this->primary !== $field) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Field '%s' is autoincrement but not primary" + ), + $field + ), 500); + } + $sql .= "SERIAL"; + } else { + switch ($this->fieldTypeLight($field)) { + case "blob": + $sql .= "BLOB"; + $params = array_slice($params, 1); + break; + case "integer": + $sql .= "INTEGER"; + $params = array_slice($params, 1); + break; + case "varchar": + $length = $this->fieldLength($field); + $sql .= "VARCHAR($length)"; + $params = array_slice($params, 1); + break; + case "float": + $sql .= "FLOAT"; + $params = array_slice($params, 1); + break; + case "datetime": + $sql .= "timestamp with time zone"; + $params = array_slice($params, 1); + break; + case "date": + $sql .= "DATE"; + $params = array_slice($params, 1); + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown type provided for field '%s'" + ), + $field + ), 500); + } + // Primary key + if ($this->primary === $field) { + $sql .= " PRIMARY KEY"; + } + // Others parameters for field + // Sort to put the autoincrement field in front of params, if it is + // present + sort($params); + foreach ($params as $p) { + switch ($p) { + case "not null": + $sql .= " NOT NULL"; + break; + default: + $this->DBException(sprintf( + dgettext( + "domframework", + "Unknown additionnal parameter '%s' for field '%s'" + ), + $p, + $field + ), 500); + } + } + } + $i++; + } + // Unique fields + if ($this->unique !== null) { + foreach ($this->unique as $u) { + $sql .= ",\n UNIQUE (\""; + if (is_array($u)) { + $sql .= implode("\",\"", $u); + } else { + $sql .= $u; + } + $sql .= "\")"; + } + } + // Foreign keys + $i = 0; + foreach ($this->foreign as $field => $k) { + $field = explode(",", $field); + $field = implode($this->sep . "," . $this->sep, $field); + $k[1] = explode(",", $k[1]); + $k[1] = implode($this->sep . "," . $this->sep, $k[1]); + $sql .= ",\n FOREIGN KEY(\"$field\") REFERENCES \"" . $k[0] . "\"(\"" . + $k[1] . "\")"; + if (isset($k[2])) { + $sql .= " " . $k[2]; + } + $i++; + } + $sql .= ")"; + break; + default: + $this->DBException(dgettext( + "domframework", + "PDO Engine not supported in dbLayeroo" + ), 500); + } + + $this->debugLog($sql, 1); + return self::$instance[$this->dsn]->exec($sql); + } + + /** Drop the table + */ + public function dropTable() + { + $this->debugLog("Entering dropTable ()", 2); + if ($this->sep === "") { + $this->DBException(dgettext("domframework", "Database not connected")); + } + if ($this->table === null) { + throw new \Exception(dgettext( + "domframework", + "No table name defined to drop the table" + ), 500); + } + $sql = "DROP TABLE $this->sep$this->tableprefix$this->table$this->sep"; + $this->debugLog($sql, 1); + return self::$instance[$this->dsn]->exec($sql); + } + + /** Get the informations about a table + * @param string $tableName The table to examine + */ + public function getTableSchema($tableName) + { + $this->debugLog("Entering getTableSchema (", $tableName, ")", 2); + switch (self::$instance[$this->dsn]->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + case "sqlite": + $st = self::$instance[$this->dsn]->prepare( + "PRAGMA table_info($tableName)" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + $fields = array(); + $unique = array(); + $foreign = array(); + $primary = ""; + foreach ($content as $row) { + $type = str_replace(" ", "", strtolower($row["type"])); + $fields[$row["name"]][] = $type; + if ($row["notnull"] === "1") { + $fields[$row["name"]][] = "not null"; + } + if ($row["pk"] === "1") { + $primary = $row["name"]; + } + } + + $st = self::$instance[$this->dsn]->prepare( + "PRAGMA index_list($tableName)" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $c) { + $st = self::$instance[$this->dsn]->prepare( + "PRAGMA index_info(" . $c["name"] . ")" + ); + $st->execute(); + $content2 = $st->fetchAll(\PDO::FETCH_ASSOC); + if (count($content2) > 1) { + $index = array(); + foreach ($content2 as $c2) { + $index[] = $c2["name"]; + } + $unique[$content2[0]["cid"] - 1] = $index; + } elseif (count($content2) === 1 && $content2[0]["cid"] >= 1) { + $index = $content2[0]["name"]; + $unique[$content2[0]["cid"] - 1] = $index; + } + } + ksort($unique); + if (! in_array($primary, $unique)) { + $unique[] = $primary; + } + + try { + $st = self::$instance[$this->dsn]->prepare( + "SELECT * FROM sqlite_sequence WHERE name='$tableName'" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + if (count($content) > 0 && $primary !== "") { + $fields[$primary][] = "autoincrement"; + } + } catch (\Exception $e) { + // If no autoincrement key, the sqlite_sequence table doesn't exists + } + + $st = self::$instance[$this->dsn]->prepare( + "PRAGMA foreign_key_list('$tableName')" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $for) { + $tmp = array($for["table"], $for["to"]); + $cascade = ""; + if ($for["on_update"] !== "NO ACTION") { + $cascade .= "ON UPDATE " . $for["on_update"]; + } + if ($for["on_delete"] !== "NO ACTION") { + $cascade .= "ON DELETE " . $for["on_delete"]; + } + if ($cascade !== "") { + $tmp[] = $cascade; + } + $foreign[$for["from"]] = $tmp; + } + + $foreignUsed = array(); + foreach ($this->listTables() as $tbl) { + $st = self::$instance[$this->dsn]->prepare( + "PRAGMA foreign_key_list($tbl)" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $row) { + if ($row["table"] !== $tableName) { + continue; + } + $foreignUsed[$row["to"]][] = array( + $tbl, $row["from"] + ); + } + } + return array("table" => $tableName, "fields" => $fields, "primary" => $primary, "unique" => $unique, "foreign" => $foreign, "foreignUsed" => $foreignUsed); - break; - case "mysql": - $st = self::$instance[$this->dsn]->prepare ( - "SHOW COLUMNS FROM `$tableName`"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - $fields = array (); - $unique = array (); - $foreign = array ("TBD"); - $primary = ""; - foreach ($content as $col) - { - $tmp = array (); - if ($col["Type"] === "int(11)") - $tmp[] = "integer"; - else - $tmp[] = $col["Type"]; - if ($col["Null"] === "NO") - $tmp[] = "not null"; - if ($col["Extra"] === "auto_increment") - $tmp[] = "autoincrement"; - $fields[$col["Field"]] = $tmp; - } - $st = self::$instance[$this->dsn]->prepare ( - "SHOW INDEX FROM `$tableName`"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $col) - { - if ($col["Key_name"] === "PRIMARY") - $primary = $col["Column_name"]; - else - { - if ($col["Non_unique"] === "1") - continue; - if (array_key_exists ($col["Key_name"], $unique)) - { - if (!is_array ($unique[$col["Key_name"]])) - $unique[$col["Key_name"]] = array ($unique[$col["Key_name"]]); - $unique[$col["Key_name"]][] = $col["Column_name"]; - } - else - { - $unique[$col["Key_name"]] = $col["Column_name"]; - } - } - } - $unique = array_values ($unique); - if (! in_array ($primary, $unique)) - $unique[] = $primary; - $st = self::$instance[$this->dsn]->prepare (" + break; + case "mysql": + $st = self::$instance[$this->dsn]->prepare( + "SHOW COLUMNS FROM `$tableName`" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + $fields = array(); + $unique = array(); + $foreign = array("TBD"); + $primary = ""; + foreach ($content as $col) { + $tmp = array(); + if ($col["Type"] === "int(11)") { + $tmp[] = "integer"; + } else { + $tmp[] = $col["Type"]; + } + if ($col["Null"] === "NO") { + $tmp[] = "not null"; + } + if ($col["Extra"] === "auto_increment") { + $tmp[] = "autoincrement"; + } + $fields[$col["Field"]] = $tmp; + } + $st = self::$instance[$this->dsn]->prepare( + "SHOW INDEX FROM `$tableName`" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $col) { + if ($col["Key_name"] === "PRIMARY") { + $primary = $col["Column_name"]; + } else { + if ($col["Non_unique"] === "1") { + continue; + } + if (array_key_exists($col["Key_name"], $unique)) { + if (!is_array($unique[$col["Key_name"]])) { + $unique[$col["Key_name"]] = array($unique[$col["Key_name"]]); + } + $unique[$col["Key_name"]][] = $col["Column_name"]; + } else { + $unique[$col["Key_name"]] = $col["Column_name"]; + } + } + } + $unique = array_values($unique); + if (! in_array($primary, $unique)) { + $unique[] = $primary; + } + $st = self::$instance[$this->dsn]->prepare(" SELECT UPDATE_RULE,DELETE_RULE,COLUMN_NAME, kColUsage.REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM information_schema.REFERENTIAL_CONSTRAINTS AS rCons, @@ -858,59 +954,64 @@ class Dblayeroo WHERE rCons.CONSTRAINT_SCHEMA=:dbname AND rCons.TABLE_NAME=:table AND rCons.CONSTRAINT_NAME=kColUsage.CONSTRAINT_NAME AND rCons.CONSTRAINT_SCHEMA=kColUsage.CONSTRAINT_SCHEMA"); - $st->execute (array(':dbname' => $this->databasename (), + $st->execute(array(':dbname' => $this->databasename(), ':table' => $tableName)); - $foreignTmp = $st->fetchAll (\PDO::FETCH_ASSOC); - $foreign = array (); - foreach ($foreignTmp as $f) - { - $tmp = array (); - $tmp[] = $f["REFERENCED_TABLE_NAME"]; - $tmp[] = $f["REFERENCED_COLUMN_NAME"]; - $tmp[2] = ""; - if ($f["UPDATE_RULE"] !== "NO ACTION" && - $f["UPDATE_RULE"] !== "RESTRICT") - $tmp[2] .= "ON UPDATE ".$f["UPDATE_RULE"]." "; - if ($f["DELETE_RULE"] !== "NO ACTION" && - $f["DELETE_RULE"] !== "RESTRICT") - $tmp[2] .= "ON DELETE ".$f["DELETE_RULE"]; - if ($tmp[2] !== "") - $tmp[2] = trim ($tmp[2]); - else - unset ($tmp[2]); - $foreign[$f["COLUMN_NAME"]] = $tmp; - } + $foreignTmp = $st->fetchAll(\PDO::FETCH_ASSOC); + $foreign = array(); + foreach ($foreignTmp as $f) { + $tmp = array(); + $tmp[] = $f["REFERENCED_TABLE_NAME"]; + $tmp[] = $f["REFERENCED_COLUMN_NAME"]; + $tmp[2] = ""; + if ( + $f["UPDATE_RULE"] !== "NO ACTION" && + $f["UPDATE_RULE"] !== "RESTRICT" + ) { + $tmp[2] .= "ON UPDATE " . $f["UPDATE_RULE"] . " "; + } + if ( + $f["DELETE_RULE"] !== "NO ACTION" && + $f["DELETE_RULE"] !== "RESTRICT" + ) { + $tmp[2] .= "ON DELETE " . $f["DELETE_RULE"]; + } + if ($tmp[2] !== "") { + $tmp[2] = trim($tmp[2]); + } else { + unset($tmp[2]); + } + $foreign[$f["COLUMN_NAME"]] = $tmp; + } - $st = self::$instance[$this->dsn]->prepare (" + $st = self::$instance[$this->dsn]->prepare(" SELECT TABLE_NAME,COLUMN_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME=:table AND TABLE_SCHEMA=:dbname"); - $st->execute (array(':dbname' => $this->databasename (), + $st->execute(array(':dbname' => $this->databasename(), ':table' => $tableName)); - $foreignUsedTmp = $st->fetchAll (\PDO::FETCH_ASSOC); - $foreignUsed = array (); - foreach ($foreignUsedTmp as $f) - { - $foreignUsed[$f["REFERENCED_COLUMN_NAME"]][] = array ( - $f["TABLE_NAME"], - $f["COLUMN_NAME"]); - } - return array ("table" => $tableName, + $foreignUsedTmp = $st->fetchAll(\PDO::FETCH_ASSOC); + $foreignUsed = array(); + foreach ($foreignUsedTmp as $f) { + $foreignUsed[$f["REFERENCED_COLUMN_NAME"]][] = array( + $f["TABLE_NAME"], + $f["COLUMN_NAME"]); + } + return array("table" => $tableName, "fields" => $fields, "primary" => $primary, "unique" => $unique, "foreign" => $foreign, "foreignUsed" => $foreignUsed); - break; - case "pgsql": - $fields = array (); - $unique = array (); - $foreign = array (); - $primary = ""; - // Get the defined primary key if not autoincrement - $st = self::$instance[$this->dsn]->prepare (" + break; + case "pgsql": + $fields = array(); + $unique = array(); + $foreign = array(); + $primary = ""; + // Get the defined primary key if not autoincrement + $st = self::$instance[$this->dsn]->prepare(" SELECT a.attname, format_type(a.atttypid, a.atttypmod) AS data_type FROM pg_index i JOIN pg_attribute a ON a.attrelid = i.indrelid @@ -918,58 +1019,59 @@ class Dblayeroo WHERE i.indrelid = :table::regclass AND i.indisprimary; "); - $st->execute (array(':table' => $tableName)); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - if (key_exists (0, $content)) - $primary = $content[0]["attname"]; - // Get the primary key if autoincrement - $st = self::$instance[$this->dsn]->prepare ( - "SELECT * + $st->execute(array(':table' => $tableName)); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + if (key_exists(0, $content)) { + $primary = $content[0]["attname"]; + } + // Get the primary key if autoincrement + $st = self::$instance[$this->dsn]->prepare( + "SELECT * FROM information_schema.columns - WHERE table_schema='public' and table_name='$tableName'"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $col) - { - $tmp = array (); - if ($col["data_type"] === "character varying") - $tmp[] = "varchar(".$col["character_maximum_length"].")"; - else - $tmp[] = $col["data_type"]; - if ($col["is_nullable"] === "NO") - $tmp[] = "not null"; - if (substr ($col["column_default"], 0, 7) === "nextval") - { - $tmp[] = "autoincrement"; - $primary = $col["column_name"]; - } - $fields[$col["column_name"]] = $tmp; - } + WHERE table_schema='public' and table_name='$tableName'" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $col) { + $tmp = array(); + if ($col["data_type"] === "character varying") { + $tmp[] = "varchar(" . $col["character_maximum_length"] . ")"; + } else { + $tmp[] = $col["data_type"]; + } + if ($col["is_nullable"] === "NO") { + $tmp[] = "not null"; + } + if (substr($col["column_default"], 0, 7) === "nextval") { + $tmp[] = "autoincrement"; + $primary = $col["column_name"]; + } + $fields[$col["column_name"]] = $tmp; + } - $st = self::$instance[$this->dsn]->prepare ( - "SELECT * + $st = self::$instance[$this->dsn]->prepare( + "SELECT * FROM information_schema.constraint_column_usage - WHERE table_name='$tableName'"); - $st->execute (); - $content = $st->fetchAll (\PDO::FETCH_ASSOC); - foreach ($content as $col) - { - if (array_key_exists ($col["constraint_name"], $unique)) - { - if (! is_array ($unique[$col["constraint_name"]])) - $unique[$col["constraint_name"]] = - array ($unique[$col["constraint_name"]]); - $unique[$col["constraint_name"]][] = $col["column_name"]; - } - elseif (! in_array ($col["column_name"], $unique)) - { - $unique[$col["constraint_name"]] = $col["column_name"]; - } - } - $unique = array_values ($unique); - if (! in_array ($primary, $unique)) - $unique[] = $primary; - $st = self::$instance[$this->dsn]->prepare (" + WHERE table_name='$tableName'" + ); + $st->execute(); + $content = $st->fetchAll(\PDO::FETCH_ASSOC); + foreach ($content as $col) { + if (array_key_exists($col["constraint_name"], $unique)) { + if (! is_array($unique[$col["constraint_name"]])) { + $unique[$col["constraint_name"]] = + array($unique[$col["constraint_name"]]); + } + $unique[$col["constraint_name"]][] = $col["column_name"]; + } elseif (! in_array($col["column_name"], $unique)) { + $unique[$col["constraint_name"]] = $col["column_name"]; + } + } + $unique = array_values($unique); + if (! in_array($primary, $unique)) { + $unique[] = $primary; + } + $st = self::$instance[$this->dsn]->prepare(" SELECT kColUsage1.column_name COLUMN_NAME, kColUsage2.table_name REFERENCED_TABLE_NAME, kColUsage2.column_name REFERENCED_COLUMN_NAME, @@ -981,30 +1083,36 @@ class Dblayeroo AND rCons.constraint_name=kColUsage1.constraint_name AND rCons.unique_constraint_name=kColUsage2.constraint_name "); - $st->execute (array(':dbname' => $this->databasename (), + $st->execute(array(':dbname' => $this->databasename(), ':table' => $tableName)); - $foreignTmp = $st->fetchAll (\PDO::FETCH_ASSOC); - $foreign = array (); - foreach ($foreignTmp as $f) - { - $tmp = array (); - $tmp[] = $f["referenced_table_name"]; - $tmp[] = $f["referenced_column_name"]; - $tmp[2] = ""; - if ($f["update_rule"] !== "NO ACTION" && - $f["update_rule"] !== "RESTRICT") - $tmp[2] .= "ON UPDATE ".$f["update_rule"]." "; - if ($f["delete_rule"] !== "NO ACTION" && - $f["delete_rule"] !== "RESTRICT") - $tmp[2] .= "ON DELETE ".$f["delete_rule"]; - if ($tmp[2] !== "") - $tmp[2] = trim ($tmp[2]); - else - unset ($tmp[2]); - $foreign[$f["column_name"]] = $tmp; - } + $foreignTmp = $st->fetchAll(\PDO::FETCH_ASSOC); + $foreign = array(); + foreach ($foreignTmp as $f) { + $tmp = array(); + $tmp[] = $f["referenced_table_name"]; + $tmp[] = $f["referenced_column_name"]; + $tmp[2] = ""; + if ( + $f["update_rule"] !== "NO ACTION" && + $f["update_rule"] !== "RESTRICT" + ) { + $tmp[2] .= "ON UPDATE " . $f["update_rule"] . " "; + } + if ( + $f["delete_rule"] !== "NO ACTION" && + $f["delete_rule"] !== "RESTRICT" + ) { + $tmp[2] .= "ON DELETE " . $f["delete_rule"]; + } + if ($tmp[2] !== "") { + $tmp[2] = trim($tmp[2]); + } else { + unset($tmp[2]); + } + $foreign[$f["column_name"]] = $tmp; + } - $st = self::$instance[$this->dsn]->prepare (" + $st = self::$instance[$this->dsn]->prepare(" SELECT kColUsage1.table_name TABLE_NAME, kColUsage1.column_name COLUMN_NAME, kColUsage2.table_name REFERENCED_TABLE_NAME, @@ -1020,408 +1128,472 @@ class Dblayeroo AND rCons.unique_constraint_name=kColUsage2.constraint_name ORDER BY kColUsage1.table_name "); - $st->execute ( - array(':dbname' => $this->databasename (), - ':table' => $tableName)); + $st->execute( + array(':dbname' => $this->databasename(), + ':table' => $tableName) + ); - $foreignUsedTmp = $st->fetchAll (\PDO::FETCH_ASSOC); - $foreignUsed = array (); - foreach ($foreignUsedTmp as $f) - { - $foreignUsed[$f["referenced_column_name"]][] = array ( - $f["table_name"], - $f["column_name"]); - } + $foreignUsedTmp = $st->fetchAll(\PDO::FETCH_ASSOC); + $foreignUsed = array(); + foreach ($foreignUsedTmp as $f) { + $foreignUsed[$f["referenced_column_name"]][] = array( + $f["table_name"], + $f["column_name"]); + } - return array ("table" => $tableName, + return array("table" => $tableName, "fields" => $fields, "primary" => $primary, "unique" => $unique, "foreign" => $foreign, "foreignUsed" => $foreignUsed); - break; - default: - $this->DBException (dgettext ("domframework", - "PDO Engine not supported in dbLayeroo"), 500); + break; + default: + $this->DBException(dgettext( + "domframework", + "PDO Engine not supported in dbLayeroo" + ), 500); + } } - } - /** Return the type of the provided field - * @param string $field The field to get the type - */ - private function fieldTypeComplete ($field) - { + /** Return the type of the provided field + * @param string $field The field to get the type + */ + private function fieldTypeComplete($field) + { // $this->debugLog ("Entering fieldTypeComplete (",$field,")", 2); - if (! array_key_exists ($field, $this->fields)) - $this->DBException (sprintf ( - "fieldType : can't find the definition for field '%s'", - $field)); - if (! array_key_exists (0, $this->fields[$field])) - $this->DBException (sprintf ( - "fieldType : can't find the type for field '%s'", - $field)); - if (! is_string ($this->fields[$field][0])) - $this->DBException (sprintf ( - "fieldType : The type of field '%s' is not a string", - $field)); - $type = strtolower ($this->fields[$field][0]); - $type = str_replace (" ", "", $type); - return $type; - } + if (! array_key_exists($field, $this->fields)) { + $this->DBException(sprintf( + "fieldType : can't find the definition for field '%s'", + $field + )); + } + if (! array_key_exists(0, $this->fields[$field])) { + $this->DBException(sprintf( + "fieldType : can't find the type for field '%s'", + $field + )); + } + if (! is_string($this->fields[$field][0])) { + $this->DBException(sprintf( + "fieldType : The type of field '%s' is not a string", + $field + )); + } + $type = strtolower($this->fields[$field][0]); + $type = str_replace(" ", "", $type); + return $type; + } - /** Return the type of the provided field. For varchar(255), return only - * varchar - * @param string $field The field to get the type - */ - private function fieldTypeLight ($field) - { - $type = $this->fieldTypeComplete ($field); - list ($type, ) = explode ("(", $type); - return $type; - } - - /** Return the length of a field (generally a varchar) - * @param string $field The field to get the type - */ - private function fieldLength ($field) - { - $type = $this->fieldTypeComplete ($field); - $pos = strpos ($type, "("); - if ($pos === false) - $this->DBException (sprintf ( - "fieldLength : no length defined for field '%s'", $field)); - $length = intval (substr ($type, 1+$pos, -1)); - if ($length === 0) - $this->DBException (sprintf ( - "fieldLength : Length equal to Zero for field '%s'", $field)); - return $length; - } - - ///////////////////////////// - /// GETTERS / SETTERS /// - ///////////////////////////// - /** Get/Set the table property - * @param string|null $table The table to use - */ - public function table ($table = null) - { - $this->debugLog ("Entering table (",$table,")", 2); - if ($table === null) - return $this->table; - if (! is_string ($table)) - $this->DBException ("Parameter table invalid: not a string"); - if (mb_strlen ($table) > 63) - $this->DBException ("Parameter table invalid: too long"); - $this->table = $table; - return $this; - } - - /** Get/Set the tableprefix property - * @param string|null $tableprefix The prefix to append - */ - public function tableprefix ($tableprefix = null) - { - $this->debugLog ("Entering tableprefix (",$tableprefix,")", 2); - if ($tableprefix === null) - return $this->tableprefix; - if (! is_string ($tableprefix)) - $this->DBException ("Parameter tableprefix invalid: not a string"); - // 64 - at least one char for the table name - if (mb_strlen ($tableprefix) > 63) - $this->DBException ("Parameter tableprefix invalid: too long"); - $this->tableprefix = $tableprefix; - return $this; - } - - /** Get/Set the fields property - * The fields to define are in the format: - * array ("fieldName"=>array ("type"[, "not null"[, "autoincrement"]])) - * @param array|null $fields The fields to define - */ - public function fields ($fields = null) - { - $this->debugLog ("Entering fields (VALUE)", 2); - if ($fields === null) - return $this->fields; - if (! is_array ($fields)) - $this->DBException ("Parameter fields invalid: not an array"); - foreach ($fields as $field=>$params) + /** Return the type of the provided field. For varchar(255), return only + * varchar + * @param string $field The field to get the type + */ + private function fieldTypeLight($field) { - if (mb_strlen ($field) > 64) - $this->DBException ("Parameter fields invalid: column name too long"); - if (! is_array ($params)) - $this->DBException ("Parameter fields invalid: ". + $type = $this->fieldTypeComplete($field); + list($type, ) = explode("(", $type); + return $type; + } + + /** Return the length of a field (generally a varchar) + * @param string $field The field to get the type + */ + private function fieldLength($field) + { + $type = $this->fieldTypeComplete($field); + $pos = strpos($type, "("); + if ($pos === false) { + $this->DBException(sprintf( + "fieldLength : no length defined for field '%s'", + $field + )); + } + $length = intval(substr($type, 1 + $pos, -1)); + if ($length === 0) { + $this->DBException(sprintf( + "fieldLength : Length equal to Zero for field '%s'", + $field + )); + } + return $length; + } + + ///////////////////////////// + /// GETTERS / SETTERS /// + ///////////////////////////// + /** Get/Set the table property + * @param string|null $table The table to use + */ + public function table($table = null) + { + $this->debugLog("Entering table (", $table, ")", 2); + if ($table === null) { + return $this->table; + } + if (! is_string($table)) { + $this->DBException("Parameter table invalid: not a string"); + } + if (mb_strlen($table) > 63) { + $this->DBException("Parameter table invalid: too long"); + } + $this->table = $table; + return $this; + } + + /** Get/Set the tableprefix property + * @param string|null $tableprefix The prefix to append + */ + public function tableprefix($tableprefix = null) + { + $this->debugLog("Entering tableprefix (", $tableprefix, ")", 2); + if ($tableprefix === null) { + return $this->tableprefix; + } + if (! is_string($tableprefix)) { + $this->DBException("Parameter tableprefix invalid: not a string"); + } + // 64 - at least one char for the table name + if (mb_strlen($tableprefix) > 63) { + $this->DBException("Parameter tableprefix invalid: too long"); + } + $this->tableprefix = $tableprefix; + return $this; + } + + /** Get/Set the fields property + * The fields to define are in the format: + * array ("fieldName"=>array ("type"[, "not null"[, "autoincrement"]])) + * @param array|null $fields The fields to define + */ + public function fields($fields = null) + { + $this->debugLog("Entering fields (VALUE)", 2); + if ($fields === null) { + return $this->fields; + } + if (! is_array($fields)) { + $this->DBException("Parameter fields invalid: not an array"); + } + foreach ($fields as $field => $params) { + if (mb_strlen($field) > 64) { + $this->DBException("Parameter fields invalid: column name too long"); + } + if (! is_array($params)) { + $this->DBException("Parameter fields invalid: " . "param not an array for '$field'"); - if (array_key_exists (0, $params)) - $fields[$field][0] = strtolower ($fields[$field][0]); - if (array_key_exists (1, $params)) - $fields[$field][1] = strtolower ($fields[$field][1]); - if (array_key_exists (2, $params)) - $fields[$field][2] = strtolower ($fields[$field][2]); - } - foreach ($fields as $field=>$params) - { - if (! array_key_exists (0, $params)) - $this->DBException ("Parameter fields invalid: ". + } + if (array_key_exists(0, $params)) { + $fields[$field][0] = strtolower($fields[$field][0]); + } + if (array_key_exists(1, $params)) { + $fields[$field][1] = strtolower($fields[$field][1]); + } + if (array_key_exists(2, $params)) { + $fields[$field][2] = strtolower($fields[$field][2]); + } + } + foreach ($fields as $field => $params) { + if (! array_key_exists(0, $params)) { + $this->DBException("Parameter fields invalid: " . "No type of column provided for '$field'"); - if (preg_match ("#^(blob|date|datetime|float|integer|time|". + } + if ( + preg_match( + "#^(blob|date|datetime|float|integer|time|" . "varchar\(\d+\))$#i", - $params[0]) !== 1) - $this->DBException ("Parameter fields invalid: ". + $params[0] + ) !== 1 + ) { + $this->DBException("Parameter fields invalid: " . "Unknown column type provided for '$field'"); - if (array_key_exists (1, $params) && - $params[1] !== "not null" && $params[1] !== "autoincrement") - $this->DBException ("Parameter fields invalid: ". + } + if ( + array_key_exists(1, $params) && + $params[1] !== "not null" && $params[1] !== "autoincrement" + ) { + $this->DBException("Parameter fields invalid: " . "Second parameter invalid for '$field'"); - if (array_key_exists (2, $params) && - $params[2] !== "autoincrement") - $this->DBException ("Parameter fields invalid: ". + } + if ( + array_key_exists(2, $params) && + $params[2] !== "autoincrement" + ) { + $this->DBException("Parameter fields invalid: " . "Third parameter invalid for '$field'"); - if ($params[0] !== "integer" && ( - isset ($params[1]) && $params[1] === "autoincrement" || - isset ($params[2]) && $params[2] === "autoincrement")) - $this->DBException ("Parameter fields invalid: ". - "Field '$field' can not be autoincrement and not integer"); - if (array_key_exists (0, $params)) - $fields[$field][0] = strtolower ($fields[$field][0]); - if (array_key_exists (1, $params)) - $fields[$field][1] = strtolower ($fields[$field][1]); - if (array_key_exists (2, $params)) - $fields[$field][2] = strtolower ($fields[$field][2]); + } + if ( + $params[0] !== "integer" && ( + isset($params[1]) && $params[1] === "autoincrement" || + isset($params[2]) && $params[2] === "autoincrement" + ) + ) { + $this->DBException("Parameter fields invalid: " . + "Field '$field' can not be autoincrement and not integer"); + } + if (array_key_exists(0, $params)) { + $fields[$field][0] = strtolower($fields[$field][0]); + } + if (array_key_exists(1, $params)) { + $fields[$field][1] = strtolower($fields[$field][1]); + } + if (array_key_exists(2, $params)) { + $fields[$field][2] = strtolower($fields[$field][2]); + } + } + $this->fields = $fields; + return $this; } - $this->fields = $fields; - return $this; - } - /** Get all the fields with the table name if needed. - * If the objectJoin is set, return the fields name too - * @param boolean|null $full Add the table name if the $full is set - */ - public function fieldsAll ($full = false) - { - $fields = array (); - if ($this->joinObject) + /** Get all the fields with the table name if needed. + * If the objectJoin is set, return the fields name too + * @param boolean|null $full Add the table name if the $full is set + */ + public function fieldsAll($full = false) { - foreach ($this->joinObject as $obj) - $fields = array_merge ($fields, $obj->fieldsAll (true)); - $full = true; + $fields = array(); + if ($this->joinObject) { + foreach ($this->joinObject as $obj) { + $fields = array_merge($fields, $obj->fieldsAll(true)); + } + $full = true; + } + foreach ($this->fields as $f => $val) { + if ($full !== false) { + $fields[$this->sep . $this->tableprefix . $this->table . $this->sep . "." . + $this->sep . $f . $this->sep] = $val; + } else { + $fields[$f] = $val; + } + } + return $fields; } - foreach ($this->fields as $f=>$val) + + /** Get/Set the primary property + * @param string|null $primary The primary key to use + */ + public function primary($primary = null) { - if ($full !== false) - $fields[$this->sep.$this->tableprefix.$this->table.$this->sep.".". - $this->sep.$f.$this->sep] = $val; - else - $fields[$f] = $val; + $this->debugLog("Entering primary (", $primary, ")", 2); + if ($primary === null) { + return $this->primary; + } + if (! is_string($primary)) { + $this->DBException("Parameter primary invalid: not a string"); + } + if (mb_strlen($primary) > 64) { + $this->DBException("Parameter primary invalid: too long"); + } + if (! array_key_exists($primary, $this->fields)) { + $this->DBException("Parameter primary invalid: column doesn't exists"); + } + $this->primary = $primary; + return $this; } - return $fields; - } - /** Get/Set the primary property - * @param string|null $primary The primary key to use - */ - public function primary ($primary = null) - { - $this->debugLog ("Entering primary (",$primary,")", 2); - if ($primary === null) - return $this->primary; - if (! is_string ($primary)) - $this->DBException ("Parameter primary invalid: not a string"); - if (mb_strlen ($primary) > 64) - $this->DBException ("Parameter primary invalid: too long"); - if (! array_key_exists ($primary, $this->fields)) - $this->DBException ("Parameter primary invalid: column doesn't exists"); - $this->primary = $primary; - return $this; - } - - /** Get/Set the unique property - * @param array|null $unique The unique fields constraint to add - */ - public function unique ($unique = null) - { - $this->debugLog ("Entering unique (VALUE)", 2); - if ($unique === null) - return $this->unique; - if (! is_array ($unique)) - $this->DBException ("Parameter unique invalid: not an array"); - foreach ($unique as $u1) + /** Get/Set the unique property + * @param array|null $unique The unique fields constraint to add + */ + public function unique($unique = null) { - if (is_string ($u1)) - { - if (mb_strlen ($u1) > 64) - $this->DBException ("Parameter unique invalid: too long '$u1'"); - } - elseif (is_array ($u1)) - { - foreach ($u1 as $u2) - { - if (is_string ($u2)) - { - if (mb_strlen ($u2) > 64) - $this->DBException ("Parameter unique invalid: too long '$u2'"); - } - else - $this->DBException ("Parameter unique invalid: Not string ". + $this->debugLog("Entering unique (VALUE)", 2); + if ($unique === null) { + return $this->unique; + } + if (! is_array($unique)) { + $this->DBException("Parameter unique invalid: not an array"); + } + foreach ($unique as $u1) { + if (is_string($u1)) { + if (mb_strlen($u1) > 64) { + $this->DBException("Parameter unique invalid: too long '$u1'"); + } + } elseif (is_array($u1)) { + foreach ($u1 as $u2) { + if (is_string($u2)) { + if (mb_strlen($u2) > 64) { + $this->DBException("Parameter unique invalid: too long '$u2'"); + } + } else { + $this->DBException("Parameter unique invalid: Not string " . "in array"); + } + } + } else { + $this->DBException("Parameter unique invalid: Not string nor array: " . + gettype($u1)); + } } - } - else - $this->DBException ("Parameter unique invalid: Not string nor array: ". - gettype ($u1)); + $this->unique = $unique; + return $this; } - $this->unique = $unique; - return $this; - } - /** Get/Set the foreign property - * @param array|null $foreign The definition of the foreign constraint - * The format is : - * array ( - * "field" => array ("parentTable", "parentField", "options if needed"), - * ) - * Multiple field and parnentField can be provided, separated by comma - */ - public function foreign ($foreign = null) - { - $this->debugLog ("Entering foreign (VALUE)", 2); - if ($foreign === null) - return $this->foreign; - if (! is_array ($foreign)) - $this->DBException ("Parameter foreign invalid: not an array"); - foreach ($foreign as $cols=>$params) + /** Get/Set the foreign property + * @param array|null $foreign The definition of the foreign constraint + * The format is : + * array ( + * "field" => array ("parentTable", "parentField", "options if needed"), + * ) + * Multiple field and parnentField can be provided, separated by comma + */ + public function foreign($foreign = null) { - foreach (explode (",", $cols) as $col) - { - if (! array_key_exists ($col, $this->fields)) - $this->DBException ( - "Parameter foreign invalid: column doesn't exists"); - if (! is_array ($params)) - $this->DBException ("Parameter foreign invalid: ". + $this->debugLog("Entering foreign (VALUE)", 2); + if ($foreign === null) { + return $this->foreign; + } + if (! is_array($foreign)) { + $this->DBException("Parameter foreign invalid: not an array"); + } + foreach ($foreign as $cols => $params) { + foreach (explode(",", $cols) as $col) { + if (! array_key_exists($col, $this->fields)) { + $this->DBException( + "Parameter foreign invalid: column doesn't exists" + ); + } + if (! is_array($params)) { + $this->DBException("Parameter foreign invalid: " . "parameters not in array"); - if (! array_key_exists (0, $params)) - $this->DBException ("Parameter foreign invalid: ". + } + if (! array_key_exists(0, $params)) { + $this->DBException("Parameter foreign invalid: " . "ParentTable is not provided"); - if (! array_key_exists (1, $params)) - $this->DBException ("Parameter foreign invalid: ". + } + if (! array_key_exists(1, $params)) { + $this->DBException("Parameter foreign invalid: " . "ParentField is not provided"); - if (! is_string ($params[0])) - $this->DBException ("Parameter foreign invalid: ". + } + if (! is_string($params[0])) { + $this->DBException("Parameter foreign invalid: " . "parameter 0 is not a string"); - if (! is_string ($params[1])) - $this->DBException ("Parameter foreign invalid: ". + } + if (! is_string($params[1])) { + $this->DBException("Parameter foreign invalid: " . "parameter 1 is not a string"); - if (mb_strlen ($params[0] > 64)) - $this->DBException ("Parameter foreign invalid: ". + } + if (mb_strlen($params[0] > 64)) { + $this->DBException("Parameter foreign invalid: " . "parameter 0 is too long"); - if (mb_strlen ($params[1] > 64)) - $this->DBException ("Parameter foreign invalid: ". + } + if (mb_strlen($params[1] > 64)) { + $this->DBException("Parameter foreign invalid: " . "parameter 1 is too long"); - } - if (substr_count ($cols, ",") !== substr_count ($params[1], ",")) - $this->DBException ("Parameter foreign invalid: ". - "Not the same number of comma between the local ". + } + } + if (substr_count($cols, ",") !== substr_count($params[1], ",")) { + $this->DBException("Parameter foreign invalid: " . + "Not the same number of comma between the local " . "field and the parent field"); - if (array_key_exists (2, $params)) - { - preg_match_all ("#^(ON UPDATE ". - "(CASCADE|RESTRICT|NO ACTION|SET DEFAULT|SET NULL) ?)?". - "(ON DELETE ". + } + if (array_key_exists(2, $params)) { + preg_match_all( + "#^(ON UPDATE " . + "(CASCADE|RESTRICT|NO ACTION|SET DEFAULT|SET NULL) ?)?" . + "(ON DELETE " . "(CASCADE|RESTRICT|NO ACTION|SET DEFAULT|SET NULL))?$#", - $params[2], $matches); - if ($matches[1] === "" && $matches[3] === "") - $this->DBException ("Parameter foreign invalid: ". + $params[2], + $matches + ); + if ($matches[1] === "" && $matches[3] === "") { + $this->DBException("Parameter foreign invalid: " . "Unknown action provided"); - } - } - $this->foreign = $foreign; - return $this; - } - - /** Get/Set the debug property - * @param integer|null $debug Set the debug value - */ - public function debug ($debug = null) - { - $this->debugLog ("Entering debug (",$debug,")", 2); - if ($debug === null) - return $this->debug; - if (! is_int ($debug)) - $this->DBException ("Parameter debug invalid: not an integer"); - $this->debug = $debug; - return $this; - } - - /** Get the sep property - */ - public function sep () - { - return $this->sep; - } - - /** Get/Set the dsn property - * @param string|null $dsn Set the DSN property of PDO - */ - public function dsn ($dsn=null) - { - $this->debugLog ("Entering dsn (",$dsn,")", 2); - if ($dsn === null) - return $this->dsn; - if (! is_string ($dsn)) - $this->DBException ("Parameter dsn invalid : not a string"); - $this->dsn = $dsn; - return $this; - } - - /** Get/Set the titles property - * @param array|null $titles The titles of the fields - * @param boolean|null $full Add the table name if the $full is set - */ - public function titles ($titles=null, $full = false) - { - $this->debugLog ("Entering titles (VALUE)", 2); - if ($titles === null) - { - if ($full === false && $this->joinObject === null) - return $this->titles; - $titles = array (); - foreach ($this->titles as $key=>$val) - { - $titles[$this->tableprefix.$this->table.".".$key] = $val; - } - if ($this->joinObject !== null) - { - foreach ($this->joinObject as $obj) - { - $titles = array_merge ($titles, $obj->titles (null, true)); + } + } } - } - return $titles; + $this->foreign = $foreign; + return $this; } - if (! is_array ($titles)) - $this->DBException ("Parameter titles invalid: not an array"); - foreach ($titles as $title=>$translation) - { - if (! is_string ($title)) - $this->DBException ("Parameter titles invalid: title not a string"); - if (mb_strlen ($title) > 64) - $this->DBException ("Parameter titles invalid: title too long"); - if (! is_string ($translation)) - $this->DBException ("Parameter titles invalid: ". - "translation not a string (table '$this->table',". - "field '$title')"); - if (mb_strlen ($translation) > 64) - $this->DBException ("Parameter titles invalid: translation too long"); - } - $this->titles = $titles; - return $this; - } - /** Dump the configuration of the table in an array - */ - public function exportConf () - { - return array ("table" => $this->table, + /** Get/Set the debug property + * @param integer|null $debug Set the debug value + */ + public function debug($debug = null) + { + $this->debugLog("Entering debug (", $debug, ")", 2); + if ($debug === null) { + return $this->debug; + } + if (! is_int($debug)) { + $this->DBException("Parameter debug invalid: not an integer"); + } + $this->debug = $debug; + return $this; + } + + /** Get the sep property + */ + public function sep() + { + return $this->sep; + } + + /** Get/Set the dsn property + * @param string|null $dsn Set the DSN property of PDO + */ + public function dsn($dsn = null) + { + $this->debugLog("Entering dsn (", $dsn, ")", 2); + if ($dsn === null) { + return $this->dsn; + } + if (! is_string($dsn)) { + $this->DBException("Parameter dsn invalid : not a string"); + } + $this->dsn = $dsn; + return $this; + } + + /** Get/Set the titles property + * @param array|null $titles The titles of the fields + * @param boolean|null $full Add the table name if the $full is set + */ + public function titles($titles = null, $full = false) + { + $this->debugLog("Entering titles (VALUE)", 2); + if ($titles === null) { + if ($full === false && $this->joinObject === null) { + return $this->titles; + } + $titles = array(); + foreach ($this->titles as $key => $val) { + $titles[$this->tableprefix . $this->table . "." . $key] = $val; + } + if ($this->joinObject !== null) { + foreach ($this->joinObject as $obj) { + $titles = array_merge($titles, $obj->titles(null, true)); + } + } + return $titles; + } + if (! is_array($titles)) { + $this->DBException("Parameter titles invalid: not an array"); + } + foreach ($titles as $title => $translation) { + if (! is_string($title)) { + $this->DBException("Parameter titles invalid: title not a string"); + } + if (mb_strlen($title) > 64) { + $this->DBException("Parameter titles invalid: title too long"); + } + if (! is_string($translation)) { + $this->DBException("Parameter titles invalid: " . + "translation not a string (table '$this->table'," . + "field '$title')"); + } + if (mb_strlen($translation) > 64) { + $this->DBException("Parameter titles invalid: translation too long"); + } + } + $this->titles = $titles; + return $this; + } + + /** Dump the configuration of the table in an array + */ + public function exportConf() + { + return array("table" => $this->table, "tableprefix" => $this->tableprefix, "fields" => $this->fields, "primary" => $this->primary, @@ -1429,2188 +1601,2455 @@ class Dblayeroo "foreign" => $this->foreign, "titles" => $this->titles, ); - } - - /** Define a real type array - * Must be array ("field" => "realtype") - * @param array $realTypes The realTypes to set - * The allowed real types are defined in test method : - * checkRealType_TYPE ($val, $definition) - * The allowed real types are : mail, date, datetime, allowedchars(a23d), - * uuid, time, array('val1','val2','val3'), regex(/^[a-zA-Z]{3,}$/i) - * integer, integerPositive, - * To be done : - * integerNegative, - * php_function(), function($val) { if ($val > 0) return "MESSAGE";} - */ - public function realTypes ($realTypes = null) - { - if ($realTypes === null) - return $this->realTypes; - if (! is_array ($realTypes)) - $this->DBException ("Invalid setRealType provided : not an array", 500); - foreach ($realTypes as $field => $realType) - { - if (! key_exists ($field, $this->fields)) - $this->DBException ("Invalid setRealType provided : ". - "field '$field' doesn't exists"); - @list ($func, $param) = explode ("(", $realType); - $func = trim ($func); - $method = "checkRealType_".$func; - if (! method_exists ($this, $method)) - $this->DBException ("Invalid setRealType provided : ". - "field '$field' : unknown realType provided '$func'"); } - $this->realTypes = $realTypes; - return $this; - } - /** Get the meta data or clear them. - * The meta data are all the requests done by the dblayeroo, the time needed - * for each, the number of rows returned by the SQL server. - * They allow to debug the app - * @param boolean|null $meta If meta is set, clear the meta-data. If not set, - * return the actual value of the meta-data - * @return array or $this - */ - public function meta ($meta = null) - { - if ($meta === null) - return self::$meta; - self::$meta = array (); - return $this; - } - - ///////////////////////////////////// - /// MANAGE THE REQUEST BY OOP /// - ///////////////////////////////////// - /** The command to use - */ - private $command = ""; - /** The DISTINCT option - */ - private $distinct = ""; - /** The columns to display in SELECT, with the tables names and the separators - * correctely defined - */ - private $displayColumn = null; - /** The alias associated to each displayColumn - */ - private $displayAlias = array (); - /** Manage the joins - */ - private $joins = array (); - /** The WHERE expression - */ - private $whereExpression = array (); - /** The values for each parameter for the WHERE condition - */ - private $whereValues = array (); - /** The columns in GROUP BY condition - */ - private $groupByExpression = null; - /** The ORDER expression - */ - private $orderExpression = array (); - /** The LIMIT expression - */ - private $limitExpression = ""; - /** The values to SET in INSERT/UPDATE - */ - private $setValues = array (); - /** The types to SET in INSERT/UPDATE - */ - private $setType = array (); - /** The dblayeroo object of the foreign keys tables to check - */ - private $setForeignObj = array (); - - /** If we need to join this object with another one, save the second one in - * this property - */ - private $joinObject; - - /** The debug depth (as we clone object, the depth is increased to debug - * easily the functions - */ - protected $debugDepth = 1; - - /** The sort order of select/order entries crossed the differents objects - */ - private static $sortOrder = 0; - - /** The method to get a new sort order acrossed the differents objects - */ - public function getSortOrder () - { - ++self::$sortOrder; - return "order".self::$sortOrder; - } - - /** Reinit the SQL request - */ - public function clearRequest () - { - $this->debugLog ("Entering clearRequest ()", 2); - if ($this->joinObject !== null) + /** Define a real type array + * Must be array ("field" => "realtype") + * @param array $realTypes The realTypes to set + * The allowed real types are defined in test method : + * checkRealType_TYPE ($val, $definition) + * The allowed real types are : mail, date, datetime, allowedchars(a23d), + * uuid, time, array('val1','val2','val3'), regex(/^[a-zA-Z]{3,}$/i) + * integer, integerPositive, + * To be done : + * integerNegative, + * php_function(), function($val) { if ($val > 0) return "MESSAGE";} + */ + public function realTypes($realTypes = null) { - foreach ($this->joinObject as $obj) - { - $obj->clearRequest (); - } - $this->joinObject = null; + if ($realTypes === null) { + return $this->realTypes; + } + if (! is_array($realTypes)) { + $this->DBException("Invalid setRealType provided : not an array", 500); + } + foreach ($realTypes as $field => $realType) { + if (! key_exists($field, $this->fields)) { + $this->DBException("Invalid setRealType provided : " . + "field '$field' doesn't exists"); + } + @list($func, $param) = explode("(", $realType); + $func = trim($func); + $method = "checkRealType_" . $func; + if (! method_exists($this, $method)) { + $this->DBException("Invalid setRealType provided : " . + "field '$field' : unknown realType provided '$func'"); + } + } + $this->realTypes = $realTypes; + return $this; } - $this->command = ""; - $this->distinct = ""; - $this->displayColumn = null; - $this->displayAlias = array (); - $this->joins = array (); - $this->whereExpression = array (); - $this->whereValues = array (); - $this->groupByExpression = null; - $this->orderExpression = array (); - $this->limitExpression = ""; - $this->setValues = array (); - $this->setType = array (); - // The foreign keys can be defined in the constructor for all the - // modifications checks. No need to remove them - //$this->setForeignObj = array (); - return $this; - } - /** Define a new foreign object - * @param object $object The dblayeroo object to use for foreign constraint - * checks - */ - public function setForeignObj ($object) - { - $this->debugLog ("Entering setForeignObj (OBJECT)", 2); - if (! is_object ($object)) - $this->DBException ("Invalid setForeignObj parameter: not an object"); - if (! is_subclass_of ($object, __CLASS__) && - get_class ($object) !== "Dblayeroo" && - get_class ($object) !== __NAMESPACE__."\Dblayeroo") - $this->DBException ( - "Invalid object provided to setForeignObj (not Dblayeroo object)"); - if (! isset ($object->table)) - $this->DBException ( - "Invalid object provided to setForeignObj (no table defined)"); - $this->setForeignObj[$object->tableprefix.$object->table] = $object; - return $this; - } - - /** Define the command to execute. Can be - * "SELECT", "INSERT", "DELETE", "UPDATE". - * @param string $command The command to execute - */ - public function command ($command) - { - $this->debugLog ("Entering command (",$command,")", 2); - $allowed = array ("SELECT", "INSERT", "DELETE", "UPDATE"); - if (! is_string ($command)) - $this->DBException ("Invalid command provided (not string)"); - $command = strtoupper ($command); - if (! in_array ($command, $allowed)) - $this->DBException ("Invalid command provided (unknown command)"); - $this->command = $command; - return $this; - } - - /** Alias of command ("SELECT") - */ - public function select () - { - $this->command = "SELECT"; - return $this; - } - - /** Alias of command ("INSERT") - */ - public function insert () - { - $this->command = "INSERT"; - return $this; - } - - /** Alias of command ("DELETE") - */ - public function delete () - { - $this->command = "DELETE"; - return $this; - } - - /** Alias of command ("UPDATE") - */ - public function update () - { - $this->command = "UPDATE"; - return $this; - } - - /** Set the DISTINCT option - */ - public function setDistinct () - { - $this->distinct = "DISTINCT"; - return $this; - } - - /** Changing the name displayColumns to displayAdd - * @param array|string|null $columnNames The columns name, separated by comma - * @deprecated 0.36 - */ - public function displayColumn ($columnNames = array ()) - { - return $this->displayAdd ($columnNames); - } - - /** Set the columns to display for the next SELECT request. - * The columns are ordered by the first added to the last added - * @param array|string|null $columnNames The columns name, separated by comma - * By default, display all the columns if this method is not called - * If the value is null or not provided or an empty array, do not display - * any field - * @param array|string|null $aliasNames Add the Aliases to the displayed - * columns - */ - public function displayAdd ($columnNames = array (), $aliasNames = array ()) - { - $this->debugLog ("Entering displayAdd (", $columnNames, ",", $aliasNames, - ")", 2); - if (! is_string ($columnNames) && ! is_array ($columnNames)) - $this->DBException ( - "Invalid columnNames provided (not string and not array)"); - if (! is_string ($aliasNames) && ! is_array ($aliasNames)) - $this->DBException ( - "Invalid aliasNames provided (not string and not array)"); - if (is_string ($columnNames)) + /** Get the meta data or clear them. + * The meta data are all the requests done by the dblayeroo, the time needed + * for each, the number of rows returned by the SQL server. + * They allow to debug the app + * @param boolean|null $meta If meta is set, clear the meta-data. If not set, + * return the actual value of the meta-data + * @return array or $this + */ + public function meta($meta = null) { - // A string must be separated by comma. But comma can be also in function - // parameter like GROUP_CONCAT(group,','),field1,field2 - // This block will explode on comma but only if not in a parenthesis block - $tmpArr = array (); - $parenthesis = false; - $tmp = ""; - for ($i = 0 ; $i < strlen ($columnNames) ; $i++) - { - $char = $columnNames[$i]; - if ($parenthesis === true) - { - $tmp .= $char; - if ($char === ")") + if ($meta === null) { + return self::$meta; + } + self::$meta = array(); + return $this; + } + + ///////////////////////////////////// + /// MANAGE THE REQUEST BY OOP /// + ///////////////////////////////////// + /** The command to use + */ + private $command = ""; + /** The DISTINCT option + */ + private $distinct = ""; + /** The columns to display in SELECT, with the tables names and the separators + * correctely defined + */ + private $displayColumn = null; + /** The alias associated to each displayColumn + */ + private $displayAlias = array(); + /** Manage the joins + */ + private $joins = array(); + /** The WHERE expression + */ + private $whereExpression = array(); + /** The values for each parameter for the WHERE condition + */ + private $whereValues = array(); + /** The columns in GROUP BY condition + */ + private $groupByExpression = null; + /** The ORDER expression + */ + private $orderExpression = array(); + /** The LIMIT expression + */ + private $limitExpression = ""; + /** The values to SET in INSERT/UPDATE + */ + private $setValues = array(); + /** The types to SET in INSERT/UPDATE + */ + private $setType = array(); + /** The dblayeroo object of the foreign keys tables to check + */ + private $setForeignObj = array(); + + /** If we need to join this object with another one, save the second one in + * this property + */ + private $joinObject; + + /** The debug depth (as we clone object, the depth is increased to debug + * easily the functions + */ + protected $debugDepth = 1; + + /** The sort order of select/order entries crossed the differents objects + */ + private static $sortOrder = 0; + + /** The method to get a new sort order acrossed the differents objects + */ + public function getSortOrder() + { + ++self::$sortOrder; + return "order" . self::$sortOrder; + } + + /** Reinit the SQL request + */ + public function clearRequest() + { + $this->debugLog("Entering clearRequest ()", 2); + if ($this->joinObject !== null) { + foreach ($this->joinObject as $obj) { + $obj->clearRequest(); + } + $this->joinObject = null; + } + $this->command = ""; + $this->distinct = ""; + $this->displayColumn = null; + $this->displayAlias = array(); + $this->joins = array(); + $this->whereExpression = array(); + $this->whereValues = array(); + $this->groupByExpression = null; + $this->orderExpression = array(); + $this->limitExpression = ""; + $this->setValues = array(); + $this->setType = array(); + // The foreign keys can be defined in the constructor for all the + // modifications checks. No need to remove them + //$this->setForeignObj = array (); + return $this; + } + + /** Define a new foreign object + * @param object $object The dblayeroo object to use for foreign constraint + * checks + */ + public function setForeignObj($object) + { + $this->debugLog("Entering setForeignObj (OBJECT)", 2); + if (! is_object($object)) { + $this->DBException("Invalid setForeignObj parameter: not an object"); + } + if ( + ! is_subclass_of($object, __CLASS__) && + get_class($object) !== "Dblayeroo" && + get_class($object) !== __NAMESPACE__ . "\Dblayeroo" + ) { + $this->DBException( + "Invalid object provided to setForeignObj (not Dblayeroo object)" + ); + } + if (! isset($object->table)) { + $this->DBException( + "Invalid object provided to setForeignObj (no table defined)" + ); + } + $this->setForeignObj[$object->tableprefix . $object->table] = $object; + return $this; + } + + /** Define the command to execute. Can be + * "SELECT", "INSERT", "DELETE", "UPDATE". + * @param string $command The command to execute + */ + public function command($command) + { + $this->debugLog("Entering command (", $command, ")", 2); + $allowed = array("SELECT", "INSERT", "DELETE", "UPDATE"); + if (! is_string($command)) { + $this->DBException("Invalid command provided (not string)"); + } + $command = strtoupper($command); + if (! in_array($command, $allowed)) { + $this->DBException("Invalid command provided (unknown command)"); + } + $this->command = $command; + return $this; + } + + /** Alias of command ("SELECT") + */ + public function select() + { + $this->command = "SELECT"; + return $this; + } + + /** Alias of command ("INSERT") + */ + public function insert() + { + $this->command = "INSERT"; + return $this; + } + + /** Alias of command ("DELETE") + */ + public function delete() + { + $this->command = "DELETE"; + return $this; + } + + /** Alias of command ("UPDATE") + */ + public function update() + { + $this->command = "UPDATE"; + return $this; + } + + /** Set the DISTINCT option + */ + public function setDistinct() + { + $this->distinct = "DISTINCT"; + return $this; + } + + /** Changing the name displayColumns to displayAdd + * @param array|string|null $columnNames The columns name, separated by comma + * @deprecated 0.36 + */ + public function displayColumn($columnNames = array()) + { + return $this->displayAdd($columnNames); + } + + /** Set the columns to display for the next SELECT request. + * The columns are ordered by the first added to the last added + * @param array|string|null $columnNames The columns name, separated by comma + * By default, display all the columns if this method is not called + * If the value is null or not provided or an empty array, do not display + * any field + * @param array|string|null $aliasNames Add the Aliases to the displayed + * columns + */ + public function displayAdd($columnNames = array(), $aliasNames = array()) + { + $this->debugLog( + "Entering displayAdd (", + $columnNames, + ",", + $aliasNames, + ")", + 2 + ); + if (! is_string($columnNames) && ! is_array($columnNames)) { + $this->DBException( + "Invalid columnNames provided (not string and not array)" + ); + } + if (! is_string($aliasNames) && ! is_array($aliasNames)) { + $this->DBException( + "Invalid aliasNames provided (not string and not array)" + ); + } + if (is_string($columnNames)) { + // A string must be separated by comma. But comma can be also in function + // parameter like GROUP_CONCAT(group,','),field1,field2 + // This block will explode on comma but only if not in a parenthesis block + $tmpArr = array(); $parenthesis = false; + $tmp = ""; + for ($i = 0; $i < strlen($columnNames); $i++) { + $char = $columnNames[$i]; + if ($parenthesis === true) { + $tmp .= $char; + if ($char === ")") { + $parenthesis = false; + } + } elseif ($char === "(") { + $tmp .= $char; + $parenthesis = true; + } elseif ($char === ",") { + $tmpArr[] = $tmp; + $tmp = ""; + } else { + $tmp .= $char; + } + } + if ($tmp !== "") { + $tmpArr[] = $tmp; + } + $columnNames = $tmpArr; } - elseif ($char === "(") - { - $tmp .= $char; - $parenthesis = true; + if (is_string($aliasNames)) { + $aliasNames = explode(",", $aliasNames); } - elseif ($char === ",") - { - $tmpArr[] = $tmp; - $tmp = ""; + if (count($aliasNames) && count($aliasNames) !== count($columnNames)) { + $this->DBException( + "The number of aliasNames are not the same as the number of columns" + ); } - else - $tmp .= $char; - } - if ($tmp !== "") - $tmpArr[] = $tmp; - $columnNames = $tmpArr; - } - if (is_string ($aliasNames)) - $aliasNames = explode (",", $aliasNames); - if (count ($aliasNames) && count ($aliasNames) !== count ($columnNames)) - $this->DBException ( - "The number of aliasNames are not the same as the number of columns"); - // If there is no provided names, reset all the defined ones - if (count ($columnNames) === 0) - $this->displayColumn = array (); - foreach ($columnNames as $nb => $display) - { - if (! is_string ($display)) - $this->DBException ( - "displayAdd: The display column name #$nb is not a string"); - $display = $name = trim ($display); - $pos = strpos ($display, "("); - if ($pos !== false) - { - $func = strtoupper (trim (substr ($name, 0, $pos))); - $name = trim (substr ($name, $pos+1, -1)); - $separator = ""; - if (in_array ($func, array ("AVG", "COUNT", "GROUP_CONCAT", "MAX", - "MIN","SUM"))) - { - $aggregateFunction = true; - // Aggregate function. Add the non aggregate fields to the GROUP BY - // expression, if not already done - if ($this->groupByExpression === null) - { - // Set to empty array to demonstrate that a GROUP BY is needed, but - // there is no already defined displayed Columns. - // Used if the group by is called from join object - if ($this->displayColumn === null) - $this->groupByExpression = array (); - else - $this->groupByExpression = $this->displayColumn; - } - if ($func === "GROUP_CONCAT" && ($pos = strpos ($name, ",'"))) - { - // There is a comma: the developper add the separator string - $separator = addslashes (substr ($name, $pos + 2, -1)); - $name = substr ($name, 0, $pos); - if ($this->driver === "sqlite" || $this->driver === "pgsql") - $separator = ",'$separator'"; - elseif ($this->driver === "mysql") - $separator = " SEPARATOR '$separator'"; - } - if ($func === "GROUP_CONCAT" && $this->driver === "pgsql") - { - $func = "string_agg"; - if ($separator === "") - $separator = ", ','"; - } + // If there is no provided names, reset all the defined ones + if (count($columnNames) === 0) { + $this->displayColumn = array(); } - } - $fieldName = $name; - $distinct = ""; - if (stripos ($name, "DISTINCT ") === 0) - { - $distinct = "DISTINCT "; - $fieldName = substr ($name, strlen ("DISTINCT ")); - } - if (! array_key_exists ($fieldName, $this->fields)) - $this->DBException (sprintf ( - "Invalid field to display '%s' : not defined in table", $fieldName)); - $getSortOrder = $this->getSortOrder(); - if (! isset ($func)) - $this->displayColumn[$getSortOrder] = - $distinct.$this->sep.$fieldName.$this->sep; - elseif ($func === "string_agg") - { - // For Postgres, the entry must be : - // string_agg(distinct "group"::character varying, ',' order by "group") - $this->displayColumn[$getSortOrder] = - "$func($distinct$this->sep$fieldName$this->sep". - "::character varying$separator ". - "order by $this->sep$fieldName$this->sep)"; - } - else - $this->displayColumn[$getSortOrder] = - "$func($distinct$this->sep$fieldName$this->sep$separator)"; - if ($this->groupByExpression !== null && ! isset ($aggregateFunction)) - { - // Not a aggregate function, but groupBy is set : add the new field name - $this->groupByExpression[$getSortOrder] = - $this->sep.$fieldName.$this->sep; - } - unset ($aggregateFunction); - unset ($func); - if (key_exists ($nb, $aliasNames)) - $this->displayAlias[$getSortOrder] = $aliasNames[$nb]; - } - return $this; - } - - /** Return the name of the display field, with $this->sep - * Add the table prefix/name if full is set - * Allow : - * name, - * DISTINCT name, - * $this->sep.$name.$this->sep, - * DISTINCT $this->sep.$name.$this->sep, - * func(name), - * func(DISTINCT name), - * func($this->sep.$name.$this->sep), - * func(DISTINCT $this->sep.$name.$this->sep), - * func($this->sep.$this->tableprefix.$this->table.$this->sep.".". - * $this->sep.$name.$this->sep) - * func(DISTINCT $this->sep.$this->tableprefix.$this->table.$this->sep.".". - * $this->sep.$name.$this->sep) - * @param string $name The name of the field - * @param boolean|null $full Add the table prefix/name if set - */ - private function displayConvert ($name, $full = false) - { - $pos = strpos ($name, "("); - if ($pos !== false) - { - $func = trim (substr ($name, 0, $pos)); - $name = trim (substr ($name, $pos+1, -1)); - } - $distinct = ""; - if (strpos ($name, "DISTINCT ") === 0) - { - $distinct = "DISTINCT "; - $name = substr ($name, strlen ("DISTINCT ")); - } - if ($name[0] !== $this->sep) - $name = $this->sep.$name; - if (! isset ($func) && substr ($name, -1) !== $this->sep) - $name = $name.$this->sep; - if ($full !== false) - $name = $this->sep.$this->tableprefix.$this->table.$this->sep.".".$name; - if (isset ($func)) - $name = "$func($distinct$name)"; - else - $name = "$distinct$name"; - return $name; - } - - /** Get the columns set in the query by displayAdd. If the $full parameter - * is set, add the table prefix/name to the result. - * If the join object is set, ask to it the columns too - * @param boolean $full Add the table prefix/name if set - */ - public function displayGet ($full = false) - { - $columns = array (); - $displayColumn = array (); - if ($this->joinObject) - { - // The join object will be added at the end - $full = true; - } - // If empty $this->displayColumn list the fields of the table (like - // tablename.*) - if ($full !== false) - { - if ($this->displayColumn === null) - { - foreach (array_keys ($this->fields) as $name) - { - $displayColumn[$this->getSortOrder()] = $this->displayConvert ($name); + foreach ($columnNames as $nb => $display) { + if (! is_string($display)) { + $this->DBException( + "displayAdd: The display column name #$nb is not a string" + ); + } + $display = $name = trim($display); + $pos = strpos($display, "("); + if ($pos !== false) { + $func = strtoupper(trim(substr($name, 0, $pos))); + $name = trim(substr($name, $pos + 1, -1)); + $separator = ""; + if ( + in_array($func, array("AVG", "COUNT", "GROUP_CONCAT", "MAX", + "MIN","SUM")) + ) { + $aggregateFunction = true; + // Aggregate function. Add the non aggregate fields to the GROUP BY + // expression, if not already done + if ($this->groupByExpression === null) { + // Set to empty array to demonstrate that a GROUP BY is needed, but + // there is no already defined displayed Columns. + // Used if the group by is called from join object + if ($this->displayColumn === null) { + $this->groupByExpression = array(); + } else { + $this->groupByExpression = $this->displayColumn; + } + } + if ($func === "GROUP_CONCAT" && ($pos = strpos($name, ",'"))) { + // There is a comma: the developper add the separator string + $separator = addslashes(substr($name, $pos + 2, -1)); + $name = substr($name, 0, $pos); + if ($this->driver === "sqlite" || $this->driver === "pgsql") { + $separator = ",'$separator'"; + } elseif ($this->driver === "mysql") { + $separator = " SEPARATOR '$separator'"; + } + } + if ($func === "GROUP_CONCAT" && $this->driver === "pgsql") { + $func = "string_agg"; + if ($separator === "") { + $separator = ", ','"; + } + } + } + } + $fieldName = $name; + $distinct = ""; + if (stripos($name, "DISTINCT ") === 0) { + $distinct = "DISTINCT "; + $fieldName = substr($name, strlen("DISTINCT ")); + } + if (! array_key_exists($fieldName, $this->fields)) { + $this->DBException(sprintf( + "Invalid field to display '%s' : not defined in table", + $fieldName + )); + } + $getSortOrder = $this->getSortOrder(); + if (! isset($func)) { + $this->displayColumn[$getSortOrder] = + $distinct . $this->sep . $fieldName . $this->sep; + } elseif ($func === "string_agg") { + // For Postgres, the entry must be : + // string_agg(distinct "group"::character varying, ',' order by "group") + $this->displayColumn[$getSortOrder] = + "$func($distinct$this->sep$fieldName$this->sep" . + "::character varying$separator " . + "order by $this->sep$fieldName$this->sep)"; + } else { + $this->displayColumn[$getSortOrder] = + "$func($distinct$this->sep$fieldName$this->sep$separator)"; + } + if ($this->groupByExpression !== null && ! isset($aggregateFunction)) { + // Not a aggregate function, but groupBy is set : add the new field name + $this->groupByExpression[$getSortOrder] = + $this->sep . $fieldName . $this->sep; + } + unset($aggregateFunction); + unset($func); + if (key_exists($nb, $aliasNames)) { + $this->displayAlias[$getSortOrder] = $aliasNames[$nb]; + } } - } - else - { - $displayColumn = $this->displayColumn; - } + return $this; } - else + + /** Return the name of the display field, with $this->sep + * Add the table prefix/name if full is set + * Allow : + * name, + * DISTINCT name, + * $this->sep.$name.$this->sep, + * DISTINCT $this->sep.$name.$this->sep, + * func(name), + * func(DISTINCT name), + * func($this->sep.$name.$this->sep), + * func(DISTINCT $this->sep.$name.$this->sep), + * func($this->sep.$this->tableprefix.$this->table.$this->sep.".". + * $this->sep.$name.$this->sep) + * func(DISTINCT $this->sep.$this->tableprefix.$this->table.$this->sep.".". + * $this->sep.$name.$this->sep) + * @param string $name The name of the field + * @param boolean|null $full Add the table prefix/name if set + */ + private function displayConvert($name, $full = false) { - if ($this->displayColumn === null) - { - foreach (array_keys ($this->fields) as $name) - { - $displayColumn[$this->getSortOrder()] = $this->displayConvert ($name); + $pos = strpos($name, "("); + if ($pos !== false) { + $func = trim(substr($name, 0, $pos)); + $name = trim(substr($name, $pos + 1, -1)); } - } - else - { - $displayColumn = $this->displayColumn; - } + $distinct = ""; + if (strpos($name, "DISTINCT ") === 0) { + $distinct = "DISTINCT "; + $name = substr($name, strlen("DISTINCT ")); + } + if ($name[0] !== $this->sep) { + $name = $this->sep . $name; + } + if (! isset($func) && substr($name, -1) !== $this->sep) { + $name = $name . $this->sep; + } + if ($full !== false) { + $name = $this->sep . $this->tableprefix . $this->table . $this->sep . "." . $name; + } + if (isset($func)) { + $name = "$func($distinct$name)"; + } else { + $name = "$distinct$name"; + } + return $name; } - foreach ($displayColumn as $pos=>$name) + + /** Get the columns set in the query by displayAdd. If the $full parameter + * is set, add the table prefix/name to the result. + * If the join object is set, ask to it the columns too + * @param boolean $full Add the table prefix/name if set + */ + public function displayGet($full = false) { - if ($full !== false) - $columns[$pos] = $this->displayConvert ($name, true); - else - $columns[$pos] = $this->displayConvert ($name); - if (key_exists ($pos, $this->displayAlias)) - $columns[$pos] .= " AS ". - $this->sep.$this->displayAlias[$pos].$this->sep; + $columns = array(); + $displayColumn = array(); + if ($this->joinObject) { + // The join object will be added at the end + $full = true; + } + // If empty $this->displayColumn list the fields of the table (like + // tablename.*) + if ($full !== false) { + if ($this->displayColumn === null) { + foreach (array_keys($this->fields) as $name) { + $displayColumn[$this->getSortOrder()] = $this->displayConvert($name); + } + } else { + $displayColumn = $this->displayColumn; + } + } else { + if ($this->displayColumn === null) { + foreach (array_keys($this->fields) as $name) { + $displayColumn[$this->getSortOrder()] = $this->displayConvert($name); + } + } else { + $displayColumn = $this->displayColumn; + } + } + foreach ($displayColumn as $pos => $name) { + if ($full !== false) { + $columns[$pos] = $this->displayConvert($name, true); + } else { + $columns[$pos] = $this->displayConvert($name); + } + if (key_exists($pos, $this->displayAlias)) { + $columns[$pos] .= " AS " . + $this->sep . $this->displayAlias[$pos] . $this->sep; + } + } + if ($this->joinObject) { + foreach ($this->joinObject as $obj) { + $columns = array_merge($columns, $obj->displayGet(true)); + } + } + ksort($columns, SORT_NATURAL); + return $columns; } - if ($this->joinObject) + + /** Do a inner join between two dblayer objects + * The join array is a associated array with local field as key and distant + * field as value + * @param object $object The dblayeroo object to use for searching the join + * data + * @param array $joinArray The values to search for join + */ + public function joinInner($object, $joinArray) { - foreach ($this->joinObject as $obj) - $columns = array_merge ($columns, $obj->displayGet (true)); + $this->debugLog("Entering joinInner (OBJECT, JOINARRAY)", 2); + return $this->joinReal("INNER", $object, $joinArray); } - ksort ($columns, SORT_NATURAL); - return $columns; - } - /** Do a inner join between two dblayer objects - * The join array is a associated array with local field as key and distant - * field as value - * @param object $object The dblayeroo object to use for searching the join - * data - * @param array $joinArray The values to search for join - */ - public function joinInner ($object, $joinArray) - { - $this->debugLog ("Entering joinInner (OBJECT, JOINARRAY)", 2); - return $this->joinReal ("INNER", $object, $joinArray); - } - - /** Do a left join between two dblayer objects - * The join array is a associated array with local field as key and distant - * field as value - * @param object $object The dblayeroo object to use for searching the join - * data - * @param array $joinArray The values to search for join - */ - public function joinLeft ($object, $joinArray) - { - $this->debugLog ("Entering joinLeft (OBJECT, JOINARRAY)", 2); - return $this->joinReal ("LEFT", $object, $joinArray); - } - - /** Do a right join between two dblayer objects - * The join array is a associated array with local field as key and distant - * field as value - * @param object $object The dblayeroo object to use for searching the join - * data - * @param array $joinArray The values to search for join - */ - public function joinRight ($object, $joinArray) - { - $this->debugLog ("Entering joinRight (OBJECT, JOINARRAY)", 2); - return $this->joinReal ("RIGHT", $object, $joinArray); - } - - /** Convert a CONCAT('text',field) to CONCAT('text',`table`.`field`) or - * generate an exception if the field is not available in table - * If the provided string is not a concat, return the original one - * @param string $concat The string to examine - * @param object $object The dblayer object to use - */ - private function concat ($concat, $object) - { - if (substr ($concat, 0, 7) !== "CONCAT(") - return $concat; - if (substr ($concat, -1) !== ")") - $this->DBException ("CONCAT without ending parenthesis"); - $tmp = substr ($concat, 7, -1); - $new = "CONCAT("; - foreach (explode (",", $tmp) as $part) + /** Do a left join between two dblayer objects + * The join array is a associated array with local field as key and distant + * field as value + * @param object $object The dblayeroo object to use for searching the join + * data + * @param array $joinArray The values to search for join + */ + public function joinLeft($object, $joinArray) { - if ($new !== "CONCAT(") - $new .= ","; - if (substr ($part, 0, 1) === "'" && - substr ($part, -1) === "'") - $new .= $part; - elseif (! array_key_exists ($part, $object->fields)) - $this->DBException (sprintf ( - "Invalid field to join in CONCAT : ". - "'%s' not defined in Distant table", $part)); - else - $new .= - $this->sep.$object->tableprefix.$object->table.$this->sep.".". - $this->sep.$part.$this->sep; + $this->debugLog("Entering joinLeft (OBJECT, JOINARRAY)", 2); + return $this->joinReal("LEFT", $object, $joinArray); } - $new .= ")"; - return $new; - } - /** Do the real join - * @param string $joinType The join type to use ("INNER", "LEFT", "RIGHT") - * @param object $object The dblayeroo object to use for searching the join - * data - * @param array $joinArray The values to search for join - */ - private function joinReal ($joinType, $object, $joinArray) - { - $this->debugLog ("Entering joinReal (",$joinType,", OBJECT, JOINARRAY)", 2); - if (! is_string ($joinType)) - $this->DBException ("Invalid joinType provided to join (not string)"); - if (! in_array ($joinType, array ("INNER", "LEFT", "RIGHT"))) - $this->DBException ("Invalid joinType provided to join (not known)"); - if (! is_object ($object)) - $this->DBException ("Invalid object provided to join (not object)"); - if (! is_subclass_of ($object, __CLASS__) && - get_class ($object) !== "Dblayeroo" && - get_class ($object) !== __NAMESPACE__."\Dblayeroo") - $this->DBException ( - "Invalid object provided to join (not Dblayeroo object)"); - if ($this->dsn !== $object->dsn) - $this->DBException ( - "DSN different : don't support JOIN between databases"); - - if (! is_array ($joinArray)) - $this->DBException ("Invalid joinArray provided (not array)"); - if (empty ($joinArray)) - $this->DBException ("Invalid joinArray provided (empty array)"); - $newJoinArray = array (); - foreach ($joinArray as $fieldLocal=>$fieldToJoin) + /** Do a right join between two dblayer objects + * The join array is a associated array with local field as key and distant + * field as value + * @param object $object The dblayeroo object to use for searching the join + * data + * @param array $joinArray The values to search for join + */ + public function joinRight($object, $joinArray) { - if (substr ($fieldLocal, 0, 7) === "CONCAT(") - $fieldLocal = $this->concat ($fieldLocal, $this); - elseif (array_key_exists ($fieldLocal, $this->fields)) - $fieldLocal = - $this->sep.$this->tableprefix.$this->table.$this->sep.".". - $this->sep.$fieldLocal.$this->sep; - else - $this->DBException (sprintf ( - "Invalid field to join '%s' : not defined in Local table", - $fieldLocal)); - - if (substr ($fieldToJoin, 0, 7) === "CONCAT(") - $fieldToJoin = $this->concat ($fieldToJoin, $object); - elseif (array_key_exists ($fieldToJoin, $object->fields)) - $fieldToJoin = - $this->sep.$object->tableprefix.$object->table.$this->sep.".". - $this->sep.$fieldToJoin.$this->sep; - else - $this->DBException (sprintf ( - "Invalid field to join '%s' : not defined in Distant table", - $fieldToJoin)); - $newJoinArray[$fieldLocal] = $fieldToJoin; + $this->debugLog("Entering joinRight (OBJECT, JOINARRAY)", 2); + return $this->joinReal("RIGHT", $object, $joinArray); } - if (! isset ($object->table) || $object->table === null || - trim ($object->table) === "") - $this->DBException ("No table defined in the Join object"); - if (! isset ($this->table) || $this->table === null || - trim ($this->table) === "") - $this->DBException ("No table defined in the local object"); - if (! isset ($object->tableprefix) || $object->tableprefix === null) - $this->DBException ("No tableprefix defined in the Join object"); - $this->joinObject[] = $object; - $tmp = ""; - foreach ($newJoinArray as $fieldLocal=>$fieldToJoin) + + /** Convert a CONCAT('text',field) to CONCAT('text',`table`.`field`) or + * generate an exception if the field is not available in table + * If the provided string is not a concat, return the original one + * @param string $concat The string to examine + * @param object $object The dblayer object to use + */ + private function concat($concat, $object) { - if ($tmp !== "") - $tmp .= " AND "; - $tmp .= "$fieldLocal=$fieldToJoin"; + if (substr($concat, 0, 7) !== "CONCAT(") { + return $concat; + } + if (substr($concat, -1) !== ")") { + $this->DBException("CONCAT without ending parenthesis"); + } + $tmp = substr($concat, 7, -1); + $new = "CONCAT("; + foreach (explode(",", $tmp) as $part) { + if ($new !== "CONCAT(") { + $new .= ","; + } + if ( + substr($part, 0, 1) === "'" && + substr($part, -1) === "'" + ) { + $new .= $part; + } elseif (! array_key_exists($part, $object->fields)) { + $this->DBException(sprintf( + "Invalid field to join in CONCAT : " . + "'%s' not defined in Distant table", + $part + )); + } else { + $new .= + $this->sep . $object->tableprefix . $object->table . $this->sep . "." . + $this->sep . $part . $this->sep; + } + } + $new .= ")"; + return $new; } - // Correct the displayQuery in the main display fields with the display - // fields of object - $this->joins[] = "$joinType JOIN ". - $this->sep.$object->tableprefix.$object->table.$this->sep." ON $tmp"; - return $this; - } - /** Get the join SQL part with recursive call of the child joins - * @param object|null $joinObject The joinObject to examine too - */ - public function joinsGet ($joinObject = null) - { - $joins = ""; - if ($joinObject === null) - $joinObject = $this; - if ($joinObject->joins !== array ()) - $joins = implode ("\n ", $joinObject->joins); - if ($joinObject->joinObject !== null) + /** Do the real join + * @param string $joinType The join type to use ("INNER", "LEFT", "RIGHT") + * @param object $object The dblayeroo object to use for searching the join + * data + * @param array $joinArray The values to search for join + */ + private function joinReal($joinType, $object, $joinArray) { - foreach ($joinObject->joinObject as $obj) - $joins .= "\n ".$joinObject->joinsGet ($obj); - } - return trim ($joins); - } + $this->debugLog("Entering joinReal (", $joinType, ", OBJECT, JOINARRAY)", 2); + if (! is_string($joinType)) { + $this->DBException("Invalid joinType provided to join (not string)"); + } + if (! in_array($joinType, array("INNER", "LEFT", "RIGHT"))) { + $this->DBException("Invalid joinType provided to join (not known)"); + } + if (! is_object($object)) { + $this->DBException("Invalid object provided to join (not object)"); + } + if ( + ! is_subclass_of($object, __CLASS__) && + get_class($object) !== "Dblayeroo" && + get_class($object) !== __NAMESPACE__ . "\Dblayeroo" + ) { + $this->DBException( + "Invalid object provided to join (not Dblayeroo object)" + ); + } + if ($this->dsn !== $object->dsn) { + $this->DBException( + "DSN different : don't support JOIN between databases" + ); + } - /** Set a new WHERE expression value - * @param string $field The field to check - * @param string $operator The operator ("=", "<=", ">=", "!=", "NOT LIKE", - * "LIKE", "IS NULL", "REGEXP", "NOT REGEXP") - * @param string|null $value The value to search ("" if not provided) - */ - public function whereAdd ($field, $operator, $value = "") - { - $this->debugLog ("Entering whereAdd (",$field,", ",$operator,", ",$value, - ")", 2); - if (! is_string ($field)) - $this->DBException ("Invalid field provided (not string)"); - if (! is_string ($operator)) - $this->DBException ("Invalid operator provided (not string)"); - if (! is_string ($value) && ! is_null ($value) && - ! is_integer ($value) && ! is_float ($value)) - $this->DBException ("Invalid value provided (not string nor null ". + if (! is_array($joinArray)) { + $this->DBException("Invalid joinArray provided (not array)"); + } + if (empty($joinArray)) { + $this->DBException("Invalid joinArray provided (empty array)"); + } + $newJoinArray = array(); + foreach ($joinArray as $fieldLocal => $fieldToJoin) { + if (substr($fieldLocal, 0, 7) === "CONCAT(") { + $fieldLocal = $this->concat($fieldLocal, $this); + } elseif (array_key_exists($fieldLocal, $this->fields)) { + $fieldLocal = + $this->sep . $this->tableprefix . $this->table . $this->sep . "." . + $this->sep . $fieldLocal . $this->sep; + } else { + $this->DBException(sprintf( + "Invalid field to join '%s' : not defined in Local table", + $fieldLocal + )); + } + + if (substr($fieldToJoin, 0, 7) === "CONCAT(") { + $fieldToJoin = $this->concat($fieldToJoin, $object); + } elseif (array_key_exists($fieldToJoin, $object->fields)) { + $fieldToJoin = + $this->sep . $object->tableprefix . $object->table . $this->sep . "." . + $this->sep . $fieldToJoin . $this->sep; + } else { + $this->DBException(sprintf( + "Invalid field to join '%s' : not defined in Distant table", + $fieldToJoin + )); + } + $newJoinArray[$fieldLocal] = $fieldToJoin; + } + if ( + ! isset($object->table) || $object->table === null || + trim($object->table) === "" + ) { + $this->DBException("No table defined in the Join object"); + } + if ( + ! isset($this->table) || $this->table === null || + trim($this->table) === "" + ) { + $this->DBException("No table defined in the local object"); + } + if (! isset($object->tableprefix) || $object->tableprefix === null) { + $this->DBException("No tableprefix defined in the Join object"); + } + $this->joinObject[] = $object; + $tmp = ""; + foreach ($newJoinArray as $fieldLocal => $fieldToJoin) { + if ($tmp !== "") { + $tmp .= " AND "; + } + $tmp .= "$fieldLocal=$fieldToJoin"; + } + // Correct the displayQuery in the main display fields with the display + // fields of object + $this->joins[] = "$joinType JOIN " . + $this->sep . $object->tableprefix . $object->table . $this->sep . " ON $tmp"; + return $this; + } + + /** Get the join SQL part with recursive call of the child joins + * @param object|null $joinObject The joinObject to examine too + */ + public function joinsGet($joinObject = null) + { + $joins = ""; + if ($joinObject === null) { + $joinObject = $this; + } + if ($joinObject->joins !== array()) { + $joins = implode("\n ", $joinObject->joins); + } + if ($joinObject->joinObject !== null) { + foreach ($joinObject->joinObject as $obj) { + $joins .= "\n " . $joinObject->joinsGet($obj); + } + } + return trim($joins); + } + + /** Set a new WHERE expression value + * @param string $field The field to check + * @param string $operator The operator ("=", "<=", ">=", "!=", "NOT LIKE", + * "LIKE", "IS NULL", "REGEXP", "NOT REGEXP") + * @param string|null $value The value to search ("" if not provided) + */ + public function whereAdd($field, $operator, $value = "") + { + $this->debugLog( + "Entering whereAdd (", + $field, + ", ", + $operator, + ", ", + $value, + ")", + 2 + ); + if (! is_string($field)) { + $this->DBException("Invalid field provided (not string)"); + } + if (! is_string($operator)) { + $this->DBException("Invalid operator provided (not string)"); + } + if ( + ! is_string($value) && ! is_null($value) && + ! is_integer($value) && ! is_float($value) + ) { + $this->DBException("Invalid value provided (not string nor null " . "nor integer not float)"); - if (! array_key_exists ($field, $this->fields)) - $this->DBException (sprintf ( - "Invalid field to whereAdd '%s' : not defined in table", $field)); - $operator = strtoupper ($operator); - $allowed = array ("=", "<", "<=", ">", ">=", "!=", + } + if (! array_key_exists($field, $this->fields)) { + $this->DBException(sprintf( + "Invalid field to whereAdd '%s' : not defined in table", + $field + )); + } + $operator = strtoupper($operator); + $allowed = array("=", "<", "<=", ">", ">=", "!=", "LIKE", "NOT LIKE", "IS NULL", "IS NOT NULL", "REGEXP", "NOT REGEXP"); - if (! in_array ($operator, $allowed)) - $this->DBException ("Invalid operator provided (unknown operator)"); - // TODO : Check if the value is corresponding to the type of the column - if (count ($this->whereExpression) && - end ($this->whereExpression) !== "AND" && - end ($this->whereExpression) !== "OR" && - end ($this->whereExpression) !== "(") - $this->whereExpression[] = "AND"; - if ($this->driver === "pgsql" && $operator === "REGEXP") - $operator = "~"; - if ($this->driver === "pgsql" && $operator === "NOT REGEXP") - $operator = "!~"; - if ($operator === "IS NULL" || $operator === "IS NOT NULL") - { - // Operator without parameter - $this->whereExpression[] = - $this->sep.$this->tableprefix.$this->table.$this->sep.".". - $this->sep.$field.$this->sep." ".$operator; - } - else - { - // Operator with parameter - $hash = md5 ("$field, $operator, $value"); - $this->whereExpression[] = - $this->sep.$this->tableprefix.$this->table.$this->sep.".". - $this->sep.$field.$this->sep." ".$operator." :$hash"; - $this->whereValues[$hash] = array ( - "field"=>$field, - "fieldfull"=> $this->tableprefix.$this->table.".".$field, - "operator"=>$operator, - "value"=>$value, - "hash"=>$hash, - "type"=>$this->fieldTypeLight ($field)); - } - return $this; - } - - /** Add a new AND to the WHERE expression - */ - public function whereAddAND () - { - $this->debugLog ("Entering whereAddAND ()", 2); - if (count ($this->whereExpression) === 0) - $this->DBException ("Can not add AND as there is no previous expression"); - $this->whereExpression[] = "AND"; - return $this; - } - - /** Add a new OR to the WHERE expression - */ - public function whereAddOR () - { - $this->debugLog ("Entering whereAddOR ()", 2); - if (count ($this->whereExpression) === 0) - $this->DBException ("Can not add OR as there is no previous expression"); - $this->whereExpression[] = "OR"; - return $this; - } - - /** Add a new Open Parenthesis to the WHERE expression - */ - public function whereAddParenthesisOpen () - { - $this->debugLog ("Entering whereAddParenthesisOpen ()", 2); - if (count ($this->whereExpression) && - end ($this->whereExpression) !== "AND" && - end ($this->whereExpression) !== "OR" && - end ($this->whereExpression) !== "(") - $this->whereExpression[] = "AND"; - $this->whereExpression[] = "("; - return $this; - } - - /** Add a new Close Parenthesis to the WHERE expression - */ - public function whereAddParenthesisClose () - { - $this->debugLog ("Entering whereAddParenthesisClose ()", 2); - $this->whereExpression[] = ")"; - return $this; - } - - /** Get the WHERE clause of the object. - * If the joinObject is set, return all the WHERE clauses - */ - public function whereGetExpression () - { - $whereExpression = $this->whereExpression; - if ($whereExpression === null) - $whereExpression = array (); - if ($this->joinObject !== null) - { - foreach ($this->joinObject as $obj) - { - $exp = $obj->whereGetExpression (); - if (count ($whereExpression) && count ($exp)) - $whereExpression[] = "AND"; - if (count ($exp)) - $whereExpression[] = "("; - $whereExpression = array_merge ($whereExpression, - $exp); - if (count ($exp)) - $whereExpression[] = ")"; - } - } - return $whereExpression; - } - - /** Get the WHERE values of the object. - * If the joinObject is set, return all the WHERE clauses with AND and - * parenthesis - */ - public function whereGetValues () - { - $whereValues = $this->whereValues; - if ($whereValues === null) - $whereValues = array (); - if ($this->joinObject !== null) - { - foreach ($this->joinObject as $obj) - { - $whereValues = array_merge ($whereValues, - $obj->whereGetValues ()); - } - } - return $whereValues; - } - - /** Add a new ORDER sort. The multiple ORDERS are used from the first added to - * the last added - * @param string $field The field to sort - * @param string|null $sort The sort order ("ASC", "DESC", "NATASC", - * "NATDESC"); - */ - public function orderAdd ($field, $sort = "ASC") - { - $this->debugLog ("Entering orderAdd (",$field,", ",$sort,")", 2); - if (! is_string ($field)) - $this->DBException ("Invalid field provided (not string)"); - if (! is_string ($sort)) - $this->DBException ("Invalid sort provided (not string)"); - $sort = strtoupper ($sort); - if (! in_array ($sort, array ("ASC", "DESC", "NATASC", "NATDESC"))) - $this->DBException ( - "Invalid sort provided (not ASC nor DESC nor NATASC nor NATDESC)"); - if (! array_key_exists ($field, $this->fields) && - ! in_array ($field, $this->displayAlias)) - $this->DBException (sprintf ( - "Invalid field to orderAdd '%s' : not defined in table nor in alias", - $field)); - $plus = ""; - if (substr ($sort, 0, 3) === "NAT") - { - $plus = "+0"; - $sort = substr ($sort, 3); - } - $exp = $this->sep.$field.$this->sep.$plus." ".$sort; - if ($plus !== "") - $exp .= ",". $this->sep.$this->table.$this->sep.".". - $this->sep.$field.$this->sep." ".$sort; - $this->orderExpression[$this->getSortOrder()] = $exp; - return $this; - } - - /** Get the ORDER fields defined. If a joinObject is set with ORDER statement, - * return the joinObject order with its tableprefix/name in addition of - * the ones of this object - * If the parameter $full is set, add the table prefix/name to the result - * @param boolean|null $full Add the table prefix/name if set - */ - public function orderGet ($full = false) - { - $order = array (); - if ($this->joinObject) - $full = true; - foreach ($this->orderExpression as $pos=>$o) - { - if ($full !== false) - $order[$pos] = $this->sep.$this->tableprefix.$this->table.$this->sep. - ".".$o; - else - $order[$pos] = $o; - } - if ($this->joinObject) - { - foreach ($this->joinObject as $obj) - $order = array_merge ($order, $obj->orderGet (true)); - } - ksort ($order, SORT_NATURAL); - return $order; - } - - /** Return true if this object or one of the join objects need GROUP BY SQL - * part - */ - public function groupByNeeded () - { - $needGroupBy = false; - if ($this->groupByExpression !== null) - $needGroupBy = true; - if ($this->joinObject) - { - foreach ($this->joinObject as $obj) - { - if ($obj->groupByNeeded () === true) - $needGroupBy = true; - } - } - return $needGroupBy; - } - - /** Get the GROUP BY fields defined. If a joinObject is set with GROUP BY - * statement, return the joinObject order with its tableprefix/name in - * addition of the ones of this object - * If the parameter $full is set, add the table prefix/name to the result - * @param boolean|null $full Add the table prefix/name if set - */ - public function groupByGet ($full = false) - { - if ($this->joinObject) - $full = true; - - $localGroupBy = array (); - // Manage the local object group by entries. In full mode, return the - // groupByExpression if it is set, or the list of the displayed fields. - if ($full) - { - if ($this->groupByExpression !== null) - { - foreach ($this->groupByExpression as $pos=>$o) - { - if ($localGroupBy === null) - $localGroupBy = array (); - $localGroupBy[$pos] = $this->sep.$this->tableprefix.$this->table. - $this->sep.".".$o; + if (! in_array($operator, $allowed)) { + $this->DBException("Invalid operator provided (unknown operator)"); } - } - elseif ($this->displayColumn !== null) - { - foreach ($this->displayColumn as $name) - { - $localGroupBy[] = $this->displayConvert ($name, true); + // TODO : Check if the value is corresponding to the type of the column + if ( + count($this->whereExpression) && + end($this->whereExpression) !== "AND" && + end($this->whereExpression) !== "OR" && + end($this->whereExpression) !== "(" + ) { + $this->whereExpression[] = "AND"; } - } - else - { - // Nothing to return if there is no groupBy and nothing to display - } - } - else - { - if ($this->groupByExpression !== null) - $localGroupBy = $this->groupByExpression; - else - $localGroupBy = array (); - } - - // Add the distant entries - $distantGroupBy = array (); - if ($this->joinObject) - { - foreach ($this->joinObject as $obj) - { - $ext = $obj->groupByGet (true); - $distantGroupBy = array_merge ($distantGroupBy, $ext); - } - } - - $groupBy = array_merge ($localGroupBy, $distantGroupBy); - ksort ($groupBy, SORT_NATURAL); - return $groupBy; - } - - /** Define a LIMIT for the request. - * To use only the nbLines, put a 0 on startLine - * @param integer $startLine The starting line in the result list - * @param integer $nbLines The number of lines to return - */ - public function limit ($startLine, $nbLines) - { - $this->debugLog ("Entering limit (",$startLine,", ",$nbLines,")", 2); - if (! preg_match ("/^\d+$/", $startLine)) - $this->DBException (sprintf ( - "Invalid startLine to limit '%d': not numerical", $startLine)); - if (! preg_match ("/^\d+$/", $nbLines)) - $this->DBException (sprintf ( - "Invalid nbLines to limit '%d': not numerical", $nbLines)); - $startLine = intval ($startLine); - $nbLines = intval ($nbLines); - if ($startLine !== 0) - $this->limitExpression = "$startLine,$nbLines"; - else - $this->limitExpression = "$nbLines"; - return $this; - } - - /** Define a LIMIT for the request. - * @param integer $nbLines The number of lines to return - */ - public function limitLines ($nbLines) - { - $this->debugLog ("Entering limitLines (",$nbLines,")", 2); - if (! preg_match ("/^\d+$/", $nbLines)) - $this->DBException (sprintf ( - "Invalid nbLines to limit '%d': not numerical", $nbLines)); - $nbLines = intval ($nbLines); - $this->limitExpression = "$nbLines"; - return $this; - } - - /** Set INSERT/UPDATE values - * - The provided array must be an associative array, the field name must be - * provided as key and the value as value. Each field=>val will be updated - * @param array $values The values to INSERT or UPDATE - */ - public function setValues ($values) - { - $this->debugLog ("Entering setValues (",$values,")", 2); - if (! is_array ($values)) - $this->DBException ("Invalid values to setValues : not an array"); - $values = $this->normalize ($values); - $associative = null; - $tmpValues = array (); - $tmpType = array (); - foreach ($values as $key=>$val) - { - if (! array_key_exists ($key, $this->fields)) - $this->DBException (sprintf ( - "Invalid field to setValues '%s' : not defined in table", $key)); - if (! is_string ($val) && ! is_int ($val) && ! is_null ($val) && - ! is_float ($val)) - $this->DBException (sprintf ( - "Invalid field to setValues '%s': not string and not numeric", $key)); - $tmpValues[$key] = $val; - $tmpType[md5 ("$key, $val")] = $this->fieldTypeLight ($key); - $this->debugLog ("setValues : Type for $key = ". - $this->fieldTypeLight ($key), 1); - } - $this->setValues = $tmpValues; - $this->setType = $tmpType; - return $this; - } - - /** Create the SQL request - */ - private function createRequest () - { - if ($this->sep === "") - $this->DBException (dgettext ("domframework", "Database not connected")); - if ($this->table === null) - $this->DBException (dgettext ("domframework", - "No table name defined to insert in the table")); - if ($this->unique === null && $this->primary === null) - $this->DBException (dgettext ("domframework", - "Unique fields of table are not defined")); - if (! is_array ($this->unique) && $this->unique !== null) - $this->DBException (dgettext ("domframework", - "The unique configuration is not an array")); - switch ($this->command) - { - case "SELECT": - $sql = "SELECT"; - if ($this->distinct !== "") - $sql .= " ".$this->distinct; - if ($this->joinObject) - $displayColumns = implode (",", $this->displayGet (true)); - elseif (count ($this->displayGet (false))) - $displayColumns = implode (",", $this->displayGet (false)); - else - $displayColumns = "*"; - if ($this->joinObject) - $order = $this->orderGet (true); - else - $order = $this->orderGet (false); - $sql .= " $displayColumns\n FROM $this->sep$this->tableprefix". - "$this->table$this->sep"; - $joinsExpression = $this->joinsGet (); - if ($joinsExpression !== "") - $sql .= "\n ".$this->joinsGet (); - $whereGetExpression = $this->whereGetExpression (); - if (! empty ($whereGetExpression)) - $sql .= "\n WHERE ". implode (" ", $whereGetExpression); - if ($this->groupByNeeded ()) - { - $groupByExpression = $this->groupByGet (); - if (count ($groupByExpression)) - $sql .= "\n GROUP BY ". implode (",", $groupByExpression); - } - if (count ($order)) - $sql .= "\n ORDER BY ". implode (",", $order); - if (! empty ($this->limitExpression)) - $sql .= "\n LIMIT $this->limitExpression"; - // No set Values for SELECT - $this->setValues = array (); - break; - case "INSERT": - $sql = "INSERT INTO $this->sep$this->tableprefix$this->table$this->sep ("; - if (empty ($this->setValues)) - $this->DBException ("No values set to add in INSERT"); - $i = 0; - foreach ($this->setValues as $key=>$val) - { - if ($i > 0) - $sql .= ","; - $sql .= $this->sep.$key.$this->sep; - $i++; - } - $sql .= ") VALUES ("; - $i = 0; - foreach ($this->setValues as $key=>$val) - { - if ($i > 0) - $sql .= ","; - $sql .= ":".md5 ("$key, $val"); - $i++; - } - $sql .= ")"; - // No WHERE in INSERT : remove the WHERE parameters - $this->whereExpression = array (); - $this->whereValues = array (); - break; - case "DELETE": - $sql = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep"; - $whereGetExpression = $this->whereGetExpression (); - if (! empty ($whereGetExpression)) - $sql .= "\n WHERE ". implode (" ", $whereGetExpression); - if (! empty ($this->orderExpression)) - $sql .= " ORDER BY ". implode (",", $this->orderExpression); - if (! empty ($this->limitExpression)) - $sql .= " LIMIT $this->limitExpression"; - // No set Values for DELETE - $this->setValues = array (); - break; - case "UPDATE": - $sql = "UPDATE $this->sep$this->tableprefix$this->table$this->sep"; - if (empty ($this->setValues)) - $this->DBException ("No values to set in UPDATE"); - $sql .= " SET "; - $i = 0; - foreach ($this->setValues as $key=>$val) - { - if ($i > 0) - $sql .= ","; - $hash = md5 ("$key, $val"); - $sql .= $this->sep.$key.$this->sep."=:".$hash; - $i++; - } - $whereGetExpression = $this->whereGetExpression (); - if (! empty ($whereGetExpression)) - $sql .= "\n WHERE ". implode (" ", $whereGetExpression); - if (! empty ($this->orderExpression)) - $sql .= " ORDER BY ". implode (",", $this->orderExpression); - if (! empty ($this->limitExpression)) - $sql .= " LIMIT $this->limitExpression"; - break; - default: - $this->DBException ("No command specified"); - } - return $sql; - } - - /** Prepare the request with the associated entries. - * If textForm is true, return a string to display what will be done - * If textForm is false, return a statement - * @param string $sql The SQL request to prepare - * @param boolean $textForm If true, return the result. If false prepare - * really the request - */ - private function prepareRequest ($sql, $textForm) - { - $text = ""; - if (!$textForm) - { - try - { - $st = self::$instance[$this->dsn]->prepare ($sql); - } - catch (\Exception $e) - { - $this->DBException ($e->getMessage ()); - } - } - foreach ($this->whereGetValues () as $hash=>$val) - { - $field = $val["field"]; - $value = $val["value"]; - $type = $val["type"]; - $text .= "DEBUG BIND WHERE : $hash ($field)->$value "; - if ($value === null) $text .= "NULL (null)\n"; - elseif ($type === "blob") $text .= "(blob)\n"; - elseif ($type === "integer") $text .= "(integer)\n"; - elseif ($type === "float") $text .= "(float)\n"; - elseif ($type === "varchar") $text .= "(varchar)\n"; - elseif ($type === "datetime") $text .= "(datetime)\n"; - elseif ($type === "date") $text .= "(date)\n"; - else - { - $text .= "(UNKNOWN)\n"; - $this->DBException ("TO BE DEVELOPPED : type=".$type); - } - if (!$textForm) - { - if ($value === null) - $st->bindValue (":$hash", $value, \PDO::PARAM_NULL); - elseif ($type === "blob") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - elseif ($type === "integer") - $st->bindValue (":$hash", $value, \PDO::PARAM_INT); - elseif ($type === "float") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - elseif ($type === "varchar") - $st->bindValue (":$hash", "$value", \PDO::PARAM_STR); - elseif ($type === "datetime") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - elseif ($type === "date") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - else - $this->DBException ("prepareRequest:whereValues TO BE DEVELOPPED : ". - "type=$type"); - } - } - foreach ($this->setValues as $field=>$value) - { - $hash = md5 ("$field, $value"); - if (! array_key_exists ($hash, $this->setType)) - $this->DBException (sprintf ("Field '%s' not found in Type list", - $field)); - $type = $this->setType[$hash]; - $text .= "DEBUG BIND SET : $hash ($field)->$value "; - if ($value === null) $text .= "NULL (null)\n"; - elseif ($type === "blob") $text .= "(blob)\n"; - elseif ($type === "integer") $text .= "(integer)\n"; - elseif ($type === "float") $text .= "(float)\n"; - elseif ($type === "varchar") $text .= "(varchar)\n"; - elseif ($type === "datetime") $text .= "(datetime)\n"; - elseif ($type === "date") $text .= "(date)\n"; - else - { - $text .= "(UNKNOWN)\n"; - $this->DBException ("TO BE DEVELOPPED : ".$fields[$field][0]); - } - if (!$textForm) - { - if ($value === null) - $st->bindValue (":$hash", $value, \PDO::PARAM_NULL); - elseif ($this->setType[$hash] === "blob") - $st->bindValue (":$hash", "$value", \PDO::PARAM_STR); - elseif ($this->setType[$hash] === "integer") - $st->bindValue (":$hash", $value, \PDO::PARAM_INT); - elseif ($this->setType[$hash] === "float") - $st->bindValue (":$hash", "$value", \PDO::PARAM_STR); - elseif ($this->setType[$hash] === "varchar") - $st->bindValue (":$hash", "$value", \PDO::PARAM_STR); - elseif ($this->setType[$hash] === "datetime") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - elseif ($this->setType[$hash] === "date") - $st->bindValue (":$hash", $value, \PDO::PARAM_STR); - else - $this->DBException ("prepareRequest:setValues TO BE DEVELOPPED : ". - $this->fields[$field][0]); - } - } - if ($textForm) - return $text; - else - return $st; - } - - /** Return the query that will be executed - */ - public function getDisplayQuery () - { - $text = ""; - $sql = $this->createRequest (); - $text .= "$sql"; - $prep = $this->prepareRequest ($sql, true); - if ($prep !== "") - $text .= "\n$prep"; - return $text; - } - - /** Normalize the values before using them. - * The normalize is called by methods : verify, checkRealTypes and setValues - * By default, remove the spaces (trim) at begin and end. - * This method can be overloaded by extending the class - * @param array $values The values to test or INSERT or UPDATE - * @return array the updated values - */ - public function normalize ($values) - { - if (! is_array ($values)) - $this->DBException ("Invalid values to normalize : not an array", 406); - foreach ($values as $key => $val) - { - if ($val !== null && ! is_array ($val)) - $values[$key] = trim ($val); - } - return $values; - } - - /** Check the provided values which will be inserted or updated against the - * database structure. - * In update, do not forget to define the whereAdd parameters ! - * @param array $values The values to test - * @param boolean|null $update if true UPDATE request, else INSERT request - * @return array The errors found by field - */ - public function verify ($values, $update = false) - { - $update = !! $update; - $errors = array (); - if ($this->table === null) - throw new \Exception ("No table name defined", 500); - if ($this->primary === null) - throw new \Exception ("No primary key defined for table '$this->table'", - 500); - $values = $this->normalize ($values); - if ($update === false) - { - // INSERT mode - if (! array_key_exists ($this->primary, $values)) - $values[$this->primary] = null; - // - Look if all the NOT NULL fields are filled - foreach ($this->fields as $field=>$params) - { - if (in_array ("not null", $params) && - ! array_key_exists ($field, $values)) - $errors[$field] = sprintf (dgettext ("domframework", - "Mandatory field '%s' not provided"), - $field); - elseif (! in_array ("not null", $params) && - ! array_key_exists ($field, $values)) - continue; - } - } - else - { - // UPDATE mode - } - - // INSERT or UPDATE mode - // - Check the validity of the content of the fields. Should be already done - // by the application, so just throw an Exception if the error is raised - foreach ($this->fields as $field=>$params) - { - $this->debugLog (" verify the field validity [$field]", 2); - if ($update !== false && ! array_key_exists ($field, $values)) - // In case of UPDATE, the values are already stored. We can skip the - // test if the user don't want to modify a field (and do not provide the - // value - continue; - if (! in_array ("not null", $params) && - ! array_key_exists ($field, $values)) - continue; - if (in_array ("not null", $params) && - ! array_key_exists ($field, $values)) - { - $errors[$field] = dgettext ("domframework", - "Field mandatory and not provided"); - continue; - } - if (in_array ("not null", $params) && - ! in_array ("autoincrement", $params) && - $values[$field] === null) - { - $errors[$field] = dgettext ("domframework", - "Field null and defined as NOT NULL and ". - "not Autoincrement"); - continue; - } - if (! is_string ($values[$field]) && ! is_integer ($values[$field]) && - ! is_null ($values[$field]) && ! is_float ($values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not a string nor numeric"); - // Do not check the format if the value to store is null. It will never - // matche any format. - if ($values[$field] === null) - continue; - switch ($this->fieldTypeLight ($field)) - { - case "blob": - // Blob can be anything. Do not test - break; - case "integer": - if (strspn ($values[$field], "0123456789") !== strlen ($values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not in integer format"); - break; - case "float": - if (strspn ($values[$field], "0123456789.") !== - strlen ($values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not in float format"); - break; - case "varchar": - $length = $this->fieldLength ($field); - if (mb_strlen ($values[$field]) > $length) - $errors[$field] = dgettext ("domframework", "Field data too long"); - break; - case "date": - if (! preg_match ("#^\d{4}-\d{2}-\d{2}$#", $values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not in date format"); - break; - case "datetime": - if (! preg_match ("#^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$#", - $values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not in datetime format"); - break; - case "time": - if (! preg_match ("#^\d{2}:\d{2}:\d{2}$#", $values[$field])) - $errors[$field] = dgettext ("domframework", - "Field not in time format"); - break; - default: - $errors[$field] = sprintf (dgettext ("domframework", - "Field '%s' : invalid SQL type (%s) in ". - "\$this->fields "), $field, - $this->fieldTypeLight ($field)); - } - } - - // - Check the unique entries (if defined) - // The primary key is always unique : add it if not set by the user - $this->debugLog (" verify the unique constraint", 2); - $uniques = $this->unique; - if (! is_array ($uniques)) - $uniques = array (); - if (! in_array ($this->primary, $uniques)) - $uniques = array_merge (array ($this->primary), $uniques); - $setValues = $values; - $foundImpactedLines = 0; - foreach ($uniques as $k=>$columns) - { - if ($update) - { - // Can not update multiple UNIQUE rows with the same value - if (is_string ($columns)) - $cols = explode (",", $columns); - elseif (is_array ($columns)) - $cols = $columns; - else - $this->DBException (dgettext ("domframework", - "Unique def is not a string or an array")); - foreach ($cols as $col) - { - if (!key_exists ($col, $setValues)) - continue; - // One column to set is a unique column : check if the where clause - // is filtering more than one entry. If there is more than one - // entry, generate an exception - $this->debugLog ("CLONE because of checking update unique fields", 2); - $objTmp = clone $this; - $objTmp->debugDepth++; - $objTmp->clearRequest (); - $objTmp->Select (); - $objTmp->displayAdd ($this->primary); - $objTmp->displayAdd ($columns); - $objTmp->whereValues = $this->whereValues; - $objTmp->whereExpression = $this->whereExpression; - $objTmp->limitLines (3); - $resUpdate = $objTmp->execute (); - unset ($objTmp); - if (count ($resUpdate) > 1) - $this->DBException (sprintf (dgettext ("domframework", - "Can't update multiple rows with unique value on col '%s'"), - $col)); - elseif (count ($resUpdate) === 1) - $foundImpactedLines++; + if ($this->driver === "pgsql" && $operator === "REGEXP") { + $operator = "~"; } - if ($foundImpactedLines === 0) - { - // There is no row available with the WHERE clause provided - // Skip all the UNIQUE tests as there will not have any modification - break; + if ($this->driver === "pgsql" && $operator === "NOT REGEXP") { + $operator = "!~"; } - } - if (! array_key_exists ($this->primary, $setValues)) - $setValues[$this->primary] = null; + if ($operator === "IS NULL" || $operator === "IS NOT NULL") { + // Operator without parameter + $this->whereExpression[] = + $this->sep . $this->tableprefix . $this->table . $this->sep . "." . + $this->sep . $field . $this->sep . " " . $operator; + } else { + // Operator with parameter + $hash = md5("$field, $operator, $value"); + $this->whereExpression[] = + $this->sep . $this->tableprefix . $this->table . $this->sep . "." . + $this->sep . $field . $this->sep . " " . $operator . " :$hash"; + $this->whereValues[$hash] = array( + "field" => $field, + "fieldfull" => $this->tableprefix . $this->table . "." . $field, + "operator" => $operator, + "value" => $value, + "hash" => $hash, + "type" => $this->fieldTypeLight($field)); + } + return $this; + } - $this->debugLog ("CLONE to check primary and unique constraint", 2); - $objTmp = clone $this; - $objTmp->debugDepth++; - $objTmp->clearRequest (); - $objTmp->Select (); - $objTmp->displayAdd ($this->primary); - if (is_array ($columns)) - { - // Multiple columns in unique - $objTmp->debugLog (" verify the unique multiple [", - implode (",", $columns),"]", 2); - foreach ($columns as $column) - { - if (! array_key_exists ($column, $setValues)) - { - if ($update !== false && array_key_exists (0, $resUpdate)) - { - // In UPDATE, if a column is not modified (doesn't appears in - // setValues), use the old value to search - $valTest = $resUpdate[0][$column]; - $objTmp->whereAdd ($column, "=", $valTest); + /** Add a new AND to the WHERE expression + */ + public function whereAddAND() + { + $this->debugLog("Entering whereAddAND ()", 2); + if (count($this->whereExpression) === 0) { + $this->DBException("Can not add AND as there is no previous expression"); + } + $this->whereExpression[] = "AND"; + return $this; + } + + /** Add a new OR to the WHERE expression + */ + public function whereAddOR() + { + $this->debugLog("Entering whereAddOR ()", 2); + if (count($this->whereExpression) === 0) { + $this->DBException("Can not add OR as there is no previous expression"); + } + $this->whereExpression[] = "OR"; + return $this; + } + + /** Add a new Open Parenthesis to the WHERE expression + */ + public function whereAddParenthesisOpen() + { + $this->debugLog("Entering whereAddParenthesisOpen ()", 2); + if ( + count($this->whereExpression) && + end($this->whereExpression) !== "AND" && + end($this->whereExpression) !== "OR" && + end($this->whereExpression) !== "(" + ) { + $this->whereExpression[] = "AND"; + } + $this->whereExpression[] = "("; + return $this; + } + + /** Add a new Close Parenthesis to the WHERE expression + */ + public function whereAddParenthesisClose() + { + $this->debugLog("Entering whereAddParenthesisClose ()", 2); + $this->whereExpression[] = ")"; + return $this; + } + + /** Get the WHERE clause of the object. + * If the joinObject is set, return all the WHERE clauses + */ + public function whereGetExpression() + { + $whereExpression = $this->whereExpression; + if ($whereExpression === null) { + $whereExpression = array(); + } + if ($this->joinObject !== null) { + foreach ($this->joinObject as $obj) { + $exp = $obj->whereGetExpression(); + if (count($whereExpression) && count($exp)) { + $whereExpression[] = "AND"; + } + if (count($exp)) { + $whereExpression[] = "("; + } + $whereExpression = array_merge( + $whereExpression, + $exp + ); + if (count($exp)) { + $whereExpression[] = ")"; + } } - else - $errors[$column] = sprintf (dgettext ("domframework", - "No column '%s' defined but must be unique !"), $column); - } - else - $objTmp->whereAdd ($column, "=", $setValues[$column]); } - } - else - { - // One column in unique - $objTmp->debugLog (" verify the unique one column [$columns]", 2); - if (! array_key_exists ($columns, $setValues)) - $errors[$columns] = sprintf (dgettext ("domframework", - "No column '%s' defined but must be unique !"), $columns); - else - $objTmp->whereAdd ($columns, "=", $setValues[$columns]); - } - if ($update && array_key_exists (0, $resUpdate)) - { - // If the value already exists, check if it is the same (the SQL can - // overwrite with the same value) - // If it is not the same, produce an error - $objTmp->whereAdd ($this->primary, "!=", - $resUpdate[0][$this->primary]); - } - if (count ($errors) == 0 && count ($objTmp->execute ())) - { - if (is_array ($columns)) - { - foreach ($columns as $column) - { - $errors[$column] = sprintf (dgettext ("domframework", - "An entry with this value '%s' already exists"), - mb_substr ($setValues[$column], 0, 15)); - } - } - else - { - $errors[$columns] = sprintf (dgettext ("domframework", - "An entry with this value '%s' already exists"), - mb_substr ($setValues[$columns], 0, 15)); - } - } - unset ($objTmp); + return $whereExpression; } - // - If foreign keys, check if the value is set in the constraint - foreach ($this->foreign as $fields=>$params) + /** Get the WHERE values of the object. + * If the joinObject is set, return all the WHERE clauses with AND and + * parenthesis + */ + public function whereGetValues() { - foreach (explode (",", $fields) as $field) - { - // Do not test in update if the field is not provided as it was already - // recorded - if ($update === true && ! array_key_exists ($field, $values)) - continue 2; - if (! array_key_exists ($field, $values) && - in_array ("not null", $this->fields[$field])) - { - $errors[$field] = sprintf (dgettext ("domframework", - "The field '%s' must be test on foreign, but is not provided"), - $field); - continue; + $whereValues = $this->whereValues; + if ($whereValues === null) { + $whereValues = array(); } - if (! array_key_exists ($params[0], $this->setForeignObj)) - $this->DBException (sprintf (dgettext ("domframework", - "No foreign object configured to test the foreign key for table ". - "'%s'"), $this->table)); - if (! array_key_exists ($field, $values) && - ! in_array ("not null", $this->fields[$field])) - $values[$field] = null; - } - $this->debugLog ("CLONE to check foreign constraint [$fields]", 2); - $objTmp = clone $this->setForeignObj[$params[0]]; - $objTmp->debug = $this->debug; - $objTmp->debugDepth++; - $objTmp->clearRequest (); - $objTmp->Select (); - $objTmp->displayAdd ($objTmp->primary); - $parentField = explode (",", $params[1]); - $i = 0; - foreach (explode (",", $fields) as $key=>$field) - { - if (key_exists ($field, $values) && $values[$field] !== null) - { - $objTmp->whereAdd ($parentField[$key], "=", $values[$field]); - $i++; + if ($this->joinObject !== null) { + foreach ($this->joinObject as $obj) { + $whereValues = array_merge( + $whereValues, + $obj->whereGetValues() + ); + } } - } - if ($i == 0) - { - // If the foreign is null, do not test as there is no WHERE clause, and - // will return all the table - continue; - } - if (count ($objTmp->execute ()) === 0) - $errors[$field] = sprintf (dgettext ("domframework", - "The value of the foreign key '%s' doesn't exists in foreign table"), - $field); + return $whereValues; } - return $errors; - } - /** Check the values before doing really the modification of the database - * @param array $values The values to test - * @param boolean|null $update if true UPDATE request, else INSERT request - */ - public function checkValues ($values, $update = false) - { - $this->debugLog ("Entering checkValues (",$update,")", 2); - if (! is_array ($values)) + /** Add a new ORDER sort. The multiple ORDERS are used from the first added to + * the last added + * @param string $field The field to sort + * @param string|null $sort The sort order ("ASC", "DESC", "NATASC", + * "NATDESC"); + */ + public function orderAdd($field, $sort = "ASC") { - $this->DBException ("checkValues fields : ". - "values provided are not an array", 406); + $this->debugLog("Entering orderAdd (", $field, ", ", $sort, ")", 2); + if (! is_string($field)) { + $this->DBException("Invalid field provided (not string)"); + } + if (! is_string($sort)) { + $this->DBException("Invalid sort provided (not string)"); + } + $sort = strtoupper($sort); + if (! in_array($sort, array("ASC", "DESC", "NATASC", "NATDESC"))) { + $this->DBException( + "Invalid sort provided (not ASC nor DESC nor NATASC nor NATDESC)" + ); + } + if ( + ! array_key_exists($field, $this->fields) && + ! in_array($field, $this->displayAlias) + ) { + $this->DBException(sprintf( + "Invalid field to orderAdd '%s' : not defined in table nor in alias", + $field + )); + } + $plus = ""; + if (substr($sort, 0, 3) === "NAT") { + $plus = "+0"; + $sort = substr($sort, 3); + } + $exp = $this->sep . $field . $this->sep . $plus . " " . $sort; + if ($plus !== "") { + $exp .= "," . $this->sep . $this->table . $this->sep . "." . + $this->sep . $field . $this->sep . " " . $sort; + } + $this->orderExpression[$this->getSortOrder()] = $exp; + return $this; } - $values = $this->normalize ($values); - $update = !! $update; - $errors = array_merge ($this->verify ($values, $update), - $this->checkRealTypes ($values, $update)); - if (count ($errors) === 0) - $this->debugLog ("End of checkValues (",$update,") : Nothing in error", - 2); - else - $this->debugLog ("End of checkValues (",$update,") : ".count ($errors). - "errors", 2); - return $errors; - } - /** Check the types of the data against the realTypes - * Return an array with the field name in error and a message - * If allowEmpty is set, do not test the "NOT NULL" feature - * In UPDATE, the values don't need be not set : they are already in database - * so $allowEmpty is true - * @param array $values The values to test - * @param boolean|null $allowEmpty Allow the "not null" to not be set - * @return array empty array if no error - */ - public function checkRealTypes ($values, $allowEmpty = false) - { - $this->debugLog ("Entering checkRealTypes (",$values,",",$allowEmpty,")", - 2); - if (! is_array ($values)) - $this->DBException ("Invalid checkRealTypes provided : not an array", - 500); - $values = $this->normalize ($values); - $errors = array (); - foreach ($this->fields as $field => $params) + /** Get the ORDER fields defined. If a joinObject is set with ORDER statement, + * return the joinObject order with its tableprefix/name in addition of + * the ones of this object + * If the parameter $full is set, add the table prefix/name to the result + * @param boolean|null $full Add the table prefix/name if set + */ + public function orderGet($full = false) { - if (! key_exists ($field, $values) || trim ($values[$field]) === "") - { - if (in_array ("not null", $params) && - ! in_array ("autoincrement", $params)) - { - if ($allowEmpty === false) - $errors[$field] = dgettext ("domframework", - "The field can not be empty"); + $order = array(); + if ($this->joinObject) { + $full = true; } - else - { - // Empty value is not tested and do not generate an error + foreach ($this->orderExpression as $pos => $o) { + if ($full !== false) { + $order[$pos] = $this->sep . $this->tableprefix . $this->table . $this->sep . + "." . $o; + } else { + $order[$pos] = $o; + } } - } - elseif (! is_string ($values[$field])) - { - $errors[$field] = dgettext ("domframework", - "The value is not a string"); - } - elseif (key_exists ($field, $this->realTypes)) - { - $val = trim ($values[$field]); - @list ($func, $param) = explode ("(", $this->realTypes[$field]); - $func = trim ($func); - $method = "checkRealType_".$func; - $res = $this->$method ($val, $this->realTypes[$field]); - if (is_string ($res)) - $errors[$field] = $res; - } + if ($this->joinObject) { + foreach ($this->joinObject as $obj) { + $order = array_merge($order, $obj->orderGet(true)); + } + } + ksort($order, SORT_NATURAL); + return $order; } - $this->debugLog ("End checkRealTypes (", $values, ",", $allowEmpty, ") : ", - $errors, 2); - return $errors; - } - /** Execute the pre-defined query - * Return the content array if SELECT command is choosed - * Return the Last ID if INSERT command is choosed - * Return the number of modified lines for UPDATE/DELETE command - */ - public function execute () - { - $this->debugLog ("Entering execute ()", 2); - switch ($this->command) + /** Return true if this object or one of the join objects need GROUP BY SQL + * part + */ + public function groupByNeeded() { - case "SELECT": - break; - case "INSERT": - $errors = $this->checkValues ($this->setValues, false); - if (count ($errors)) - { - $val = reset ($errors); - $this->DBException (key ($errors)." : $val", 406); - } - break; - case "UPDATE": - $errors = $this->checkValues ($this->setValues, true); - if (count ($errors)) - { - $val = reset ($errors); - $this->DBException (key ($errors)." : $val", 406); - } - break; - case "DELETE": - break; - default: - $this->DBException ("execute : command not defined : no check"); + $needGroupBy = false; + if ($this->groupByExpression !== null) { + $needGroupBy = true; + } + if ($this->joinObject) { + foreach ($this->joinObject as $obj) { + if ($obj->groupByNeeded() === true) { + $needGroupBy = true; + } + } + } + return $needGroupBy; } - $this->debugLog ("Entering createRequest ()", 2); - $sql = $this->createRequest (); - $this->debugLog ("Entering prepareRequest (XXX, ",false,")", 2); - $st = $this->prepareRequest ($sql, false); - $this->debugLog ("'", $this->getDisplayQuery (), "'", 1); - $startTime = microtime (true); - $st->execute (); - switch ($this->command) + + /** Get the GROUP BY fields defined. If a joinObject is set with GROUP BY + * statement, return the joinObject order with its tableprefix/name in + * addition of the ones of this object + * If the parameter $full is set, add the table prefix/name to the result + * @param boolean|null $full Add the table prefix/name if set + */ + public function groupByGet($full = false) { - case "SELECT": - $result = $st->fetchAll (\PDO::FETCH_NUM); - // There is no fetchAll corresponding to the columnName->value. Assign the - // name to the value by index. - // FETCH_ASSOC doesn't work in empty left join (return NULL instead of - // the filled value) - $fieldsAll = $this->fieldsAll (true); - // If the displayed fields are all in the same table, remove the table - // name in the columns - $cleanable = true; - $cleanTable = ""; - foreach ($this->displayGet (true) as $display) - { - preg_match_all ("#".$this->sep."(.+)".$this->sep."\.#", $display, - $matches); - if ($cleanTable === "") - $cleanTable = $matches[1][0]; - elseif ($cleanTable !== $matches[1][0]) - { - $cleanable = false; - break; + if ($this->joinObject) { + $full = true; } - } - $columns = array_values ($this->displayGet (true)); - // Get the columns names that will be displayed to user. - // If the cleanable is possible, remove the table names - $columnNames = array_combine ($columns, $columns); - //if ($this->joinObject === null && count ($this->displayGet (false))) - if ($cleanable) - { - // Remove the table name as there is no collisions risk - // In case of Alias, remove the $this->sep too - foreach ($columnNames as $key => $col) - { - // Remove the table and the separator if exists - $col = preg_replace ("#".$this->sep."[^".$this->sep."]+". - $this->sep."\.#U", "", $col); - // Remove the separator if not table exists - $col = str_replace ($this->sep, "", $col); - if ($col[0] === $this->sep) - $col = substr ($col, 1); - elseif (strpos ($col, "DISTINCT ".$this->sep) === 0) - $col = "DISTINCT ".substr ($col, 10); - if (substr ($col, -1) === $this->sep && - strpos ($col, " AS ".$this->sep) === false) - { - $col = substr ($col, 0, -1); - } - if (strpos ($col, " AS ".$this->sep)) - { - // remove the separator before the AS - $col = substr ($col, 0, strpos ($col, " AS ".$this->sep) -1). - substr ($col, strpos ($col, " AS ".$this->sep)); - } - $columnNames[$key] = $col; + + $localGroupBy = array(); + // Manage the local object group by entries. In full mode, return the + // groupByExpression if it is set, or the list of the displayed fields. + if ($full) { + if ($this->groupByExpression !== null) { + foreach ($this->groupByExpression as $pos => $o) { + if ($localGroupBy === null) { + $localGroupBy = array(); + } + $localGroupBy[$pos] = $this->sep . $this->tableprefix . $this->table . + $this->sep . "." . $o; + } + } elseif ($this->displayColumn !== null) { + foreach ($this->displayColumn as $name) { + $localGroupBy[] = $this->displayConvert($name, true); + } + } else { + // Nothing to return if there is no groupBy and nothing to display + } + } else { + if ($this->groupByExpression !== null) { + $localGroupBy = $this->groupByExpression; + } else { + $localGroupBy = array(); + } } - } - else - { - foreach ($columnNames as $key => $col) - { - $columnNames[$key] = str_replace ($this->sep, "", $col); + + // Add the distant entries + $distantGroupBy = array(); + if ($this->joinObject) { + foreach ($this->joinObject as $obj) { + $ext = $obj->groupByGet(true); + $distantGroupBy = array_merge($distantGroupBy, $ext); + } } - } - foreach ($result as $rownb=>$row) - { - foreach ($row as $colNb=>$val) - { - // Harmonize the fetchAll result between all the databases drivers - $pos = strpos ($columns[$colNb], "("); - if ($pos) - { - // Function. The function that return an int must be added in this - // list, to cast correctely the value - $func = strtoupper (trim (substr ($columns[$colNb], 0, $pos))); - if (in_array ($func, array ("AVG", "COUNT", "MAX", "MIN", "SUM"))) - $val = intval ($val); - } - else - { - $name = $columns[$colNb]; - $pos = strpos ($columns[$colNb], " AS "); - if ($pos) - $name = substr ($columns[$colNb], 0, $pos); - $name = str_replace ("DISTINCT ", "", $name); - /*if ($cleanable) - $name = str_replace ($this->sep.$this->tableprefix.$this->table. - $this->sep.".", "", $name);*/ - if (strtolower ($fieldsAll[$name][0]) === "integer" && - $val !== null) - $val = intval ($val); - } - if (($pos = strpos ($columns[$colNb], " AS ".$this->sep)) !== false) - { - $pos += strlen (" AS ".$this->sep); - $colName = substr ($columns[$colNb], $pos, -1); - } - else - $colName = $columnNames[$columns[$colNb]]; - $result[$rownb][$colName] = $val; - unset ($result[$rownb][$colNb]); + + $groupBy = array_merge($localGroupBy, $distantGroupBy); + ksort($groupBy, SORT_NATURAL); + return $groupBy; + } + + /** Define a LIMIT for the request. + * To use only the nbLines, put a 0 on startLine + * @param integer $startLine The starting line in the result list + * @param integer $nbLines The number of lines to return + */ + public function limit($startLine, $nbLines) + { + $this->debugLog("Entering limit (", $startLine, ", ", $nbLines, ")", 2); + if (! preg_match("/^\d+$/", $startLine)) { + $this->DBException(sprintf( + "Invalid startLine to limit '%d': not numerical", + $startLine + )); } - } - self::$meta[] = array ( - "command" => $this->command, - "sql" => $sql, - "sqltime" => microtime (true) - $startTime, - "displayQuery" => $this->getDisplayQuery (), - "nbrows" => count ($result), - ); - return $result; - case "INSERT": - self::$meta[] = array ( - "command" => $this->command, - "sql" => $sql, - "sqltime" => microtime (true) - $startTime, - "displayQuery" => $this->getDisplayQuery (), - "nbrows" => $st->rowCount (), - ); - // If the primary key is not autoincrement, return the provided value if - // exists - if (! in_array ("autoincrement", $this->fields[$this->primary]) && - key_exists ($this->primary, $this->setValues)) - return $this->setValues[$this->primary]; + if (! preg_match("/^\d+$/", $nbLines)) { + $this->DBException(sprintf( + "Invalid nbLines to limit '%d': not numerical", + $nbLines + )); + } + $startLine = intval($startLine); + $nbLines = intval($nbLines); + if ($startLine !== 0) { + $this->limitExpression = "$startLine,$nbLines"; + } else { + $this->limitExpression = "$nbLines"; + } + return $this; + } + + /** Define a LIMIT for the request. + * @param integer $nbLines The number of lines to return + */ + public function limitLines($nbLines) + { + $this->debugLog("Entering limitLines (", $nbLines, ")", 2); + if (! preg_match("/^\d+$/", $nbLines)) { + $this->DBException(sprintf( + "Invalid nbLines to limit '%d': not numerical", + $nbLines + )); + } + $nbLines = intval($nbLines); + $this->limitExpression = "$nbLines"; + return $this; + } + + /** Set INSERT/UPDATE values + * - The provided array must be an associative array, the field name must be + * provided as key and the value as value. Each field=>val will be updated + * @param array $values The values to INSERT or UPDATE + */ + public function setValues($values) + { + $this->debugLog("Entering setValues (", $values, ")", 2); + if (! is_array($values)) { + $this->DBException("Invalid values to setValues : not an array"); + } + $values = $this->normalize($values); + $associative = null; + $tmpValues = array(); + $tmpType = array(); + foreach ($values as $key => $val) { + if (! array_key_exists($key, $this->fields)) { + $this->DBException(sprintf( + "Invalid field to setValues '%s' : not defined in table", + $key + )); + } + if ( + ! is_string($val) && ! is_int($val) && ! is_null($val) && + ! is_float($val) + ) { + $this->DBException(sprintf( + "Invalid field to setValues '%s': not string and not numeric", + $key + )); + } + $tmpValues[$key] = $val; + $tmpType[md5("$key, $val")] = $this->fieldTypeLight($key); + $this->debugLog("setValues : Type for $key = " . + $this->fieldTypeLight($key), 1); + } + $this->setValues = $tmpValues; + $this->setType = $tmpType; + return $this; + } + + /** Create the SQL request + */ + private function createRequest() + { + if ($this->sep === "") { + $this->DBException(dgettext("domframework", "Database not connected")); + } + if ($this->table === null) { + $this->DBException(dgettext( + "domframework", + "No table name defined to insert in the table" + )); + } + if ($this->unique === null && $this->primary === null) { + $this->DBException(dgettext( + "domframework", + "Unique fields of table are not defined" + )); + } + if (! is_array($this->unique) && $this->unique !== null) { + $this->DBException(dgettext( + "domframework", + "The unique configuration is not an array" + )); + } + switch ($this->command) { + case "SELECT": + $sql = "SELECT"; + if ($this->distinct !== "") { + $sql .= " " . $this->distinct; + } + if ($this->joinObject) { + $displayColumns = implode(",", $this->displayGet(true)); + } elseif (count($this->displayGet(false))) { + $displayColumns = implode(",", $this->displayGet(false)); + } else { + $displayColumns = "*"; + } + if ($this->joinObject) { + $order = $this->orderGet(true); + } else { + $order = $this->orderGet(false); + } + $sql .= " $displayColumns\n FROM $this->sep$this->tableprefix" . + "$this->table$this->sep"; + $joinsExpression = $this->joinsGet(); + if ($joinsExpression !== "") { + $sql .= "\n " . $this->joinsGet(); + } + $whereGetExpression = $this->whereGetExpression(); + if (! empty($whereGetExpression)) { + $sql .= "\n WHERE " . implode(" ", $whereGetExpression); + } + if ($this->groupByNeeded()) { + $groupByExpression = $this->groupByGet(); + if (count($groupByExpression)) { + $sql .= "\n GROUP BY " . implode(",", $groupByExpression); + } + } + if (count($order)) { + $sql .= "\n ORDER BY " . implode(",", $order); + } + if (! empty($this->limitExpression)) { + $sql .= "\n LIMIT $this->limitExpression"; + } + // No set Values for SELECT + $this->setValues = array(); + break; + case "INSERT": + $sql = "INSERT INTO $this->sep$this->tableprefix$this->table$this->sep ("; + if (empty($this->setValues)) { + $this->DBException("No values set to add in INSERT"); + } + $i = 0; + foreach ($this->setValues as $key => $val) { + if ($i > 0) { + $sql .= ","; + } + $sql .= $this->sep . $key . $this->sep; + $i++; + } + $sql .= ") VALUES ("; + $i = 0; + foreach ($this->setValues as $key => $val) { + if ($i > 0) { + $sql .= ","; + } + $sql .= ":" . md5("$key, $val"); + $i++; + } + $sql .= ")"; + // No WHERE in INSERT : remove the WHERE parameters + $this->whereExpression = array(); + $this->whereValues = array(); + break; + case "DELETE": + $sql = "DELETE FROM $this->sep$this->tableprefix$this->table$this->sep"; + $whereGetExpression = $this->whereGetExpression(); + if (! empty($whereGetExpression)) { + $sql .= "\n WHERE " . implode(" ", $whereGetExpression); + } + if (! empty($this->orderExpression)) { + $sql .= " ORDER BY " . implode(",", $this->orderExpression); + } + if (! empty($this->limitExpression)) { + $sql .= " LIMIT $this->limitExpression"; + } + // No set Values for DELETE + $this->setValues = array(); + break; + case "UPDATE": + $sql = "UPDATE $this->sep$this->tableprefix$this->table$this->sep"; + if (empty($this->setValues)) { + $this->DBException("No values to set in UPDATE"); + } + $sql .= " SET "; + $i = 0; + foreach ($this->setValues as $key => $val) { + if ($i > 0) { + $sql .= ","; + } + $hash = md5("$key, $val"); + $sql .= $this->sep . $key . $this->sep . "=:" . $hash; + $i++; + } + $whereGetExpression = $this->whereGetExpression(); + if (! empty($whereGetExpression)) { + $sql .= "\n WHERE " . implode(" ", $whereGetExpression); + } + if (! empty($this->orderExpression)) { + $sql .= " ORDER BY " . implode(",", $this->orderExpression); + } + if (! empty($this->limitExpression)) { + $sql .= " LIMIT $this->limitExpression"; + } + break; + default: + $this->DBException("No command specified"); + } + return $sql; + } + + /** Prepare the request with the associated entries. + * If textForm is true, return a string to display what will be done + * If textForm is false, return a statement + * @param string $sql The SQL request to prepare + * @param boolean $textForm If true, return the result. If false prepare + * really the request + */ + private function prepareRequest($sql, $textForm) + { + $text = ""; + if (!$textForm) { + try { + $st = self::$instance[$this->dsn]->prepare($sql); + } catch (\Exception $e) { + $this->DBException($e->getMessage()); + } + } + foreach ($this->whereGetValues() as $hash => $val) { + $field = $val["field"]; + $value = $val["value"]; + $type = $val["type"]; + $text .= "DEBUG BIND WHERE : $hash ($field)->$value "; + if ($value === null) { + $text .= "NULL (null)\n"; + } elseif ($type === "blob") { + $text .= "(blob)\n"; + } elseif ($type === "integer") { + $text .= "(integer)\n"; + } elseif ($type === "float") { + $text .= "(float)\n"; + } elseif ($type === "varchar") { + $text .= "(varchar)\n"; + } elseif ($type === "datetime") { + $text .= "(datetime)\n"; + } elseif ($type === "date") { + $text .= "(date)\n"; + } else { + $text .= "(UNKNOWN)\n"; + $this->DBException("TO BE DEVELOPPED : type=" . $type); + } + if (!$textForm) { + if ($value === null) { + $st->bindValue(":$hash", $value, \PDO::PARAM_NULL); + } elseif ($type === "blob") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } elseif ($type === "integer") { + $st->bindValue(":$hash", $value, \PDO::PARAM_INT); + } elseif ($type === "float") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } elseif ($type === "varchar") { + $st->bindValue(":$hash", "$value", \PDO::PARAM_STR); + } elseif ($type === "datetime") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } elseif ($type === "date") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } else { + $this->DBException("prepareRequest:whereValues TO BE DEVELOPPED : " . + "type=$type"); + } + } + } + foreach ($this->setValues as $field => $value) { + $hash = md5("$field, $value"); + if (! array_key_exists($hash, $this->setType)) { + $this->DBException(sprintf( + "Field '%s' not found in Type list", + $field + )); + } + $type = $this->setType[$hash]; + $text .= "DEBUG BIND SET : $hash ($field)->$value "; + if ($value === null) { + $text .= "NULL (null)\n"; + } elseif ($type === "blob") { + $text .= "(blob)\n"; + } elseif ($type === "integer") { + $text .= "(integer)\n"; + } elseif ($type === "float") { + $text .= "(float)\n"; + } elseif ($type === "varchar") { + $text .= "(varchar)\n"; + } elseif ($type === "datetime") { + $text .= "(datetime)\n"; + } elseif ($type === "date") { + $text .= "(date)\n"; + } else { + $text .= "(UNKNOWN)\n"; + $this->DBException("TO BE DEVELOPPED : " . $fields[$field][0]); + } + if (!$textForm) { + if ($value === null) { + $st->bindValue(":$hash", $value, \PDO::PARAM_NULL); + } elseif ($this->setType[$hash] === "blob") { + $st->bindValue(":$hash", "$value", \PDO::PARAM_STR); + } elseif ($this->setType[$hash] === "integer") { + $st->bindValue(":$hash", $value, \PDO::PARAM_INT); + } elseif ($this->setType[$hash] === "float") { + $st->bindValue(":$hash", "$value", \PDO::PARAM_STR); + } elseif ($this->setType[$hash] === "varchar") { + $st->bindValue(":$hash", "$value", \PDO::PARAM_STR); + } elseif ($this->setType[$hash] === "datetime") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } elseif ($this->setType[$hash] === "date") { + $st->bindValue(":$hash", $value, \PDO::PARAM_STR); + } else { + $this->DBException("prepareRequest:setValues TO BE DEVELOPPED : " . + $this->fields[$field][0]); + } + } + } + if ($textForm) { + return $text; + } else { + return $st; + } + } + + /** Return the query that will be executed + */ + public function getDisplayQuery() + { + $text = ""; + $sql = $this->createRequest(); + $text .= "$sql"; + $prep = $this->prepareRequest($sql, true); + if ($prep !== "") { + $text .= "\n$prep"; + } + return $text; + } + + /** Normalize the values before using them. + * The normalize is called by methods : verify, checkRealTypes and setValues + * By default, remove the spaces (trim) at begin and end. + * This method can be overloaded by extending the class + * @param array $values The values to test or INSERT or UPDATE + * @return array the updated values + */ + public function normalize($values) + { + if (! is_array($values)) { + $this->DBException("Invalid values to normalize : not an array", 406); + } + foreach ($values as $key => $val) { + if ($val !== null && ! is_array($val)) { + $values[$key] = trim($val); + } + } + return $values; + } + + /** Check the provided values which will be inserted or updated against the + * database structure. + * In update, do not forget to define the whereAdd parameters ! + * @param array $values The values to test + * @param boolean|null $update if true UPDATE request, else INSERT request + * @return array The errors found by field + */ + public function verify($values, $update = false) + { + $update = !! $update; + $errors = array(); + if ($this->table === null) { + throw new \Exception("No table name defined", 500); + } + if ($this->primary === null) { + throw new \Exception( + "No primary key defined for table '$this->table'", + 500 + ); + } + $values = $this->normalize($values); + if ($update === false) { + // INSERT mode + if (! array_key_exists($this->primary, $values)) { + $values[$this->primary] = null; + } + // - Look if all the NOT NULL fields are filled + foreach ($this->fields as $field => $params) { + if ( + in_array("not null", $params) && + ! array_key_exists($field, $values) + ) { + $errors[$field] = sprintf( + dgettext( + "domframework", + "Mandatory field '%s' not provided" + ), + $field + ); + } elseif ( + ! in_array("not null", $params) && + ! array_key_exists($field, $values) + ) { + continue; + } + } + } else { + // UPDATE mode + } + + // INSERT or UPDATE mode + // - Check the validity of the content of the fields. Should be already done + // by the application, so just throw an Exception if the error is raised + foreach ($this->fields as $field => $params) { + $this->debugLog(" verify the field validity [$field]", 2); + if ($update !== false && ! array_key_exists($field, $values)) { + // In case of UPDATE, the values are already stored. We can skip the + // test if the user don't want to modify a field (and do not provide the + // value + continue; + } + if ( + ! in_array("not null", $params) && + ! array_key_exists($field, $values) + ) { + continue; + } + if ( + in_array("not null", $params) && + ! array_key_exists($field, $values) + ) { + $errors[$field] = dgettext( + "domframework", + "Field mandatory and not provided" + ); + continue; + } + if ( + in_array("not null", $params) && + ! in_array("autoincrement", $params) && + $values[$field] === null + ) { + $errors[$field] = dgettext( + "domframework", + "Field null and defined as NOT NULL and " . + "not Autoincrement" + ); + continue; + } + if ( + ! is_string($values[$field]) && ! is_integer($values[$field]) && + ! is_null($values[$field]) && ! is_float($values[$field]) + ) { + $errors[$field] = dgettext( + "domframework", + "Field not a string nor numeric" + ); + } + // Do not check the format if the value to store is null. It will never + // matche any format. + if ($values[$field] === null) { + continue; + } + switch ($this->fieldTypeLight($field)) { + case "blob": + // Blob can be anything. Do not test + break; + case "integer": + if (strspn($values[$field], "0123456789") !== strlen($values[$field])) { + $errors[$field] = dgettext( + "domframework", + "Field not in integer format" + ); + } + break; + case "float": + if ( + strspn($values[$field], "0123456789.") !== + strlen($values[$field]) + ) { + $errors[$field] = dgettext( + "domframework", + "Field not in float format" + ); + } + break; + case "varchar": + $length = $this->fieldLength($field); + if (mb_strlen($values[$field]) > $length) { + $errors[$field] = dgettext("domframework", "Field data too long"); + } + break; + case "date": + if (! preg_match("#^\d{4}-\d{2}-\d{2}$#", $values[$field])) { + $errors[$field] = dgettext( + "domframework", + "Field not in date format" + ); + } + break; + case "datetime": + if ( + ! preg_match( + "#^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$#", + $values[$field] + ) + ) { + $errors[$field] = dgettext( + "domframework", + "Field not in datetime format" + ); + } + break; + case "time": + if (! preg_match("#^\d{2}:\d{2}:\d{2}$#", $values[$field])) { + $errors[$field] = dgettext( + "domframework", + "Field not in time format" + ); + } + break; + default: + $errors[$field] = sprintf( + dgettext( + "domframework", + "Field '%s' : invalid SQL type (%s) in " . + "\$this->fields " + ), + $field, + $this->fieldTypeLight($field) + ); + } + } + + // - Check the unique entries (if defined) + // The primary key is always unique : add it if not set by the user + $this->debugLog(" verify the unique constraint", 2); + $uniques = $this->unique; + if (! is_array($uniques)) { + $uniques = array(); + } + if (! in_array($this->primary, $uniques)) { + $uniques = array_merge(array($this->primary), $uniques); + } + $setValues = $values; + $foundImpactedLines = 0; + foreach ($uniques as $k => $columns) { + if ($update) { + // Can not update multiple UNIQUE rows with the same value + if (is_string($columns)) { + $cols = explode(",", $columns); + } elseif (is_array($columns)) { + $cols = $columns; + } else { + $this->DBException(dgettext( + "domframework", + "Unique def is not a string or an array" + )); + } + foreach ($cols as $col) { + if (!key_exists($col, $setValues)) { + continue; + } + // One column to set is a unique column : check if the where clause + // is filtering more than one entry. If there is more than one + // entry, generate an exception + $this->debugLog("CLONE because of checking update unique fields", 2); + $objTmp = clone $this; + $objTmp->debugDepth++; + $objTmp->clearRequest(); + $objTmp->Select(); + $objTmp->displayAdd($this->primary); + $objTmp->displayAdd($columns); + $objTmp->whereValues = $this->whereValues; + $objTmp->whereExpression = $this->whereExpression; + $objTmp->limitLines(3); + $resUpdate = $objTmp->execute(); + unset($objTmp); + if (count($resUpdate) > 1) { + $this->DBException(sprintf( + dgettext( + "domframework", + "Can't update multiple rows with unique value on col '%s'" + ), + $col + )); + } elseif (count($resUpdate) === 1) { + $foundImpactedLines++; + } + } + if ($foundImpactedLines === 0) { + // There is no row available with the WHERE clause provided + // Skip all the UNIQUE tests as there will not have any modification + break; + } + } + if (! array_key_exists($this->primary, $setValues)) { + $setValues[$this->primary] = null; + } + + $this->debugLog("CLONE to check primary and unique constraint", 2); + $objTmp = clone $this; + $objTmp->debugDepth++; + $objTmp->clearRequest(); + $objTmp->Select(); + $objTmp->displayAdd($this->primary); + if (is_array($columns)) { + // Multiple columns in unique + $objTmp->debugLog( + " verify the unique multiple [", + implode(",", $columns), + "]", + 2 + ); + foreach ($columns as $column) { + if (! array_key_exists($column, $setValues)) { + if ($update !== false && array_key_exists(0, $resUpdate)) { + // In UPDATE, if a column is not modified (doesn't appears in + // setValues), use the old value to search + $valTest = $resUpdate[0][$column]; + $objTmp->whereAdd($column, "=", $valTest); + } else { + $errors[$column] = sprintf(dgettext( + "domframework", + "No column '%s' defined but must be unique !" + ), $column); + } + } else { + $objTmp->whereAdd($column, "=", $setValues[$column]); + } + } + } else { + // One column in unique + $objTmp->debugLog(" verify the unique one column [$columns]", 2); + if (! array_key_exists($columns, $setValues)) { + $errors[$columns] = sprintf(dgettext( + "domframework", + "No column '%s' defined but must be unique !" + ), $columns); + } else { + $objTmp->whereAdd($columns, "=", $setValues[$columns]); + } + } + if ($update && array_key_exists(0, $resUpdate)) { + // If the value already exists, check if it is the same (the SQL can + // overwrite with the same value) + // If it is not the same, produce an error + $objTmp->whereAdd( + $this->primary, + "!=", + $resUpdate[0][$this->primary] + ); + } + if (count($errors) == 0 && count($objTmp->execute())) { + if (is_array($columns)) { + foreach ($columns as $column) { + $errors[$column] = sprintf( + dgettext( + "domframework", + "An entry with this value '%s' already exists" + ), + mb_substr($setValues[$column], 0, 15) + ); + } + } else { + $errors[$columns] = sprintf( + dgettext( + "domframework", + "An entry with this value '%s' already exists" + ), + mb_substr($setValues[$columns], 0, 15) + ); + } + } + unset($objTmp); + } + + // - If foreign keys, check if the value is set in the constraint + foreach ($this->foreign as $fields => $params) { + foreach (explode(",", $fields) as $field) { + // Do not test in update if the field is not provided as it was already + // recorded + if ($update === true && ! array_key_exists($field, $values)) { + continue 2; + } + if ( + ! array_key_exists($field, $values) && + in_array("not null", $this->fields[$field]) + ) { + $errors[$field] = sprintf( + dgettext( + "domframework", + "The field '%s' must be test on foreign, but is not provided" + ), + $field + ); + continue; + } + if (! array_key_exists($params[0], $this->setForeignObj)) { + $this->DBException(sprintf(dgettext( + "domframework", + "No foreign object configured to test the foreign key for table " . + "'%s'" + ), $this->table)); + } + if ( + ! array_key_exists($field, $values) && + ! in_array("not null", $this->fields[$field]) + ) { + $values[$field] = null; + } + } + $this->debugLog("CLONE to check foreign constraint [$fields]", 2); + $objTmp = clone $this->setForeignObj[$params[0]]; + $objTmp->debug = $this->debug; + $objTmp->debugDepth++; + $objTmp->clearRequest(); + $objTmp->Select(); + $objTmp->displayAdd($objTmp->primary); + $parentField = explode(",", $params[1]); + $i = 0; + foreach (explode(",", $fields) as $key => $field) { + if (key_exists($field, $values) && $values[$field] !== null) { + $objTmp->whereAdd($parentField[$key], "=", $values[$field]); + $i++; + } + } + if ($i == 0) { + // If the foreign is null, do not test as there is no WHERE clause, and + // will return all the table + continue; + } + if (count($objTmp->execute()) === 0) { + $errors[$field] = sprintf( + dgettext( + "domframework", + "The value of the foreign key '%s' doesn't exists in foreign table" + ), + $field + ); + } + } + return $errors; + } + + /** Check the values before doing really the modification of the database + * @param array $values The values to test + * @param boolean|null $update if true UPDATE request, else INSERT request + */ + public function checkValues($values, $update = false) + { + $this->debugLog("Entering checkValues (", $update, ")", 2); + if (! is_array($values)) { + $this->DBException("checkValues fields : " . + "values provided are not an array", 406); + } + $values = $this->normalize($values); + $update = !! $update; + $errors = array_merge( + $this->verify($values, $update), + $this->checkRealTypes($values, $update) + ); + if (count($errors) === 0) { + $this->debugLog( + "End of checkValues (", + $update, + ") : Nothing in error", + 2 + ); + } else { + $this->debugLog("End of checkValues (", $update, ") : " . count($errors) . + "errors", 2); + } + return $errors; + } + + /** Check the types of the data against the realTypes + * Return an array with the field name in error and a message + * If allowEmpty is set, do not test the "NOT NULL" feature + * In UPDATE, the values don't need be not set : they are already in database + * so $allowEmpty is true + * @param array $values The values to test + * @param boolean|null $allowEmpty Allow the "not null" to not be set + * @return array empty array if no error + */ + public function checkRealTypes($values, $allowEmpty = false) + { + $this->debugLog( + "Entering checkRealTypes (", + $values, + ",", + $allowEmpty, + ")", + 2 + ); + if (! is_array($values)) { + $this->DBException( + "Invalid checkRealTypes provided : not an array", + 500 + ); + } + $values = $this->normalize($values); + $errors = array(); + foreach ($this->fields as $field => $params) { + if (! key_exists($field, $values) || trim($values[$field]) === "") { + if ( + in_array("not null", $params) && + ! in_array("autoincrement", $params) + ) { + if ($allowEmpty === false) { + $errors[$field] = dgettext( + "domframework", + "The field can not be empty" + ); + } + } else { + // Empty value is not tested and do not generate an error + } + } elseif (! is_string($values[$field])) { + $errors[$field] = dgettext( + "domframework", + "The value is not a string" + ); + } elseif (key_exists($field, $this->realTypes)) { + $val = trim($values[$field]); + @list($func, $param) = explode("(", $this->realTypes[$field]); + $func = trim($func); + $method = "checkRealType_" . $func; + $res = $this->$method($val, $this->realTypes[$field]); + if (is_string($res)) { + $errors[$field] = $res; + } + } + } + $this->debugLog( + "End checkRealTypes (", + $values, + ",", + $allowEmpty, + ") : ", + $errors, + 2 + ); + return $errors; + } + + /** Execute the pre-defined query + * Return the content array if SELECT command is choosed + * Return the Last ID if INSERT command is choosed + * Return the number of modified lines for UPDATE/DELETE command + */ + public function execute() + { + $this->debugLog("Entering execute ()", 2); + switch ($this->command) { + case "SELECT": + break; + case "INSERT": + $errors = $this->checkValues($this->setValues, false); + if (count($errors)) { + $val = reset($errors); + $this->DBException(key($errors) . " : $val", 406); + } + break; + case "UPDATE": + $errors = $this->checkValues($this->setValues, true); + if (count($errors)) { + $val = reset($errors); + $this->DBException(key($errors) . " : $val", 406); + } + break; + case "DELETE": + break; + default: + $this->DBException("execute : command not defined : no check"); + } + $this->debugLog("Entering createRequest ()", 2); + $sql = $this->createRequest(); + $this->debugLog("Entering prepareRequest (XXX, ", false, ")", 2); + $st = $this->prepareRequest($sql, false); + $this->debugLog("'", $this->getDisplayQuery(), "'", 1); + $startTime = microtime(true); + $st->execute(); + switch ($this->command) { + case "SELECT": + $result = $st->fetchAll(\PDO::FETCH_NUM); + // There is no fetchAll corresponding to the columnName->value. Assign the + // name to the value by index. + // FETCH_ASSOC doesn't work in empty left join (return NULL instead of + // the filled value) + $fieldsAll = $this->fieldsAll(true); + // If the displayed fields are all in the same table, remove the table + // name in the columns + $cleanable = true; + $cleanTable = ""; + foreach ($this->displayGet(true) as $display) { + preg_match_all( + "#" . $this->sep . "(.+)" . $this->sep . "\.#", + $display, + $matches + ); + if ($cleanTable === "") { + $cleanTable = $matches[1][0]; + } elseif ($cleanTable !== $matches[1][0]) { + $cleanable = false; + break; + } + } + $columns = array_values($this->displayGet(true)); + // Get the columns names that will be displayed to user. + // If the cleanable is possible, remove the table names + $columnNames = array_combine($columns, $columns); + //if ($this->joinObject === null && count ($this->displayGet (false))) + if ($cleanable) { + // Remove the table name as there is no collisions risk + // In case of Alias, remove the $this->sep too + foreach ($columnNames as $key => $col) { + // Remove the table and the separator if exists + $col = preg_replace("#" . $this->sep . "[^" . $this->sep . "]+" . + $this->sep . "\.#U", "", $col); + // Remove the separator if not table exists + $col = str_replace($this->sep, "", $col); + if ($col[0] === $this->sep) { + $col = substr($col, 1); + } elseif (strpos($col, "DISTINCT " . $this->sep) === 0) { + $col = "DISTINCT " . substr($col, 10); + } + if ( + substr($col, -1) === $this->sep && + strpos($col, " AS " . $this->sep) === false + ) { + $col = substr($col, 0, -1); + } + if (strpos($col, " AS " . $this->sep)) { + // remove the separator before the AS + $col = substr($col, 0, strpos($col, " AS " . $this->sep) - 1) . + substr($col, strpos($col, " AS " . $this->sep)); + } + $columnNames[$key] = $col; + } + } else { + foreach ($columnNames as $key => $col) { + $columnNames[$key] = str_replace($this->sep, "", $col); + } + } + foreach ($result as $rownb => $row) { + foreach ($row as $colNb => $val) { + // Harmonize the fetchAll result between all the databases drivers + $pos = strpos($columns[$colNb], "("); + if ($pos) { + // Function. The function that return an int must be added in this + // list, to cast correctely the value + $func = strtoupper(trim(substr($columns[$colNb], 0, $pos))); + if (in_array($func, array("AVG", "COUNT", "MAX", "MIN", "SUM"))) { + $val = intval($val); + } + } else { + $name = $columns[$colNb]; + $pos = strpos($columns[$colNb], " AS "); + if ($pos) { + $name = substr($columns[$colNb], 0, $pos); + } + $name = str_replace("DISTINCT ", "", $name); + /*if ($cleanable) + $name = str_replace ($this->sep.$this->tableprefix.$this->table. + $this->sep.".", "", $name);*/ + if ( + strtolower($fieldsAll[$name][0]) === "integer" && + $val !== null + ) { + $val = intval($val); + } + } + if (($pos = strpos($columns[$colNb], " AS " . $this->sep)) !== false) { + $pos += strlen(" AS " . $this->sep); + $colName = substr($columns[$colNb], $pos, -1); + } else { + $colName = $columnNames[$columns[$colNb]]; + } + $result[$rownb][$colName] = $val; + unset($result[$rownb][$colNb]); + } + } + self::$meta[] = array( + "command" => $this->command, + "sql" => $sql, + "sqltime" => microtime(true) - $startTime, + "displayQuery" => $this->getDisplayQuery(), + "nbrows" => count($result), + ); + return $result; + case "INSERT": + self::$meta[] = array( + "command" => $this->command, + "sql" => $sql, + "sqltime" => microtime(true) - $startTime, + "displayQuery" => $this->getDisplayQuery(), + "nbrows" => $st->rowCount(), + ); + // If the primary key is not autoincrement, return the provided value if + // exists + if ( + ! in_array("autoincrement", $this->fields[$this->primary]) && + key_exists($this->primary, $this->setValues) + ) { + return $this->setValues[$this->primary]; + } // If the primary key is autoincrement and the provided value is not null // Return it - if (in_array ("autoincrement", $this->fields[$this->primary]) && - key_exists ($this->primary, $this->setValues) && - $this->setValues[$this->primary] !== null) - return $this->setValues[$this->primary]; + if ( + in_array("autoincrement", $this->fields[$this->primary]) && + key_exists($this->primary, $this->setValues) && + $this->setValues[$this->primary] !== null + ) { + return $this->setValues[$this->primary]; + } // If the primary key is autoincrement and the provided value is null or // not provided, return the autoincremented value // PostGres need the name of the column autoincrement to return something - $autoInc = null; - if ($this->driver === "pgsql") - { - foreach ($this->fields as $col=>$params) - { - if (in_array ("autoincrement", $params)) - { - $autoInc = $col; - break; - } + $autoInc = null; + if ($this->driver === "pgsql") { + foreach ($this->fields as $col => $params) { + if (in_array("autoincrement", $params)) { + $autoInc = $col; + break; + } + } + if ($autoInc !== null) { + $autoInc = $this->table . "_${col}_seq"; + } + } + $this->debugLog( + "INSERT: lastInsertId=", + self::$instance[$this->dsn]->lastInsertId($autoInc), + 1 + ); + return self::$instance[$this->dsn]->lastInsertId($autoInc); + case "UPDATE": + case "DELETE": + self::$meta[] = array( + "command" => $this->command, + "sql" => $sql, + "sqltime" => microtime(true) - $startTime, + "displayQuery" => $this->getDisplayQuery(), + "nbrows" => $st->rowCount(), + ); + return $st->rowCount(); + default: + $this->DBException("execute : command not defined : no RC"); } - if ($autoInc !== null) - $autoInc = $this->table."_${col}_seq"; - } - $this->debugLog ("INSERT: lastInsertId=", - self::$instance[$this->dsn]->lastInsertId ($autoInc), 1); - return self::$instance[$this->dsn]->lastInsertId ($autoInc); - case "UPDATE": - case "DELETE": - self::$meta[] = array ( - "command" => $this->command, - "sql" => $sql, - "sqltime" => microtime (true) - $startTime, - "displayQuery" => $this->getDisplayQuery (), - "nbrows" => $st->rowCount (), - ); - return $st->rowCount (); - default: - $this->DBException ("execute : command not defined : no RC"); } - } - /** Execute a non prepared query in the database context. - * As there is no verification, this method is DANGEROUS and should not be - * used ! - * @param string $sql The SQL request to directely send to the database - * @return PDOStatement The PDO Statement to traverse - */ - public function directQuery ($sql) - { - if (! key_exists ($this->dsn, self::$instance)) - $this->DBException ("Direct query without established connection"); - return self::$instance[$this->dsn]->query ($sql, \PDO::FETCH_ASSOC); - } - - /** Error management - * @param string $message The message to throw in the exception - * @param integer|null $code The error code to return to the user - */ - public function DBException ($message, $code = 500) - { - $message = $this->DBExceptionMsg ($message); - throw new \Exception ($message, $code); - } - - /** Return the $message adapted with the debug trace if needed - * @param string $message The message to throw in the exception - */ - public function DBExceptionMsg ($message) - { - $backtrace = debug_backtrace (); - if ($this->debug) + /** Execute a non prepared query in the database context. + * As there is no verification, this method is DANGEROUS and should not be + * used ! + * @param string $sql The SQL request to directely send to the database + * @return PDOStatement The PDO Statement to traverse + */ + public function directQuery($sql) { - backtrace::show (debug_backtrace ()); + if (! key_exists($this->dsn, self::$instance)) { + $this->DBException("Direct query without established connection"); + } + return self::$instance[$this->dsn]->query($sql, \PDO::FETCH_ASSOC); } - if (! array_key_exists (1, $backtrace)) - unset ($backtrace); - else + + /** Error management + * @param string $message The message to throw in the exception + * @param integer|null $code The error code to return to the user + */ + public function DBException($message, $code = 500) { - $backtrace = end ($backtrace); - $filename = basename ($backtrace["file"]); - $line = $backtrace["line"]; - $method = $backtrace["function"]; - $message .= " ($filename:$line [$method])"; + $message = $this->DBExceptionMsg($message); + throw new \Exception($message, $code); } - return $message; - } - /** Debug function - * @param mixed ...$message The message to display in debug - * @param integer priority The display message if $priority <= $this->debug - */ - public function debugLog ($message, $priority) - { - if ((!!$this->debug) === false) - return; - $args = func_get_args(); - $priority = array_pop ($args); - if ($priority > $this->debug) - return; - echo str_repeat ("=", $this->debugDepth * 2)." "; - foreach ($args as $nb=>$arg) + /** Return the $message adapted with the debug trace if needed + * @param string $message The message to throw in the exception + */ + public function DBExceptionMsg($message) { - if (is_string ($arg) || is_int ($arg)) - echo $arg; - elseif (is_bool ($arg) && $arg === true) - echo "true"; - elseif (is_bool ($arg) && $arg === false) - echo "false"; - elseif (is_array ($arg)) - print_r ($arg); - elseif (is_null ($arg)) - echo "NULL"; - else - die ("DEBUG TYPE UNKNOWN ".gettype ($arg)."\n"); + $backtrace = debug_backtrace(); + if ($this->debug) { + backtrace::show(debug_backtrace()); + } + if (! array_key_exists(1, $backtrace)) { + unset($backtrace); + } else { + $backtrace = end($backtrace); + $filename = basename($backtrace["file"]); + $line = $backtrace["line"]; + $method = $backtrace["function"]; + $message .= " ($filename:$line [$method])"; + } + return $message; } - echo "\n"; - } - ////////////////////////////////////////////// - //// ALL THE CHECK REALTYPES METHODS //// - ////////////////////////////////////////////// - /** Check the type "integerPositive" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_integerPositive ($val, $definition) - { - if (substr ($val, 0, 1) === "-") - return dgettext ("domframework", "Invalid positive integer : ". - "can not start by minus sign"); - if (strspn ($val, "0123456789") !== strlen ($val)) - return dgettext ("domframework", "Invalid positive integer : ". - "invalid char"); - if (substr ($val, 0, 1) === "0" && $val !== "0") - return dgettext ("domframework", "Invalid positive integer : ". - "can not start by Zero"); - return; - } - - /** Check the type "integer" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_integer ($val, $definition) - { - if (strspn ($val, "0123456789-") !== strlen ($val)) - return dgettext ("domframework", "Invalid integer : ". - "invalid char"); - if (substr ($val, 0, 1) === "0" && $val !== "0") - return dgettext ("domframework", "Invalid integer : ". - "can not start by Zero"); - if (substr ($val, 0, 2) === "-0") - return dgettext ("domframework", "Invalid integer : ". - "can not start by Minus Zero"); - return; - } - - /** Check the type "allowedchars" - * the chars must be in UTF-8 - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_allowedchars ($val, $definition) - { - list ($func, $param) = explode ("(", $definition); - if ($param === null) - $this->DBException ("Invalid allowedchars definied : ". - "must have a starting parenthesis"); - if (substr ($param, -1) !== ")") - $this->DBException ("Invalid allowedchars definied : ". - "must have a ending parenthesis"); - $allowedChars = mb_substr ($param, 0, -1); - $allowedChars = preg_quote ($allowedChars, "#"); - preg_match ('#^['.$allowedChars.']+#u', $val, $matches); - if (isset ($matches[0]) && - mb_strlen ($matches[0]) === mb_strlen ($val)) - return; - return dgettext ("domframework", "Invalid char provided"); - } - - /** Check the type "array" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_array ($val, $definition) - { - list ($func, $param) = explode ("(", $definition); - if ($param === null) - $this->DBException ("Invalid array definied : ". - "must have a starting parenthesis"); - if (substr ($param, -1) !== ")") - $this->DBException ("Invalid array definied : ". - "must have a ending parenthesis"); - $param = mb_substr ($param, 0, -1); - $array = explode (",", $param); - foreach ($array as $key => $tmp) + /** Debug function + * @param mixed ...$message The message to display in debug + * @param integer priority The display message if $priority <= $this->debug + */ + public function debugLog($message, $priority) { - $array[$key] = mb_substr ($tmp, 1, -1); + if ((!!$this->debug) === false) { + return; + } + $args = func_get_args(); + $priority = array_pop($args); + if ($priority > $this->debug) { + return; + } + echo str_repeat("=", $this->debugDepth * 2) . " "; + foreach ($args as $nb => $arg) { + if (is_string($arg) || is_int($arg)) { + echo $arg; + } elseif (is_bool($arg) && $arg === true) { + echo "true"; + } elseif (is_bool($arg) && $arg === false) { + echo "false"; + } elseif (is_array($arg)) { + print_r($arg); + } elseif (is_null($arg)) { + echo "NULL"; + } else { + die("DEBUG TYPE UNKNOWN " . gettype($arg) . "\n"); + } + } + echo "\n"; } - if (in_array ($val, $array)) - return; - return dgettext ("domframework", "Invalid value provided : ". - "not in allowed list"); - } - /** Check the type "regex" - * Do not forget to add the separators, the ^ and $ - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_regex ($val, $definition) - { - list ($func, $param) = explode ("(", $definition); - if ($param === null) - $this->DBException ("Invalid regex definied : ". - "must have a starting parenthesis"); - if (substr ($param, -1) !== ")") - $this->DBException ("Invalid regex definied : ". - "must have a ending parenthesis"); - $param = mb_substr ($param, 0, -1); - if (@preg_match ($param, $val) === false) - $this->DBException ("Invalid regex definied : ". - "must have a ending parenthesis"); - if (preg_match ($param, $val)) - return; - return dgettext ("domframework", "Invalid value provided : ". - "do not match the regex"); - } + ////////////////////////////////////////////// + //// ALL THE CHECK REALTYPES METHODS //// + ////////////////////////////////////////////// + /** Check the type "integerPositive" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_integerPositive($val, $definition) + { + if (substr($val, 0, 1) === "-") { + return dgettext("domframework", "Invalid positive integer : " . + "can not start by minus sign"); + } + if (strspn($val, "0123456789") !== strlen($val)) { + return dgettext("domframework", "Invalid positive integer : " . + "invalid char"); + } + if (substr($val, 0, 1) === "0" && $val !== "0") { + return dgettext("domframework", "Invalid positive integer : " . + "can not start by Zero"); + } + return; + } - /** Check the type "mail" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_mail ($val, $definition) - { - if (!! filter_var ($val, FILTER_VALIDATE_EMAIL)) - return; - return dgettext ("domframework", "Invalid mail provided"); - } + /** Check the type "integer" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_integer($val, $definition) + { + if (strspn($val, "0123456789-") !== strlen($val)) { + return dgettext("domframework", "Invalid integer : " . + "invalid char"); + } + if (substr($val, 0, 1) === "0" && $val !== "0") { + return dgettext("domframework", "Invalid integer : " . + "can not start by Zero"); + } + if (substr($val, 0, 2) === "-0") { + return dgettext("domframework", "Invalid integer : " . + "can not start by Minus Zero"); + } + return; + } - /** Check the type "uuid" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_uuid ($val, $definition) - { - if (strlen ($val) !== 36) - return dgettext ("domframework", "Invalid UUID provided : ". - "invalid length"); - if (strspn ($val, "0123456789abcdefABCDEF-") !== strlen ($val)) - return dgettext ("domframework", "Invalid UUID provided : invalid char"); - if ($val[8] !== "-" || $val[13] !== "-" || $val[18] !== "-" || - $val[23] !== "-") - return dgettext ("domframework", "Invalid UUID provided : missing dash"); - } + /** Check the type "allowedchars" + * the chars must be in UTF-8 + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_allowedchars($val, $definition) + { + list($func, $param) = explode("(", $definition); + if ($param === null) { + $this->DBException("Invalid allowedchars definied : " . + "must have a starting parenthesis"); + } + if (substr($param, -1) !== ")") { + $this->DBException("Invalid allowedchars definied : " . + "must have a ending parenthesis"); + } + $allowedChars = mb_substr($param, 0, -1); + $allowedChars = preg_quote($allowedChars, "#"); + preg_match('#^[' . $allowedChars . ']+#u', $val, $matches); + if ( + isset($matches[0]) && + mb_strlen($matches[0]) === mb_strlen($val) + ) { + return; + } + return dgettext("domframework", "Invalid char provided"); + } - /** Check the type "sqldate" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_sqldate ($val, $definition) - { - if (strlen ($val) !== 10) - return dgettext ("domframework", "Invalid date provided : ". - "invalid length"); - if (strspn ($val, "0123456789-") !== strlen ($val)) - return dgettext ("domframework", "Invalid date provided : ". - "invalid chars"); - $arr = \date_parse ($val); - if ($arr["warning_count"] !== 0) - return dgettext ("domframework", "Invalid date provided : ". - "can not parse the date"); - if ($arr["error_count"] !== 0) - return dgettext ("domframework", "Invalid date provided : ". - "can not parse the date"); - if (isset ($arr["tz_abbr"])) - return dgettext ("domframework", "Invalid date provided : ". - "can not parse the date"); - if (\DateTime::createFromFormat("Y-m-d", $val) === false) - return dgettext ("domframework", "Invalid date provided : ". - "the date doesn't exists"); - } + /** Check the type "array" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_array($val, $definition) + { + list($func, $param) = explode("(", $definition); + if ($param === null) { + $this->DBException("Invalid array definied : " . + "must have a starting parenthesis"); + } + if (substr($param, -1) !== ")") { + $this->DBException("Invalid array definied : " . + "must have a ending parenthesis"); + } + $param = mb_substr($param, 0, -1); + $array = explode(",", $param); + foreach ($array as $key => $tmp) { + $array[$key] = mb_substr($tmp, 1, -1); + } + if (in_array($val, $array)) { + return; + } + return dgettext("domframework", "Invalid value provided : " . + "not in allowed list"); + } - /** Check the type "sqltime" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_sqltime ($val, $definition) - { - if (strlen ($val) !== 8) - return dgettext ("domframework", "Invalid time provided : ". - "invalid length"); - if (strspn ($val, "0123456789:") !== strlen ($val)) - return dgettext ("domframework", "Invalid time provided : ". - "invalid chars"); - $arr = \date_parse ($val); - if ($arr["warning_count"] !== 0) - return dgettext ("domframework", "Invalid time provided : ". - "can not parse the time"); - if ($arr["error_count"] !== 0) - return dgettext ("domframework", "Invalid time provided : ". - "can not parse the time"); - if (isset ($arr["tz_abbr"])) - return dgettext ("domframework", "Invalid time provided : ". - "can not parse the date"); - if (\DateTime::createFromFormat("H:i:s", $val) === false) - return dgettext ("domframework", "Invalid time provided : ". - "the time doesn't exists"); - } + /** Check the type "regex" + * Do not forget to add the separators, the ^ and $ + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_regex($val, $definition) + { + list($func, $param) = explode("(", $definition); + if ($param === null) { + $this->DBException("Invalid regex definied : " . + "must have a starting parenthesis"); + } + if (substr($param, -1) !== ")") { + $this->DBException("Invalid regex definied : " . + "must have a ending parenthesis"); + } + $param = mb_substr($param, 0, -1); + if (@preg_match($param, $val) === false) { + $this->DBException("Invalid regex definied : " . + "must have a ending parenthesis"); + } + if (preg_match($param, $val)) { + return; + } + return dgettext("domframework", "Invalid value provided : " . + "do not match the regex"); + } - /** Check the type "sqldatetime" - * @param string $val The value to check - * @param string $definition The definition of the type - * @return string or null - */ - private function checkRealType_sqldatetime ($val, $definition) - { - if (strlen ($val) !== 19) - return dgettext ("domframework", "Invalid date and time provided : ". - "invalid length"); - if (strspn ($val, "0123456789 :-") !== strlen ($val)) - return dgettext ("domframework", "Invalid date and time provided : ". - "invalid chars"); - $arr = \date_parse ($val); - if ($arr["warning_count"] !== 0) - return dgettext ("domframework", "Invalid date and time provided : ". - "can not parse the date"); - if ($arr["error_count"] !== 0) - return dgettext ("domframework", "Invalid date and time provided : ". - "can not parse the date"); - if (isset ($arr["tz_abbr"])) - return dgettext ("domframework", "Invalid date and time provided : ". - "can not parse the date"); - if (\DateTime::createFromFormat("Y-m-d H:i:s", $val) === false) - return dgettext ("domframework", "Invalid date and time provided : ". - "the date doesn't exists"); - } + /** Check the type "mail" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_mail($val, $definition) + { + if (!! filter_var($val, FILTER_VALIDATE_EMAIL)) { + return; + } + return dgettext("domframework", "Invalid mail provided"); + } + + /** Check the type "uuid" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_uuid($val, $definition) + { + if (strlen($val) !== 36) { + return dgettext("domframework", "Invalid UUID provided : " . + "invalid length"); + } + if (strspn($val, "0123456789abcdefABCDEF-") !== strlen($val)) { + return dgettext("domframework", "Invalid UUID provided : invalid char"); + } + if ( + $val[8] !== "-" || $val[13] !== "-" || $val[18] !== "-" || + $val[23] !== "-" + ) { + return dgettext("domframework", "Invalid UUID provided : missing dash"); + } + } + + /** Check the type "sqldate" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqldate($val, $definition) + { + if (strlen($val) !== 10) { + return dgettext("domframework", "Invalid date provided : " . + "invalid length"); + } + if (strspn($val, "0123456789-") !== strlen($val)) { + return dgettext("domframework", "Invalid date provided : " . + "invalid chars"); + } + $arr = \date_parse($val); + if ($arr["warning_count"] !== 0) { + return dgettext("domframework", "Invalid date provided : " . + "can not parse the date"); + } + if ($arr["error_count"] !== 0) { + return dgettext("domframework", "Invalid date provided : " . + "can not parse the date"); + } + if (isset($arr["tz_abbr"])) { + return dgettext("domframework", "Invalid date provided : " . + "can not parse the date"); + } + if (\DateTime::createFromFormat("Y-m-d", $val) === false) { + return dgettext("domframework", "Invalid date provided : " . + "the date doesn't exists"); + } + } + + /** Check the type "sqltime" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqltime($val, $definition) + { + if (strlen($val) !== 8) { + return dgettext("domframework", "Invalid time provided : " . + "invalid length"); + } + if (strspn($val, "0123456789:") !== strlen($val)) { + return dgettext("domframework", "Invalid time provided : " . + "invalid chars"); + } + $arr = \date_parse($val); + if ($arr["warning_count"] !== 0) { + return dgettext("domframework", "Invalid time provided : " . + "can not parse the time"); + } + if ($arr["error_count"] !== 0) { + return dgettext("domframework", "Invalid time provided : " . + "can not parse the time"); + } + if (isset($arr["tz_abbr"])) { + return dgettext("domframework", "Invalid time provided : " . + "can not parse the date"); + } + if (\DateTime::createFromFormat("H:i:s", $val) === false) { + return dgettext("domframework", "Invalid time provided : " . + "the time doesn't exists"); + } + } + + /** Check the type "sqldatetime" + * @param string $val The value to check + * @param string $definition The definition of the type + * @return string or null + */ + private function checkRealType_sqldatetime($val, $definition) + { + if (strlen($val) !== 19) { + return dgettext("domframework", "Invalid date and time provided : " . + "invalid length"); + } + if (strspn($val, "0123456789 :-") !== strlen($val)) { + return dgettext("domframework", "Invalid date and time provided : " . + "invalid chars"); + } + $arr = \date_parse($val); + if ($arr["warning_count"] !== 0) { + return dgettext("domframework", "Invalid date and time provided : " . + "can not parse the date"); + } + if ($arr["error_count"] !== 0) { + return dgettext("domframework", "Invalid date and time provided : " . + "can not parse the date"); + } + if (isset($arr["tz_abbr"])) { + return dgettext("domframework", "Invalid date and time provided : " . + "can not parse the date"); + } + if (\DateTime::createFromFormat("Y-m-d H:i:s", $val) === false) { + return dgettext("domframework", "Invalid date and time provided : " . + "the date doesn't exists"); + } + } } diff --git a/src/Encrypt.php b/src/Encrypt.php index cd0be21..0bd34d4 100644 --- a/src/Encrypt.php +++ b/src/Encrypt.php @@ -1,4 +1,5 @@ @@ -11,84 +12,125 @@ namespace Domframework; */ class Encrypt { - /** Check if openssl library is enabled - */ - public function __construct () - { - if (! function_exists ("openssl_random_pseudo_bytes")) - throw new \Exception ("No OpenSSL support in PHP. Please install it", - 500); - } + /** Check if openssl library is enabled + */ + public function __construct() + { + if (! function_exists("openssl_random_pseudo_bytes")) { + throw new \Exception( + "No OpenSSL support in PHP. Please install it", + 500 + ); + } + } - /** Encrypt the payload to not be readable by anybody - * @param string $payload The payload to encrypt - * @param string $ckey The 24 chars for the cipher key - * @param string|null $cipherMethod DES-EDE3-CBC by default - * @return encrypted payload - */ - public function encrypt ($payload, $ckey, $cipherMethod = "des-ede3-cbc") - { - if (! in_array ($cipherMethod, openssl_get_cipher_methods())) - throw new \Exception (dgettext ("domframework", - "Invalid cipher provided to encrypt method : ". - "doesn't exists in OpenSSL"), 500); - if (! is_string ($payload)) - throw new \Exception (dgettext ("domframework", - "Invalid payload provided to encrypt method : ". - "Not a string"), 500); - if (strlen ($ckey) !== 24) - throw new \Exception (dgettext ("domframework", - "Invalid cipherKey provided to encrypt method :" . - " length different of 24 chars"), 500); - // Must be the same as decrypt - $options = true; - $ivlen = openssl_cipher_iv_length ($cipherMethod); - $iv = openssl_random_pseudo_bytes ($ivlen); - $ciphertext = openssl_encrypt ($payload, $cipherMethod, $ckey, $options, - $iv); - if ($ciphertext === false) - throw new \Exception (dgettext ("domframework", - "Can not encrypt the payload"), 500); - $ciphertext = $iv . $ciphertext; - return $ciphertext; - } + /** Encrypt the payload to not be readable by anybody + * @param string $payload The payload to encrypt + * @param string $ckey The 24 chars for the cipher key + * @param string|null $cipherMethod DES-EDE3-CBC by default + * @return encrypted payload + */ + public function encrypt($payload, $ckey, $cipherMethod = "des-ede3-cbc") + { + if (! in_array($cipherMethod, openssl_get_cipher_methods())) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipher provided to encrypt method : " . + "doesn't exists in OpenSSL" + ), 500); + } + if (! is_string($payload)) { + throw new \Exception(dgettext( + "domframework", + "Invalid payload provided to encrypt method : " . + "Not a string" + ), 500); + } + if (strlen($ckey) !== 24) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipherKey provided to encrypt method :" . + " length different of 24 chars" + ), 500); + } + // Must be the same as decrypt + $options = true; + $ivlen = openssl_cipher_iv_length($cipherMethod); + $iv = openssl_random_pseudo_bytes($ivlen); + $ciphertext = openssl_encrypt( + $payload, + $cipherMethod, + $ckey, + $options, + $iv + ); + if ($ciphertext === false) { + throw new \Exception(dgettext( + "domframework", + "Can not encrypt the payload" + ), 500); + } + $ciphertext = $iv . $ciphertext; + return $ciphertext; + } - /** Decrypt the ciphertext - * @param string $ciphertext The payload to decrypt - * @param string $ckey The 24 chars for the cipher key - * @param string|null $cipherMethod DES-EDE3-CBC by default - * @return decrypted text - */ - public function decrypt ($ciphertext, $ckey, $cipherMethod = "des-ede3-cbc") - { - if (! is_string ($ciphertext)) - throw new \Exception (dgettext ("domframework", - "Invalid ciphertext provided to decrypt method : not a string"), 500); - if (! is_string ($ckey)) - throw new \Exception (dgettext ("domframework", - "Invalid cipherkey provided to decrypt method : not a string"), 500); - if (! is_string ($cipherMethod)) - throw new \Exception (dgettext ("domframework", - "Invalid cipherMethod provided to decrypt method : not a string"), 500); - if (trim ($ciphertext) === "") - throw new \Exception (dgettext ("domframework", - "Invalid ciphertext provided to decrypt method : empty string"), 500); - if (! in_array ($cipherMethod, openssl_get_cipher_methods())) - throw new \Exception (dgettext ("domframework", - "Invalid cipherMethod provided to decrypt method : ". - "doesn't exists in OpenSSL"), 500); - if (strlen ($ckey) !== 24) - throw new \Exception (dgettext ("domframework", - "Invalid cipherKey provided to decrypt method :" . - " length different of 24 chars"), 500); - $ivlen = openssl_cipher_iv_length ($cipherMethod); - $iv = substr ($ciphertext, 0, $ivlen); - if (strlen ($iv) != $ivlen) - throw new \Exception (dgettext ("domframework", - "Can not decrypt the payload : invalid salt"), 500); - // Must be the same as encrypt - $options = true; - $ciphertext = substr ($ciphertext, $ivlen); - return openssl_decrypt ($ciphertext, $cipherMethod, $ckey, $options, $iv); - } + /** Decrypt the ciphertext + * @param string $ciphertext The payload to decrypt + * @param string $ckey The 24 chars for the cipher key + * @param string|null $cipherMethod DES-EDE3-CBC by default + * @return decrypted text + */ + public function decrypt($ciphertext, $ckey, $cipherMethod = "des-ede3-cbc") + { + if (! is_string($ciphertext)) { + throw new \Exception(dgettext( + "domframework", + "Invalid ciphertext provided to decrypt method : not a string" + ), 500); + } + if (! is_string($ckey)) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipherkey provided to decrypt method : not a string" + ), 500); + } + if (! is_string($cipherMethod)) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipherMethod provided to decrypt method : not a string" + ), 500); + } + if (trim($ciphertext) === "") { + throw new \Exception(dgettext( + "domframework", + "Invalid ciphertext provided to decrypt method : empty string" + ), 500); + } + if (! in_array($cipherMethod, openssl_get_cipher_methods())) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipherMethod provided to decrypt method : " . + "doesn't exists in OpenSSL" + ), 500); + } + if (strlen($ckey) !== 24) { + throw new \Exception(dgettext( + "domframework", + "Invalid cipherKey provided to decrypt method :" . + " length different of 24 chars" + ), 500); + } + $ivlen = openssl_cipher_iv_length($cipherMethod); + $iv = substr($ciphertext, 0, $ivlen); + if (strlen($iv) != $ivlen) { + throw new \Exception(dgettext( + "domframework", + "Can not decrypt the payload : invalid salt" + ), 500); + } + // Must be the same as encrypt + $options = true; + $ciphertext = substr($ciphertext, $ivlen); + return openssl_decrypt($ciphertext, $cipherMethod, $ckey, $options, $iv); + } } diff --git a/src/File.php b/src/File.php index 2afa9a5..ffa245c 100644 --- a/src/File.php +++ b/src/File.php @@ -1,4 +1,5 @@ @@ -17,916 +18,1071 @@ namespace Domframework; */ class File { - /** The virtual current working directory */ - private $cwd = "."; - /** The real directory used as root in virtual chroot */ - private $baseDir = "/"; + /** The virtual current working directory */ + private $cwd = "."; + /** The real directory used as root in virtual chroot */ + private $baseDir = "/"; - /** The lock stack */ - private $locks = array (); + /** The lock stack */ + private $locks = array(); - /** Activate the debug and define the minimum priority to save */ - public $debug = 0; + /** Activate the debug and define the minimum priority to save */ + public $debug = 0; - /** Change the current working directory - * @param string $directory Go in the provided directory - * @return bool true if the directory is changed - * @throws If directory not exists, or the directory is not executable - */ - public function chdir ($directory) - { - $this->debug (2, "chdir ($directory)"); - $tmpdirectory = $this->realpath ($directory); - $this->checkPathRO ($tmpdirectory); - if ($this->baseDir === "/") - $this->cwd = $tmpdirectory; - else - $this->cwd = substr ($tmpdirectory, strlen ($this->baseDir)); - $this->debug (1, "chdir $directory -> $this->cwd"); - return true; - } - - /** Change the group for a file/dir... - * @param string $filename The file/directory to change - * @param mixed $group The group name or group GID - * @throws If filename not exists, or the directory is not RW - */ - public function chgrp ($filename, $group) - { - $this->debug (2, "chgrp ($filename, $group)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod doesn't exists"), - $filename), 404); - if (! is_writeable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod is not writeable"), - $filename), 500); - $rc = chgrp ($filename, $group); - $this->debug (1, "chgrp ($filename, $group) => $rc"); - return $rc; - } - - /** Change the rights mode for a file/dir... - * @param string $filename The file/directory to change - * @param integer $mode The mode to use for the filename - * @throws If filename not exists, or the directory is not RW - */ - public function chmod ($filename, $mode) - { - $this->debug (2, "chmod ($filename, $mode)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod doesn't exists"), - $filename), 404); - if (! is_writeable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod is not writeable"), - $filename), 500); - $rc = chmod ($filename, $mode); - $this->debug (1, "chmod ($filename, $mode) => $rc"); - return $rc; - } - - /** Change the owner for a file/dir... - * @param string $filename The file/directory to change - * @param mixed $user The user name or user UID - * @throws If filename not exists, or the directory is not RW - */ - public function chown ($filename, $user) - { - $this->debug (2, "chown ($filename, $user)"); - if (posix_getuid () !== 0 && - posix_getuid () !== $user && - posix_getpwuid (posix_getuid()) !== $user) - throw new \Exception (sprintf (dgettext ("domframework", - "Only root user can change the file owner for '%s'"), - $filename), 500); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod doesn't exists"), - $filename), 404); - if (! is_writeable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' to chmod is not writeable"), - $filename), 500); - $rc = chown ($filename, $user); - $this->debug (1, "chown ($filename, $user) => $rc"); - return $rc; - } - - /** Chroot in the provided directory - * @param string $directory The directory to chroot - * @return boolean true if the chroot is done, false if there is a failure - * @throws If directory not exists, or the directory is not executable - */ - public function chroot ($directory) - { - // Use the checkPathRO (using the $this->baseDir) to not allow to go away of - // the chroot. - $this->debug (2, "chroot ($directory)"); - $directory = $this->realpath ($directory); - $this->checkPathRO ($directory); - $this->baseDir = preg_replace ("#//+#", "/", $directory); - $this->cwd = "/"; - $this->debug (1, "chroot $directory -> $this->baseDir"); - return true; - } - - /** Get the file contents in an array (like 'file' function, but can not - * have the same name as the class...) - * @param string $filename Name of the file to read - * @return string Content of the file - * @throws If parent directory not exists, is not readable, the file is not - * exists or is not readable - */ - public function fileArray ($filename) - { - $this->debug (2, "file ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable"), - $filename), 500); - $contents = file ($filename); - $this->debug (1, "file ($filename) => ". count ($contents). " rows"); - return $contents; - } - - /** Checks whether a file or directory exists - * @param string $filename The file or directory to verify - * @return bool true if the file exists, false otherwise - * @throws If parent directory not exists, or is not executable - */ - public function file_exists ($filename) - { - $this->debug (2, "file_exists ($filename)"); - $filename = $this->realpath ($filename); - try + /** Change the current working directory + * @param string $directory Go in the provided directory + * @return bool true if the directory is changed + * @throws If directory not exists, or the directory is not executable + */ + public function chdir($directory) { - $this->checkPathRO (dirname ($filename)); - } - catch (\Exception $e) - { - if ($e->getCode () !== 404) - throw new \Exception ($e->getMessage (), $e->getCode ()); - } - if (file_exists ($filename) && ! is_link ($filename)) - return true; - return false; - } - - /** Get the file contents - * @param string $filename Name of the file to read - * @return string Content of the file - * @throws If parent directory not exists, is not readable, the file is not - * exists or is not readable - */ - public function file_get_contents ($filename) - { - $this->debug (2, "file_get_contents ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable"), - $filename), 500); - $contents = file_get_contents ($filename); - $this->debug (1, "file_get_contents ($filename) => ".strlen ($contents). - " bytes"); - return $contents; - } - - /** Write a string to a file - * @param string $filename Path to the file where to write the data - * @param string|integer $data The data to write - * @param integer|null $flags The optional flags - * @return integer the length of the data stored - * @throws If parent directory not exists, is not writeable, or the file - * exists and is not writeable - */ - public function file_put_contents ($filename, $data, $flags=0) - { - $this->debug (2, "file_put_contents ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (file_exists ($filename) && ! is_writeable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not writeable"), - $filename), 500); - if (file_exists ($filename) && ! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - $contents = file_put_contents ($filename, $data, $flags); - $this->debug (1, "file_put_contents ($filename, \$data) => ". - "$contents bytes"); - return $contents; - - } - - /** Get the file modification time of a file - * @param string $filename Path to the file - * @return integer|boolean the time the file was last modified, or FALSE - * on failure. The time is returned as a Unix timestamp, which is suitable - * for the date() function. - * @throws If parent directory not exists, is not writeable - */ - public function filemtime ($filename) - { - $this->debug (2, "filemtime ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - return filemtime ($filename); - } - - /** Get the file size - * @param string $filename Path to the file - * @return integer|boolean the size of the file or FALSE on failure. - * @throws If parent directory not exists, is not writeable - */ - public function filesize ($filename) - { - $this->debug (2, "filesize ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - return filesize ($filename); - } - - /** Get the file info of the provided filename - * @param string $filename Path to the file - * @return string the mimetype of the file - * @throws If parent directory not exists, is not writeable - */ - public function fileinfoMimeType ($filename) - { - $this->debug (2, "filesize ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - $finfo = new \finfo (FILEINFO_MIME_TYPE); - return $finfo->file ($filename); - } - - /** Return the current working directory - * @return string the current working directory */ - public function getcwd () - { - $this->debug (1, "getcwd $this->cwd"); - return $this->cwd; - } - - /** Find pathnames matching a pattern - * If there is some unreadable files, skip them quietly - * @param string $pattern The pattern to found - * @param integer|null $flags The additional flags - * @return array Return an array if there is an error - * @throws If parent directory not exists, or is not executable - * or if there is one file unreadable - */ - public function glob ($pattern, $flags=0) - { - $this->debug (2, "glob ($pattern, $flags)"); - $this->checkPathRO ($this->baseDir); - if (substr ($pattern, 0, 1) === "/") - $relative = 0; - else - $relative = 1; - $pattern = $this->realpath ($pattern); - $files = glob ($pattern, $flags); - if ($files === false) - // FIXME : In the exception : how found the file which is not readable ? - throw new \Exception ("Glob : can't read some files", 500); - foreach ($files as &$file) - { - if (strlen ($this->baseDir) > 1) - { - if ($relative == 1) - $file = substr ($file, strlen ($this->baseDir)+strlen ($this->cwd)+1); - else - $file = substr ($file, strlen ($this->baseDir)); - } - else - { - if ($relative == 1) - $file = substr ($file, strlen ($this->cwd)+1); - } - } - return $files; - } - - /** Tells whether the given filename is a directory - * @param string $filename The filename to test - * @return bool true if the $filename is a directory and exists, false - * otherwise - * @throws If parent directory not exists, or is not executable - */ - public function is_dir ($filename) - { - $this->debug (2, "is_dir ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (file_exists ($filename) && is_dir ($filename)) - return true; - return false; - } - - /** Tells whether the given filename is a valid file - * @param string $filename The filename to test - * @return bool true if the $filename is a file and exists, false otherwise - * @throws If parent directory not exists, or is not executable - */ - public function is_file ($filename) - { - $this->debug (2, "is_file ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (file_exists ($filename) && is_file ($filename)) - return true; - return false; - } - - /** Tells whether a file exists and is executable - * @param string $filename The filename to test - * @return bool true if the $filename is a file exists and is writeable - * @throws If parent directory not exists, or is not executable - */ - public function is_executable ($filename) - { - $this->debug (2, "is_executable ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (file_exists ($filename) && is_executable ($filename)) - return true; - return false; - } - - /** Tells whether a file exists and is readable - * @param string $filename The filename to test - * @return bool true if the $filename is a file exists and is readable - * @throws If parent directory not exists, or is not executable - */ - public function is_readable ($filename) - { - $this->debug (2, "is_readable ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (file_exists ($filename) && is_readable ($filename)) - return true; - return false; - } - - /** Tells whether a file exists and is writeable - * @param string $filename The filename to test - * @return bool true if the $filename is a file exists and is writeable - * @throws If parent directory not exists, or is not executable - */ - public function is_writeable ($filename) - { - $this->debug (2, "is_writeable ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (file_exists ($filename) && is_writeable ($filename)) - return true; - return false; - } - - /** Lock a file exclusively - * @param string $filename The file to lock - * @return bool true if the lock is acquired, false otherwise - * @throws If parent directory not exists, or is not writeable - */ - public function lockEX ($filename) - { - $this->debug (2, "lockEX ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' doesn't exists : could not be locked"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable : could not be locked"), - $filename), 500); - $this->locks[$filename] = fopen ($filename, "rt"); - return flock ($this->locks[$filename], LOCK_EX); - } - - /** Lock a file shared (allow multiple read) - * @param string $filename The file to lock - * @return bool true if the lock is acquired, false otherwise - * @throws If parent directory not exists, or is not writeable - */ - public function lockSH ($filename) - { - $this->debug (2, "lockSH ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' doesn't exists : could not be locked"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable : could not be locked"), - $filename), 500); - $this->locks[$filename] = fopen ($filename, "rt"); - return flock ($this->locks[$filename], LOCK_SH); - } - - /** Unlock a file previously locked - * @param string $filename The file to lock - * @return bool true if the lock is acquired, false otherwise - * @throws If parent directory not exists, or is not writeable - */ - public function lockUN ($filename) - { - $this->debug (2, "lockUN ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - $res = true; - if (isset ($this->locks[$filename])) - { - $res = flock ($this->locks[$filename], LOCK_UN); - fclose ($this->locks[$filename]); - unset($this->locks[$filename]); - } - return $res; - } - - /** Calculate the md5 sum of a file - * @param string $filename The file to hash - * @return string the calulated hash - * @throws If the file doesn't exists - */ - public function md5_file ($filename) - { - $this->debug (2, "md5_file ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable"), - $filename), 500); - return md5_file ($filename); - } - - /** Create a new directory - * @param string $pathname The directory to create - * @param integer $mode The mode to create (0777 by default) - * @param boolean $recursive (false by default) - * @return bool true if the directory is correctely created, false if the - * directory already exists - * @throws If parent directory not exists, is not writeable - */ - public function mkdir ($pathname, $mode = 0777, $recursive = false) - { - $this->debug (2, "mkdir ($pathname, $mode, $recursive)"); - $pathname = $this->realpath ($pathname); - if ($recursive) - { - $parents = explode ("/", $pathname); - array_pop ($parents); - $parent = ""; - foreach ($parents as $p) - { - $parent = $parent.$p."/"; - if (! file_exists ($parent)) - { - if (is_writeable (dirname ($parent))) - break; - throw new \Exception (sprintf ("Last Directory '%s' is readonly", - dirname ($parent)), 500); + $this->debug(2, "chdir ($directory)"); + $tmpdirectory = $this->realpath($directory); + $this->checkPathRO($tmpdirectory); + if ($this->baseDir === "/") { + $this->cwd = $tmpdirectory; + } else { + $this->cwd = substr($tmpdirectory, strlen($this->baseDir)); } - } - if ($parent === dirname ($pathname) && ! is_writeable (dirname ($parent))) - { - throw new \Exception (sprintf ("Parent directory '%s' is readonly", - dirname ($parent)), 500); - } + $this->debug(1, "chdir $directory -> $this->cwd"); + return true; } - else + + /** Change the group for a file/dir... + * @param string $filename The file/directory to change + * @param mixed $group The group name or group GID + * @throws If filename not exists, or the directory is not RW + */ + public function chgrp($filename, $group) { - $this->checkPathRW (dirname ($pathname)); + $this->debug(2, "chgrp ($filename, $group)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod doesn't exists" + ), + $filename + ), 404); + } + if (! is_writeable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod is not writeable" + ), + $filename + ), 500); + } + $rc = chgrp($filename, $group); + $this->debug(1, "chgrp ($filename, $group) => $rc"); + return $rc; } - if (file_exists ($pathname)) - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' already exists"), - $pathname), 500); - $rc = mkdir ($pathname, $mode, $recursive); - $this->debug (1, "mkdir ($pathname, $mode, $recursive) => $rc"); - return $rc; - } - /** Copy a file or a directory - * @param string $oldname The file to copy - * @param string $newname The new name of the file. It will be - * overwrited if it already exists - * @return bool - */ - public function copy ($oldname, $newname) - { - $this->debug (2, "copy ($oldname, $newname)"); - $oldname = $this->realpath ($oldname); - $newname = $this->realpath ($newname); - $this->checkPathRO (dirname ($oldname)); - $this->checkPathRW (dirname ($newname)); - if (is_dir ($oldname)) + /** Change the rights mode for a file/dir... + * @param string $filename The file/directory to change + * @param integer $mode The mode to use for the filename + * @throws If filename not exists, or the directory is not RW + */ + public function chmod($filename, $mode) { - // Copy directory structure - if (! $this->file_exists ($newname)) - $this->mkdir ($newname); - $files = $this->scandirNotSorted ($oldname); - foreach ($files as $file) - $this->copy ("$oldname/$file", "$newname/$file"); + $this->debug(2, "chmod ($filename, $mode)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod doesn't exists" + ), + $filename + ), 404); + } + if (! is_writeable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod is not writeable" + ), + $filename + ), 500); + } + $rc = chmod($filename, $mode); + $this->debug(1, "chmod ($filename, $mode) => $rc"); + return $rc; } - else + + /** Change the owner for a file/dir... + * @param string $filename The file/directory to change + * @param mixed $user The user name or user UID + * @throws If filename not exists, or the directory is not RW + */ + public function chown($filename, $user) { - $rc = copy ($oldname, $newname); + $this->debug(2, "chown ($filename, $user)"); + if ( + posix_getuid() !== 0 && + posix_getuid() !== $user && + posix_getpwuid(posix_getuid()) !== $user + ) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Only root user can change the file owner for '%s'" + ), + $filename + ), 500); + } + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod doesn't exists" + ), + $filename + ), 404); + } + if (! is_writeable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' to chmod is not writeable" + ), + $filename + ), 500); + } + $rc = chown($filename, $user); + $this->debug(1, "chown ($filename, $user) => $rc"); + return $rc; } - $this->debug (1, "copy ($oldname, $newname) => $rc"); - return $rc; - } - /** Renames a file or directory - * @param string $oldname The file or directory to rename - * @param string $newname The new name of the file or directory. It will be - * overwrited if it already exists - * @return bool - */ - public function rename ($oldname, $newname) - { - $this->debug (2, "rename ($oldname, $newname)"); - $oldname = $this->realpath ($oldname); - $newname = $this->realpath ($newname); - $this->checkPathRO (dirname ($oldname)); - $this->checkPathRW (dirname ($newname)); - $rc = rename ($oldname, $newname); - $this->debug (1, "rename ($oldname, $newname) => $rc"); - return $rc; - } - - /** Return a ini file converted to an array - * @param string $filename The filename of the ini file being parsed. - * @param boolean $process_sections Process the sections - * @return array - */ - public function parse_ini_file ($filename, $process_sections = false) - { - $this->debug (2, "parse_ini_file ($filename, $process_sections)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable"), - $filename), 500); - return parse_ini_file ($filename, $process_sections); - } - - /** Return the canonical absolute path. Do not check if the directory exists, - * if there is links. Just calculate the realpath based on the chroot value - * @param string $path the path to analyze - * @return string the canonical absolute path - */ - public function realpath ($path) - { - $oriPath = $path; - $this->debug (2, "realpath ($oriPath)"); - $path = preg_replace ("#//+#", "/", $path); - if (substr ($path, -1) === "/") - $path = substr ($path, 0, -1); - $parts = explode ("/", $path); - $current = $this->cwd; - $tmp = explode ("/", $current); - foreach ($parts as $part) + /** Chroot in the provided directory + * @param string $directory The directory to chroot + * @return boolean true if the chroot is done, false if there is a failure + * @throws If directory not exists, or the directory is not executable + */ + public function chroot($directory) { - if ($part === "") - $tmp = array(); - elseif ($part === ".") - continue; - elseif ($part === "..") - { - array_pop ($tmp); - continue; - } - else - array_push ($tmp, $part); + // Use the checkPathRO (using the $this->baseDir) to not allow to go away of + // the chroot. + $this->debug(2, "chroot ($directory)"); + $directory = $this->realpath($directory); + $this->checkPathRO($directory); + $this->baseDir = preg_replace("#//+#", "/", $directory); + $this->cwd = "/"; + $this->debug(1, "chroot $directory -> $this->baseDir"); + return true; } - if (reset ($tmp) === ".") + + /** Get the file contents in an array (like 'file' function, but can not + * have the same name as the class...) + * @param string $filename Name of the file to read + * @return string Content of the file + * @throws If parent directory not exists, is not readable, the file is not + * exists or is not readable + */ + public function fileArray($filename) { - array_shift ($tmp); - $path = $current."/".implode ("/", $tmp); + $this->debug(2, "file ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable" + ), + $filename + ), 500); + } + $contents = file($filename); + $this->debug(1, "file ($filename) => " . count($contents) . " rows"); + return $contents; } - else - $path = "/".implode ("/", $tmp); - if ($this->baseDir !== "/") - $path = $this->baseDir.$path; - $path = preg_replace ("#//+#", "/", $path); - if ($path !== "/" && substr ($path, -1) === "/") - $path = substr ($path, 0, -1); - $this->debug (1, "realpath ($oriPath) => $path"); - return $path; - } - /** Remove the provided directory - * If the recurse flag is true, remove the content too (files and - * directories) - * @param string $dirname The directory to remove - * @param boolean $recursive Remove recursively - * @return bool true if all is removed, false otherwise - * @throws If parent directory not exists, is not writeable or the current - * dir is not writeable - */ - public function rmdir ($dirname, $recursive=false) - { - $this->debug (2, "rmdir ($dirname, $recursive)"); - $tmpdirname = $this->realpath ($dirname); - $this->checkPathRW (dirname ($tmpdirname)); - $this->checkPathRW ($tmpdirname); - if ($recursive === false) - return @rmdir ($tmpdirname); - $files = array_diff (scandir ($tmpdirname), array(".", "..")); - foreach ($files as $file) + /** Checks whether a file or directory exists + * @param string $filename The file or directory to verify + * @return bool true if the file exists, false otherwise + * @throws If parent directory not exists, or is not executable + */ + public function file_exists($filename) { - if (is_dir ("$tmpdirname/$file")) - { - $this->rmdir("$dirname/$file", $recursive); - } - else - { - unlink ("$tmpdirname/$file"); - } + $this->debug(2, "file_exists ($filename)"); + $filename = $this->realpath($filename); + try { + $this->checkPathRO(dirname($filename)); + } catch (\Exception $e) { + if ($e->getCode() !== 404) { + throw new \Exception($e->getMessage(), $e->getCode()); + } + } + if (file_exists($filename) && ! is_link($filename)) { + return true; + } + return false; } - return rmdir ($tmpdirname); - } - /** Return the list of files and directories in the directory. - * Do not return the . and .. virtual dirs. - * The result is sorted - * @param string $directory The directory to read - * @return array the list of files and dirs - * @throws If directory not exists, or is not executable - */ - public function scandir ($directory) - { - $this->debug (2, "scandir ($directory)"); - $directory = $this->realpath ($directory); - $this->checkPathRO ($directory); - $res = array_values (array_diff (scandir ($directory), array('..', '.'))); - natsort ($res); - return $res; - } - - /** Return the list of files and directories in the directory. - * Do not return the . and .. virtual dirs. - * The result is NOT sorted - * @param string $directory The directory to read - * @return array the list of files and dirs - * @throws If directory not exists, or is not executable - */ - public function scandirNotSorted ($directory) - { - $this->debug (2, "scandirNotSorted ($directory)"); - $directory = $this->realpath ($directory); - $this->checkPathRO ($directory); - $res = array_values (array_diff (scandir ($directory, SCANDIR_SORT_NONE), - array('..', '.'))); - return $res; - } - - /** Calculate the sha1 sum of a file - * @param string $filename The file to hash - * @return string the calulated hash - * @throws If the file doesn't exists - */ - public function sha1_file ($filename) - { - $this->debug (2, "sha1_file ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRO (dirname ($filename)); - if (! is_file ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not a file"), - $filename), 500); - if (! is_readable ($filename)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not readable"), - $filename), 500); - return sha1_file ($filename); - } - - /** Create a new file or update the timestamp if the file exists - * @param string $filename the filename - * @param integer|null $time the timestamp to use (actual timestamp if not - * defined) - * @param integer|null $atime the access timestamp to use (actual timestamp - * if not defined) - * @return bool true or false on failure - * @throws If parent directory not exists, is not writeable - */ - public function touch ($filename, $time = null, $atime = null) - { - $this->debug (2, "touch ($filename, $time, $atime)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if ($time === null) - $time = time (); - if ($atime === null) - $atime = time (); - $rc = touch ($filename, $time, $atime); - $this->debug (1, "touch ($filename, $time, $atime) => $rc"); - return $rc; - } - - /** Delete an existing file. - * @param string $filename The filename to remove - * @return bool true if the file si removed, false otherwise - * @throws If parent directory not exists, or is not executable - */ - public function unlink ($filename) - { - $this->debug (2, "unlink ($filename)"); - $filename = $this->realpath ($filename); - $this->checkPathRW (dirname ($filename)); - if (! file_exists ($filename) || ! is_writeable ($filename)) - return false; - return unlink ($filename); - } - - /** Check all the parents of the $directory if they are available, and - * executable. The path must exists. - * Must use the filesystem path (complete) and not the version in chroot. - * The last directoy must be executable and readable (no test for writeable) - * @param string $path The directory path to check - * @return boolean true if the path is executable for all the parents and - * for the last directory - * @throws if there is a missing part, or a parent is not executable - */ - private function checkPathRO ($path) - { - $this->debug (2, "checkPathRO ($path)"); - $path = preg_replace ("#//+#", "/", $path); - $parents = explode ("/", $path); - array_pop ($parents); - $parent = ""; - foreach ($parents as $p) + /** Get the file contents + * @param string $filename Name of the file to read + * @return string Content of the file + * @throws If parent directory not exists, is not readable, the file is not + * exists or is not readable + */ + public function file_get_contents($filename) { - $parent = $parent.$p."/"; - if (! file_exists ($parent)) - { - $this->debug (1, - "checkPathRO ($path) => Parent Path '$parent' not found"); - throw new \Exception (sprintf (dgettext ("domframework", - "Parent Path '%s' not found"), - $parent), 404); - } - if (! is_executable ($parent)) - { - $this->debug (1, "checkPathRO ($path) => ". + $this->debug(2, "file_get_contents ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable" + ), + $filename + ), 500); + } + $contents = file_get_contents($filename); + $this->debug(1, "file_get_contents ($filename) => " . strlen($contents) . + " bytes"); + return $contents; + } + + /** Write a string to a file + * @param string $filename Path to the file where to write the data + * @param string|integer $data The data to write + * @param integer|null $flags The optional flags + * @return integer the length of the data stored + * @throws If parent directory not exists, is not writeable, or the file + * exists and is not writeable + */ + public function file_put_contents($filename, $data, $flags = 0) + { + $this->debug(2, "file_put_contents ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (file_exists($filename) && ! is_writeable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not writeable" + ), + $filename + ), 500); + } + if (file_exists($filename) && ! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + $contents = file_put_contents($filename, $data, $flags); + $this->debug(1, "file_put_contents ($filename, \$data) => " . + "$contents bytes"); + return $contents; + } + + /** Get the file modification time of a file + * @param string $filename Path to the file + * @return integer|boolean the time the file was last modified, or FALSE + * on failure. The time is returned as a Unix timestamp, which is suitable + * for the date() function. + * @throws If parent directory not exists, is not writeable + */ + public function filemtime($filename) + { + $this->debug(2, "filemtime ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + return filemtime($filename); + } + + /** Get the file size + * @param string $filename Path to the file + * @return integer|boolean the size of the file or FALSE on failure. + * @throws If parent directory not exists, is not writeable + */ + public function filesize($filename) + { + $this->debug(2, "filesize ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + return filesize($filename); + } + + /** Get the file info of the provided filename + * @param string $filename Path to the file + * @return string the mimetype of the file + * @throws If parent directory not exists, is not writeable + */ + public function fileinfoMimeType($filename) + { + $this->debug(2, "filesize ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + $finfo = new \finfo(FILEINFO_MIME_TYPE); + return $finfo->file($filename); + } + + /** Return the current working directory + * @return string the current working directory */ + public function getcwd() + { + $this->debug(1, "getcwd $this->cwd"); + return $this->cwd; + } + + /** Find pathnames matching a pattern + * If there is some unreadable files, skip them quietly + * @param string $pattern The pattern to found + * @param integer|null $flags The additional flags + * @return array Return an array if there is an error + * @throws If parent directory not exists, or is not executable + * or if there is one file unreadable + */ + public function glob($pattern, $flags = 0) + { + $this->debug(2, "glob ($pattern, $flags)"); + $this->checkPathRO($this->baseDir); + if (substr($pattern, 0, 1) === "/") { + $relative = 0; + } else { + $relative = 1; + } + $pattern = $this->realpath($pattern); + $files = glob($pattern, $flags); + if ($files === false) { + // FIXME : In the exception : how found the file which is not readable ? + throw new \Exception("Glob : can't read some files", 500); + } + foreach ($files as &$file) { + if (strlen($this->baseDir) > 1) { + if ($relative == 1) { + $file = substr($file, strlen($this->baseDir) + strlen($this->cwd) + 1); + } else { + $file = substr($file, strlen($this->baseDir)); + } + } else { + if ($relative == 1) { + $file = substr($file, strlen($this->cwd) + 1); + } + } + } + return $files; + } + + /** Tells whether the given filename is a directory + * @param string $filename The filename to test + * @return bool true if the $filename is a directory and exists, false + * otherwise + * @throws If parent directory not exists, or is not executable + */ + public function is_dir($filename) + { + $this->debug(2, "is_dir ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (file_exists($filename) && is_dir($filename)) { + return true; + } + return false; + } + + /** Tells whether the given filename is a valid file + * @param string $filename The filename to test + * @return bool true if the $filename is a file and exists, false otherwise + * @throws If parent directory not exists, or is not executable + */ + public function is_file($filename) + { + $this->debug(2, "is_file ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (file_exists($filename) && is_file($filename)) { + return true; + } + return false; + } + + /** Tells whether a file exists and is executable + * @param string $filename The filename to test + * @return bool true if the $filename is a file exists and is writeable + * @throws If parent directory not exists, or is not executable + */ + public function is_executable($filename) + { + $this->debug(2, "is_executable ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (file_exists($filename) && is_executable($filename)) { + return true; + } + return false; + } + + /** Tells whether a file exists and is readable + * @param string $filename The filename to test + * @return bool true if the $filename is a file exists and is readable + * @throws If parent directory not exists, or is not executable + */ + public function is_readable($filename) + { + $this->debug(2, "is_readable ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (file_exists($filename) && is_readable($filename)) { + return true; + } + return false; + } + + /** Tells whether a file exists and is writeable + * @param string $filename The filename to test + * @return bool true if the $filename is a file exists and is writeable + * @throws If parent directory not exists, or is not executable + */ + public function is_writeable($filename) + { + $this->debug(2, "is_writeable ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (file_exists($filename) && is_writeable($filename)) { + return true; + } + return false; + } + + /** Lock a file exclusively + * @param string $filename The file to lock + * @return bool true if the lock is acquired, false otherwise + * @throws If parent directory not exists, or is not writeable + */ + public function lockEX($filename) + { + $this->debug(2, "lockEX ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' doesn't exists : could not be locked" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable : could not be locked" + ), + $filename + ), 500); + } + $this->locks[$filename] = fopen($filename, "rt"); + return flock($this->locks[$filename], LOCK_EX); + } + + /** Lock a file shared (allow multiple read) + * @param string $filename The file to lock + * @return bool true if the lock is acquired, false otherwise + * @throws If parent directory not exists, or is not writeable + */ + public function lockSH($filename) + { + $this->debug(2, "lockSH ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' doesn't exists : could not be locked" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable : could not be locked" + ), + $filename + ), 500); + } + $this->locks[$filename] = fopen($filename, "rt"); + return flock($this->locks[$filename], LOCK_SH); + } + + /** Unlock a file previously locked + * @param string $filename The file to lock + * @return bool true if the lock is acquired, false otherwise + * @throws If parent directory not exists, or is not writeable + */ + public function lockUN($filename) + { + $this->debug(2, "lockUN ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + $res = true; + if (isset($this->locks[$filename])) { + $res = flock($this->locks[$filename], LOCK_UN); + fclose($this->locks[$filename]); + unset($this->locks[$filename]); + } + return $res; + } + + /** Calculate the md5 sum of a file + * @param string $filename The file to hash + * @return string the calulated hash + * @throws If the file doesn't exists + */ + public function md5_file($filename) + { + $this->debug(2, "md5_file ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable" + ), + $filename + ), 500); + } + return md5_file($filename); + } + + /** Create a new directory + * @param string $pathname The directory to create + * @param integer $mode The mode to create (0777 by default) + * @param boolean $recursive (false by default) + * @return bool true if the directory is correctely created, false if the + * directory already exists + * @throws If parent directory not exists, is not writeable + */ + public function mkdir($pathname, $mode = 0777, $recursive = false) + { + $this->debug(2, "mkdir ($pathname, $mode, $recursive)"); + $pathname = $this->realpath($pathname); + if ($recursive) { + $parents = explode("/", $pathname); + array_pop($parents); + $parent = ""; + foreach ($parents as $p) { + $parent = $parent . $p . "/"; + if (! file_exists($parent)) { + if (is_writeable(dirname($parent))) { + break; + } + throw new \Exception(sprintf( + "Last Directory '%s' is readonly", + dirname($parent) + ), 500); + } + } + if ($parent === dirname($pathname) && ! is_writeable(dirname($parent))) { + throw new \Exception(sprintf( + "Parent directory '%s' is readonly", + dirname($parent) + ), 500); + } + } else { + $this->checkPathRW(dirname($pathname)); + } + if (file_exists($pathname)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' already exists" + ), + $pathname + ), 500); + } + $rc = mkdir($pathname, $mode, $recursive); + $this->debug(1, "mkdir ($pathname, $mode, $recursive) => $rc"); + return $rc; + } + + /** Copy a file or a directory + * @param string $oldname The file to copy + * @param string $newname The new name of the file. It will be + * overwrited if it already exists + * @return bool + */ + public function copy($oldname, $newname) + { + $this->debug(2, "copy ($oldname, $newname)"); + $oldname = $this->realpath($oldname); + $newname = $this->realpath($newname); + $this->checkPathRO(dirname($oldname)); + $this->checkPathRW(dirname($newname)); + if (is_dir($oldname)) { + // Copy directory structure + if (! $this->file_exists($newname)) { + $this->mkdir($newname); + } + $files = $this->scandirNotSorted($oldname); + foreach ($files as $file) { + $this->copy("$oldname/$file", "$newname/$file"); + } + } else { + $rc = copy($oldname, $newname); + } + $this->debug(1, "copy ($oldname, $newname) => $rc"); + return $rc; + } + + /** Renames a file or directory + * @param string $oldname The file or directory to rename + * @param string $newname The new name of the file or directory. It will be + * overwrited if it already exists + * @return bool + */ + public function rename($oldname, $newname) + { + $this->debug(2, "rename ($oldname, $newname)"); + $oldname = $this->realpath($oldname); + $newname = $this->realpath($newname); + $this->checkPathRO(dirname($oldname)); + $this->checkPathRW(dirname($newname)); + $rc = rename($oldname, $newname); + $this->debug(1, "rename ($oldname, $newname) => $rc"); + return $rc; + } + + /** Return a ini file converted to an array + * @param string $filename The filename of the ini file being parsed. + * @param boolean $process_sections Process the sections + * @return array + */ + public function parse_ini_file($filename, $process_sections = false) + { + $this->debug(2, "parse_ini_file ($filename, $process_sections)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable" + ), + $filename + ), 500); + } + return parse_ini_file($filename, $process_sections); + } + + /** Return the canonical absolute path. Do not check if the directory exists, + * if there is links. Just calculate the realpath based on the chroot value + * @param string $path the path to analyze + * @return string the canonical absolute path + */ + public function realpath($path) + { + $oriPath = $path; + $this->debug(2, "realpath ($oriPath)"); + $path = preg_replace("#//+#", "/", $path); + if (substr($path, -1) === "/") { + $path = substr($path, 0, -1); + } + $parts = explode("/", $path); + $current = $this->cwd; + $tmp = explode("/", $current); + foreach ($parts as $part) { + if ($part === "") { + $tmp = array(); + } elseif ($part === ".") { + continue; + } elseif ($part === "..") { + array_pop($tmp); + continue; + } else { + array_push($tmp, $part); + } + } + if (reset($tmp) === ".") { + array_shift($tmp); + $path = $current . "/" . implode("/", $tmp); + } else { + $path = "/" . implode("/", $tmp); + } + if ($this->baseDir !== "/") { + $path = $this->baseDir . $path; + } + $path = preg_replace("#//+#", "/", $path); + if ($path !== "/" && substr($path, -1) === "/") { + $path = substr($path, 0, -1); + } + $this->debug(1, "realpath ($oriPath) => $path"); + return $path; + } + + /** Remove the provided directory + * If the recurse flag is true, remove the content too (files and + * directories) + * @param string $dirname The directory to remove + * @param boolean $recursive Remove recursively + * @return bool true if all is removed, false otherwise + * @throws If parent directory not exists, is not writeable or the current + * dir is not writeable + */ + public function rmdir($dirname, $recursive = false) + { + $this->debug(2, "rmdir ($dirname, $recursive)"); + $tmpdirname = $this->realpath($dirname); + $this->checkPathRW(dirname($tmpdirname)); + $this->checkPathRW($tmpdirname); + if ($recursive === false) { + return @rmdir($tmpdirname); + } + $files = array_diff(scandir($tmpdirname), array(".", "..")); + foreach ($files as $file) { + if (is_dir("$tmpdirname/$file")) { + $this->rmdir("$dirname/$file", $recursive); + } else { + unlink("$tmpdirname/$file"); + } + } + return rmdir($tmpdirname); + } + + /** Return the list of files and directories in the directory. + * Do not return the . and .. virtual dirs. + * The result is sorted + * @param string $directory The directory to read + * @return array the list of files and dirs + * @throws If directory not exists, or is not executable + */ + public function scandir($directory) + { + $this->debug(2, "scandir ($directory)"); + $directory = $this->realpath($directory); + $this->checkPathRO($directory); + $res = array_values(array_diff(scandir($directory), array('..', '.'))); + natsort($res); + return $res; + } + + /** Return the list of files and directories in the directory. + * Do not return the . and .. virtual dirs. + * The result is NOT sorted + * @param string $directory The directory to read + * @return array the list of files and dirs + * @throws If directory not exists, or is not executable + */ + public function scandirNotSorted($directory) + { + $this->debug(2, "scandirNotSorted ($directory)"); + $directory = $this->realpath($directory); + $this->checkPathRO($directory); + $res = array_values(array_diff( + scandir($directory, SCANDIR_SORT_NONE), + array('..', '.') + )); + return $res; + } + + /** Calculate the sha1 sum of a file + * @param string $filename The file to hash + * @return string the calulated hash + * @throws If the file doesn't exists + */ + public function sha1_file($filename) + { + $this->debug(2, "sha1_file ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRO(dirname($filename)); + if (! is_file($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not a file" + ), + $filename + ), 500); + } + if (! is_readable($filename)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "File '%s' is not readable" + ), + $filename + ), 500); + } + return sha1_file($filename); + } + + /** Create a new file or update the timestamp if the file exists + * @param string $filename the filename + * @param integer|null $time the timestamp to use (actual timestamp if not + * defined) + * @param integer|null $atime the access timestamp to use (actual timestamp + * if not defined) + * @return bool true or false on failure + * @throws If parent directory not exists, is not writeable + */ + public function touch($filename, $time = null, $atime = null) + { + $this->debug(2, "touch ($filename, $time, $atime)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if ($time === null) { + $time = time(); + } + if ($atime === null) { + $atime = time(); + } + $rc = touch($filename, $time, $atime); + $this->debug(1, "touch ($filename, $time, $atime) => $rc"); + return $rc; + } + + /** Delete an existing file. + * @param string $filename The filename to remove + * @return bool true if the file si removed, false otherwise + * @throws If parent directory not exists, or is not executable + */ + public function unlink($filename) + { + $this->debug(2, "unlink ($filename)"); + $filename = $this->realpath($filename); + $this->checkPathRW(dirname($filename)); + if (! file_exists($filename) || ! is_writeable($filename)) { + return false; + } + return unlink($filename); + } + + /** Check all the parents of the $directory if they are available, and + * executable. The path must exists. + * Must use the filesystem path (complete) and not the version in chroot. + * The last directoy must be executable and readable (no test for writeable) + * @param string $path The directory path to check + * @return boolean true if the path is executable for all the parents and + * for the last directory + * @throws if there is a missing part, or a parent is not executable + */ + private function checkPathRO($path) + { + $this->debug(2, "checkPathRO ($path)"); + $path = preg_replace("#//+#", "/", $path); + $parents = explode("/", $path); + array_pop($parents); + $parent = ""; + foreach ($parents as $p) { + $parent = $parent . $p . "/"; + if (! file_exists($parent)) { + $this->debug( + 1, + "checkPathRO ($path) => Parent Path '$parent' not found" + ); + throw new \Exception(sprintf( + dgettext( + "domframework", + "Parent Path '%s' not found" + ), + $parent + ), 404); + } + if (! is_executable($parent)) { + $this->debug(1, "checkPathRO ($path) => " . "Parent Directory '$parent' not executable"); - throw new \Exception (sprintf (dgettext ("domframework", - "Parent Directory '%s' not executable"), - $parent), 500); - } - if ($this->checkExternalPathRO ($parent) !== true) - { - $this->debug (1, "checkPathRO ($path) => ". - "Parent Directory '$parent' not accessible by ". + throw new \Exception(sprintf( + dgettext( + "domframework", + "Parent Directory '%s' not executable" + ), + $parent + ), 500); + } + if ($this->checkExternalPathRO($parent) !== true) { + $this->debug(1, "checkPathRO ($path) => " . + "Parent Directory '$parent' not accessible by " . "external check read-only"); - throw new \Exception (sprintf (dgettext ("domframework", - "Parent Directory '%s' not accessible ". - "by external check read-only"), - $parent), 500); - } - } - if (! file_exists ($path)) - { - $this->debug (1, "checkPathRO ($path) => Path '$path' not found"); - throw new \Exception (sprintf (dgettext ("domframework", - "Path '%s' not found"), - $path), 404); - } - if (! is_dir ($path)) - { - $this->debug (1, "checkPathRO ($path) => ". + throw new \Exception(sprintf( + dgettext( + "domframework", + "Parent Directory '%s' not accessible " . + "by external check read-only" + ), + $parent + ), 500); + } + } + if (! file_exists($path)) { + $this->debug(1, "checkPathRO ($path) => Path '$path' not found"); + throw new \Exception(sprintf( + dgettext( + "domframework", + "Path '%s' not found" + ), + $path + ), 404); + } + if (! is_dir($path)) { + $this->debug(1, "checkPathRO ($path) => " . "Path '$path' is not a directory"); - throw new \Exception (sprintf (dgettext ("domframework", - "Path '%s' is not a directory"), - $path), - 500); - } - if (! is_executable ($path)) - { - $this->debug (1, "checkPathRO ($path) => ". + throw new \Exception( + sprintf( + dgettext( + "domframework", + "Path '%s' is not a directory" + ), + $path + ), + 500 + ); + } + if (! is_executable($path)) { + $this->debug(1, "checkPathRO ($path) => " . "Directory '$path' is not executable"); - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' is not executable"), - $path), 500); - } - if (! is_readable ($path)) - { - $this->debug (1, "checkPathRO ($path) => ". + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' is not executable" + ), + $path + ), 500); + } + if (! is_readable($path)) { + $this->debug(1, "checkPathRO ($path) => " . "Directory '$path' is not readable"); - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' is not readable"), - $path), 500); + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' is not readable" + ), + $path + ), 500); + } + return $this->checkExternalPathRO($path); } - return $this->checkExternalPathRO ($path); - } - /** Check all the parents of the $directory if they are available, and - * executable. The path must exists. - * Must use the filesystem path (complete) and not the version in chroot. - * The last directoy must be executable and readable and writeable - * @param string $path The directory path to check - * @return true if the path is executable for all the parents and for the - * last directory - * @throws if there is a missing part, or a parent is not executable - */ - private function checkPathRW ($path) - { - $this->debug (2, "checkPathRW ($path)"); - $this->checkPathRO ($path); - if (! is_writeable ($path)) + /** Check all the parents of the $directory if they are available, and + * executable. The path must exists. + * Must use the filesystem path (complete) and not the version in chroot. + * The last directoy must be executable and readable and writeable + * @param string $path The directory path to check + * @return true if the path is executable for all the parents and for the + * last directory + * @throws if there is a missing part, or a parent is not executable + */ + private function checkPathRW($path) { - $this->debug (1, "checkPathRW ($path) => ". + $this->debug(2, "checkPathRW ($path)"); + $this->checkPathRO($path); + if (! is_writeable($path)) { + $this->debug(1, "checkPathRW ($path) => " . "Directory '$path' is not writeable"); - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' is not writeable"), - $path), 500); - } - if ($this->checkExternalPathRW ($path) !== true) - { - $this->debug (1, "checkPathRW ($path) => ". - "Directory '$path' not accessible by ". + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' is not writeable" + ), + $path + ), 500); + } + if ($this->checkExternalPathRW($path) !== true) { + $this->debug(1, "checkPathRW ($path) => " . + "Directory '$path' not accessible by " . "external check read-write"); - throw new \Exception (sprintf (dgettext ("domframework", - "Directory '%s' not accessible ". - "by external check read-write"), - $path), 500); + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' not accessible " . + "by external check read-write" + ), + $path + ), 500); + } + return true; } - return true; - } - /** Save a debug log - * @param integer $prio The message priority. Should be higher than - * $this->debug to save the message - * @param string $message The message to save - * @return null - */ - private function debug ($prio, $message) - { - if ($this->debug === false || $this->debug === 0) - return; - if ($prio <= $this->debug) + /** Save a debug log + * @param integer $prio The message priority. Should be higher than + * $this->debug to save the message + * @param string $message The message to save + * @return null + */ + private function debug($prio, $message) { - echo "[$prio] $message\n"; - //file_put_contents ("/tmp/domframework.file.debug", + if ($this->debug === false || $this->debug === 0) { + return; + } + if ($prio <= $this->debug) { + echo "[$prio] $message\n"; + //file_put_contents ("/tmp/domframework.file.debug", // date ("Y:m:d H:i:s")." [$prio] $message\n", // FILE_APPEND); + } } - } - /** External function allowed to be overloaded to test the RO access to a - * resource - * @param string $path The path to test in the filesystem - * @return boolean true if RO access, false if not - */ - public function checkExternalPathRO ($path) - { - return true; - } + /** External function allowed to be overloaded to test the RO access to a + * resource + * @param string $path The path to test in the filesystem + * @return boolean true if RO access, false if not + */ + public function checkExternalPathRO($path) + { + return true; + } - /** External function allowed to be overloaded to test the RW access to a - * resource - * @param string $path The path to test in the filesystem - * @return boolean true if RW access, false if not - */ - public function checkExternalPathRW ($path) - { - return true; - } + /** External function allowed to be overloaded to test the RW access to a + * resource + * @param string $path The path to test in the filesystem + * @return boolean true if RW access, false if not + */ + public function checkExternalPathRW($path) + { + return true; + } } diff --git a/src/Fork.php b/src/Fork.php index eaec33a..3d469d4 100644 --- a/src/Fork.php +++ b/src/Fork.php @@ -1,4 +1,5 @@ @@ -11,256 +12,257 @@ namespace Domframework; */ class Fork { - /** The PID list of childs - */ - private $pidList = array (); + /** The PID list of childs + */ + private $pidList = array(); - /** The constructor check if the posix functions exists - */ - public function __construct () - { - if (! function_exists ("pcntl_fork")) - throw new \Exception ("Can't fork as PHP doesn't have the pcntl_fork", - 500); - if (function_exists ("pcntl_async_signals")) - pcntl_async_signals (true); - else - declare (ticks=1); - } - - /** Return the number of active PID - */ - public function childCount () - { - return count ($this->pidList); - } - - /** Return the list of the active PID - */ - public function childList () - { - return $this->pidList; - } - - /** Create a child - * If some parameters are provided, the called child method will receive them - * This function fork and return the child PID - * @param callable $callable The callback method to use in child - * @param mixed|null $params The params to provide to child method - * @return The child PID - */ - public function startChild ($callable, $params = array ()) - { - $pid = pcntl_fork (); - if ($pid === -1) - throw new \Exception ("Can't fork the child", 500); - elseif ($pid) + /** The constructor check if the posix functions exists + */ + public function __construct() { - // The parent - $this->pidList[$pid] = $pid; - return $pid; - } - // Call the child method - $args = func_get_args (); - unset ($args[0]); - call_user_func_array ($callable, $args); - exit; - } - - /** Create a detached child. The terminal is closed. All the displayed - * messages from the child are silently dropped. - * If some parameters are provided, the called child method will receive them - * This function fork and return the child PID - * @param string $name The name displayed in the processus list - * @param callable $callable The callback method to use in child - * @param mixed|null $params The params to provide to child method - * @return The child PID - */ - public function startDetachedChild ($name, $callable, $params = array ()) - { - $pid = pcntl_fork (); - if ($pid === -1) - throw new \Exception ("Can't fork the child", 500); - elseif ($pid) - { - // The parent - $this->pidList[$pid] = $pid; - return $pid; - } - // Call the child method - $sid = posix_setsid(); - - // Will catch all the text messages from the application to not crash if - // there is an "echo" - ob_start (); - - // Catch the error messages from the application to not hang if triggered - // An other handler can be set in function to execute - set_error_handler (function () {}); - - // Close the file handlers STDOUT/STDIN - fclose (STDIN); - fclose (STDOUT); - fclose (STDERR); - if (function_exists ("cli_set_process_title")) - cli_set_process_title ($name); - - $args = func_get_args (); - unset ($args[0]); - call_user_func_array ($callable, $args); - exit; - } - - /** Wait the end of one child - * Return the PID of the dead child - */ - public function waitEndChild () - { - while (1) - { - $stoppedPid = pcntl_wait ($status, WNOHANG); - if ($stoppedPid > 0) - { - unset ($this->pidList[$stoppedPid]); - return $stoppedPid; - } - usleep (100); - } - } - - /** Clean the childs which are finished. Do not block the process - */ - public function cleanEndChild () - { - $stoppedPid = pcntl_wait ($status, WNOHANG); - while ($stoppedPid > 0) - { - unset ($this->pidList[$stoppedPid]); - $stoppedPid = pcntl_wait ($status, WNOHANG); - } - } - - /** Stop (SIGTERM) a specific child. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer $pid The PID of the child to stop - * @param integer|null $maxWait The maximum time to wait the child if set - * @return $pid if the child is dead correctely. Return false if the child is - * not dead in the $maxWait time - */ - public function stopChild ($pid, $maxWait = null) - { - if (! key_exists ($pid, $this->pidList)) - throw new \Exception ("Can't stop pid '$pid' : not in the fork list", - 500); - return $this->sendSignalToChild (SIGTERM, $pid, $maxWait); - } - - /** Kill (SIGKILL) a specific child. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer $pid The PID of the child to stop - * @param integer|null $maxWait The maximum time to wait the child if set - * @return $pid if the child is dead correctely. Return false if the child is - * not dead in the $maxWait time - */ - public function killChild ($pid, $maxWait = null) - { - if (! key_exists ($pid, $this->pidList)) - throw new \Exception ("Can't kill pid '$pid' : not in the fork list", - 500); - return $this->sendSignalToChild (SIGKILL, $pid, $maxWait); - } - - /** Send a signal to a specific child. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer $signal The signal to send to child (SIGTERM or SIGKILL) - * @param integer $pid The PID of the child to stop - * @param integer|null $maxWait The maximum time to wait the child if set - * @return $pid if the child is dead correctely. Return false if the child is - * not dead in the $maxWait time - */ - private function sendSignalToChild ($signal, $pid, $maxWait = null) - { - posix_kill ($pid, $signal); - if ($maxWait !== null) - { - $startWait = time (); - while (time () < $startWait + $maxWait) - { - if (pcntl_waitpid ($pid, $status, WNOHANG) > 0) - { - unset ($this->pidList[$pid]); - return $pid; + if (! function_exists("pcntl_fork")) { + throw new \Exception( + "Can't fork as PHP doesn't have the pcntl_fork", + 500 + ); } - usleep (100); - } - return false; - } - return $pid; - } - - /** Stop all the existing children. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer|null $maxWait The maximum time to wait the child if set - * @return true if all the children are dead correctely. Return false if at - * least one child isnot dead in the $maxWait time - */ - public function stopAll ($maxWait = null) - { - return $this->sendSigToAll (SIGTERM, $maxWait); - } - - /** Kill all the existing children. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer|null $maxWait The maximum time to wait the child if set - * @return true if all the children are dead correctely. Return false if at - * least one child isnot dead in the $maxWait time - */ - public function killAll ($maxWait = null) - { - return $this->sendSigToAll (SIGKILL, $maxWait); - } - - /** Send a stop or kill signal to all the existing children. - * If the $maxWait parameter is set, wait the dead of the child for $maxWait - * seconds. If $maxWait is not set, do not wait the child, only send it the - * signal - * @param integer $signal The signal to send to child (SIGTERM or SIGKILL) - * @param integer|null $maxWait The maximum time to wait the child if set - * @return true if all the children are dead correctely. Return false if at - * least one child isnot dead in the $maxWait time - */ - private function sendSigToAll ($signal, $maxWait = null) - { - foreach ($this->pidList as $pid) - { - posix_kill ($pid, $signal); - } - if ($maxWait !== null) - { - $startWait = time (); - while (time () < $startWait + $maxWait) - { - $pid = pcntl_wait ($status, WNOHANG); - if ($pid > 0) - { - unset ($this->pidList[$pid]); - if (empty ($this->pidList)) - return true; + if (function_exists("pcntl_async_signals")) { + pcntl_async_signals(true); + } else { + declare(ticks=1); } - usleep (100); - } - return false; } - return true; - } + + /** Return the number of active PID + */ + public function childCount() + { + return count($this->pidList); + } + + /** Return the list of the active PID + */ + public function childList() + { + return $this->pidList; + } + + /** Create a child + * If some parameters are provided, the called child method will receive them + * This function fork and return the child PID + * @param callable $callable The callback method to use in child + * @param mixed|null $params The params to provide to child method + * @return The child PID + */ + public function startChild($callable, $params = array()) + { + $pid = pcntl_fork(); + if ($pid === -1) { + throw new \Exception("Can't fork the child", 500); + } elseif ($pid) { + // The parent + $this->pidList[$pid] = $pid; + return $pid; + } + // Call the child method + $args = func_get_args(); + unset($args[0]); + call_user_func_array($callable, $args); + exit; + } + + /** Create a detached child. The terminal is closed. All the displayed + * messages from the child are silently dropped. + * If some parameters are provided, the called child method will receive them + * This function fork and return the child PID + * @param string $name The name displayed in the processus list + * @param callable $callable The callback method to use in child + * @param mixed|null $params The params to provide to child method + * @return The child PID + */ + public function startDetachedChild($name, $callable, $params = array()) + { + $pid = pcntl_fork(); + if ($pid === -1) { + throw new \Exception("Can't fork the child", 500); + } elseif ($pid) { + // The parent + $this->pidList[$pid] = $pid; + return $pid; + } + // Call the child method + $sid = posix_setsid(); + + // Will catch all the text messages from the application to not crash if + // there is an "echo" + ob_start(); + + // Catch the error messages from the application to not hang if triggered + // An other handler can be set in function to execute + set_error_handler(function () { + }); + + // Close the file handlers STDOUT/STDIN + fclose(STDIN); + fclose(STDOUT); + fclose(STDERR); + if (function_exists("cli_set_process_title")) { + cli_set_process_title($name); + } + + $args = func_get_args(); + unset($args[0]); + call_user_func_array($callable, $args); + exit; + } + + /** Wait the end of one child + * Return the PID of the dead child + */ + public function waitEndChild() + { + while (1) { + $stoppedPid = pcntl_wait($status, WNOHANG); + if ($stoppedPid > 0) { + unset($this->pidList[$stoppedPid]); + return $stoppedPid; + } + usleep(100); + } + } + + /** Clean the childs which are finished. Do not block the process + */ + public function cleanEndChild() + { + $stoppedPid = pcntl_wait($status, WNOHANG); + while ($stoppedPid > 0) { + unset($this->pidList[$stoppedPid]); + $stoppedPid = pcntl_wait($status, WNOHANG); + } + } + + /** Stop (SIGTERM) a specific child. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer $pid The PID of the child to stop + * @param integer|null $maxWait The maximum time to wait the child if set + * @return $pid if the child is dead correctely. Return false if the child is + * not dead in the $maxWait time + */ + public function stopChild($pid, $maxWait = null) + { + if (! key_exists($pid, $this->pidList)) { + throw new \Exception( + "Can't stop pid '$pid' : not in the fork list", + 500 + ); + } + return $this->sendSignalToChild(SIGTERM, $pid, $maxWait); + } + + /** Kill (SIGKILL) a specific child. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer $pid The PID of the child to stop + * @param integer|null $maxWait The maximum time to wait the child if set + * @return $pid if the child is dead correctely. Return false if the child is + * not dead in the $maxWait time + */ + public function killChild($pid, $maxWait = null) + { + if (! key_exists($pid, $this->pidList)) { + throw new \Exception( + "Can't kill pid '$pid' : not in the fork list", + 500 + ); + } + return $this->sendSignalToChild(SIGKILL, $pid, $maxWait); + } + + /** Send a signal to a specific child. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer $signal The signal to send to child (SIGTERM or SIGKILL) + * @param integer $pid The PID of the child to stop + * @param integer|null $maxWait The maximum time to wait the child if set + * @return $pid if the child is dead correctely. Return false if the child is + * not dead in the $maxWait time + */ + private function sendSignalToChild($signal, $pid, $maxWait = null) + { + posix_kill($pid, $signal); + if ($maxWait !== null) { + $startWait = time(); + while (time() < $startWait + $maxWait) { + if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { + unset($this->pidList[$pid]); + return $pid; + } + usleep(100); + } + return false; + } + return $pid; + } + + /** Stop all the existing children. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer|null $maxWait The maximum time to wait the child if set + * @return true if all the children are dead correctely. Return false if at + * least one child isnot dead in the $maxWait time + */ + public function stopAll($maxWait = null) + { + return $this->sendSigToAll(SIGTERM, $maxWait); + } + + /** Kill all the existing children. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer|null $maxWait The maximum time to wait the child if set + * @return true if all the children are dead correctely. Return false if at + * least one child isnot dead in the $maxWait time + */ + public function killAll($maxWait = null) + { + return $this->sendSigToAll(SIGKILL, $maxWait); + } + + /** Send a stop or kill signal to all the existing children. + * If the $maxWait parameter is set, wait the dead of the child for $maxWait + * seconds. If $maxWait is not set, do not wait the child, only send it the + * signal + * @param integer $signal The signal to send to child (SIGTERM or SIGKILL) + * @param integer|null $maxWait The maximum time to wait the child if set + * @return true if all the children are dead correctely. Return false if at + * least one child isnot dead in the $maxWait time + */ + private function sendSigToAll($signal, $maxWait = null) + { + foreach ($this->pidList as $pid) { + posix_kill($pid, $signal); + } + if ($maxWait !== null) { + $startWait = time(); + while (time() < $startWait + $maxWait) { + $pid = pcntl_wait($status, WNOHANG); + if ($pid > 0) { + unset($this->pidList[$pid]); + if (empty($this->pidList)) { + return true; + } + } + usleep(100); + } + return false; + } + return true; + } } diff --git a/src/Form.php b/src/Form.php index a0d3855..a1feb93 100644 --- a/src/Form.php +++ b/src/Form.php @@ -1,4 +1,5 @@ @@ -13,553 +14,567 @@ namespace Domframework; */ class Form { - /** All the fields */ - private $fields = NULL; - /** The name of the form - */ - private $formName; - /** Allow to debug the PHP - */ - public $debug=0; - /** CSRF protection - * By default, the CSRF protection is active if a SESSION is active too. - * It can be disabled if needed. An Exception is raised if the form is send - * back without the token - */ - public $csrf=TRUE; - /** Name of the CSRF hidden field in HTML page - */ - public $csrfField = "CSRF_TOKEN"; - /** The CSRF token value - */ - private $csrfToken = ""; + private $fields = null; + /** The name of the form + */ + private $formName; + /** Allow to debug the PHP + */ + public $debug = 0; + /** CSRF protection + * By default, the CSRF protection is active if a SESSION is active too. + * It can be disabled if needed. An Exception is raised if the form is send + * back without the token + */ + public $csrf = true; + /** Name of the CSRF hidden field in HTML page + */ + public $csrfField = "CSRF_TOKEN"; + /** The CSRF token value + */ + private $csrfToken = ""; - /** The method used to send the values - */ - private $method = "post"; + /** The method used to send the values + */ + private $method = "post"; - /** The Bootstrap width of the column of titles - */ - public $titlewidth = 2; - /** The Bootstrap width of the column of fields - */ - public $fieldwidth = 10; + /** The Bootstrap width of the column of titles + */ + public $titlewidth = 2; + /** The Bootstrap width of the column of fields + */ + public $fieldwidth = 10; - /** Define a class for form object - */ - public $formClass = "form-horizontal"; + /** Define a class for form object + */ + public $formClass = "form-horizontal"; - /** The logging callable method - */ - private $loggingCallable = null; - /** The logging basemsg - */ - private $loggingBasemsg = ""; + /** The logging callable method + */ + private $loggingCallable = null; + /** The logging basemsg + */ + private $loggingBasemsg = ""; - /** Form template (Bootstrap3 by default) - */ - private $formTemplate = "Bootstrap3"; + /** Form template (Bootstrap3 by default) + */ + private $formTemplate = "Bootstrap3"; - /** Create a form - * @param string|null $formName The form name - */ - public function __construct ($formName = "form") - { - $this->formName = $formName; - } - - // The setters of the properties - /** Set the debug level - * @param integer $val The debug value - */ - public function debug ($val) - { - $this->debug = $val; - return $this; - } - - /** Set the csrf enable - * @param integer $val The csrf check - */ - public function csrf ($val) - { - $this->csrf = !! $val; - return $this; - } - - /** Set the method - * @param string $val The method to use - */ - public function method ($val) - { - $this->method = strtolower ($val); - return $this; - } - - /** Set the csrf token name - * @param integer $val The csrf token name - */ - public function csrfField ($val) - { - $this->csrfField = $val; - return $this; - } - - /** Set the titlewidth - * @param integer $val The titlewidth - */ - public function titlewidth ($val) - { - $this->titlewidth = $val; - return $this; - } - - /** Set the fieldwidth - * @param integer $val The fieldwidth - */ - public function fieldwidth ($val) - { - $this->fieldwidth = $val; - return $this; - } - - /** Set the formClass - * @param integer $val The formClass - */ - public function formClass ($val) - { - $this->formClass = $val; - return $this; - } - - /** Set logging class an method - * @param callable $loggingCallable The callable function. This method will - * receive two params : the LOG level (LOG_ERROR...) and the message - * @param string|null $loggingBasemsg The basemsg added at the beginning of - * the log - */ - public function logging ($loggingCallable, $loggingBasemsg = "") - { - $this->loggingCallable = $loggingCallable; - $this->loggingBasemsg = $loggingBasemsg; - } - - /** Set the Form Templating to use. - * Can be : Bootstrap3, Bootstrap4 (later Bulma) - * @param string $formTemplate The template to use - */ - public function formTemplate ($formTemplate) - { - if (! in_array ($formTemplate, - array ("Bootstrap3", "Bootstrap4"))) - throw new \Exception ("Unknown formTemplate provided", 500); - $this->formTemplate = $formTemplate; - return $this; - } - - /** The private method to log if the $this->loggingCallable is defined - * @param integer $prio The priority of the message - * @param string $msg The message to store - */ - private function loggingCallable ($prio, $msg) - { - if (! is_callable ($this->loggingCallable)) - return; - $base = ""; - if ($this->loggingBasemsg !== "") - $base = $this->loggingBasemsg. " "; - call_user_func ($this->loggingCallable, $prio, $base.$msg); - } - - /** Save the array of 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, - * textarea - * text by default - * - [help] : The Help message (written below the field). Overwrited in - * case of error - * - [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 - * - [mandatory] : boolean to add a red star at end of label - * - [hidden] : hide the field (add a style='display:hidden' to the field) - * - [maxlength] : the maximum length of the content of the field in chars - * - [rows] : Number of rows - * - [cols] : Number of columns - * - [placeholder] : The text to be displayed in the placeholder - * - * @param array $fields The fields to be displayed - */ - public function fields ($fields) - { - $this->fields = $fields; - } - - /** Add a field to the form. For the details of a field, see the description - * in fields method - * @param object $field The field to add - */ - public function addfield ($field) - { - $this->fields[] = $field; - } - - /** Return the values provided by the user. Test the CSRF before continue - * NEVER read the values from $_POST in your codes or CSRF will not be - * checked - */ - public function values () - { - $values = array (); - if ($this->method === "post") + /** Create a form + * @param string|null $formName The form name + */ + public function __construct($formName = "form") { - if (isset ($_POST[$this->formName])) - $values = $_POST[$this->formName]; - } - elseif ($this->method === "get") - { - if (isset ($_GET[$this->formName])) - $values = $_GET[$this->formName]; - } - else - { - $this->loggingCallable (LOG_ERR, - "Unknown FORM method (GET or POST allowed)"); - throw new \Exception (dgettext ("domframework", - "Unknown FORM method (GET or POST allowed)")); + $this->formName = $formName; } - if (count ($values) !== 0 && $this->csrf === true) + // The setters of the properties + /** Set the debug level + * @param integer $val The debug value + */ + public function debug($val) { - // CSRF protection - try - { - $this->checkToken ($values[$this->csrfField]); - } - catch (\Exception $e) - { - $this->loggingCallable (LOG_ERR, $e->getMessage ()); - throw new \Exception (dgettext ("domframework", - "Can not read the data from the form : ". - "Expired or missing CSRF Token"), 500); - } - // Remove the field CSRF : can not be used outside the form - unset ($values[$this->csrfField]); + $this->debug = $val; + return $this; } - if (isset ($_SESSION["domframework"]["form"][$this->formName]["fields"])) + + /** Set the csrf enable + * @param integer $val The csrf check + */ + public function csrf($val) { - foreach ($_SESSION["domframework"]["form"][$this->formName]["fields"] as - $field) - { - if ($field->type === "hidden" || - ($field->readonly !== null && $field->readonly !== false)) - { - if (isset ($field->values)) - $values[$field->name] = $field->values; - elseif (isset ($field->defaults)) - $values[$field->name] = $field->defaults; + $this->csrf = !! $val; + return $this; + } + + /** Set the method + * @param string $val The method to use + */ + public function method($val) + { + $this->method = strtolower($val); + return $this; + } + + /** Set the csrf token name + * @param integer $val The csrf token name + */ + public function csrfField($val) + { + $this->csrfField = $val; + return $this; + } + + /** Set the titlewidth + * @param integer $val The titlewidth + */ + public function titlewidth($val) + { + $this->titlewidth = $val; + return $this; + } + + /** Set the fieldwidth + * @param integer $val The fieldwidth + */ + public function fieldwidth($val) + { + $this->fieldwidth = $val; + return $this; + } + + /** Set the formClass + * @param integer $val The formClass + */ + public function formClass($val) + { + $this->formClass = $val; + return $this; + } + + /** Set logging class an method + * @param callable $loggingCallable The callable function. This method will + * receive two params : the LOG level (LOG_ERROR...) and the message + * @param string|null $loggingBasemsg The basemsg added at the beginning of + * the log + */ + public function logging($loggingCallable, $loggingBasemsg = "") + { + $this->loggingCallable = $loggingCallable; + $this->loggingBasemsg = $loggingBasemsg; + } + + /** Set the Form Templating to use. + * Can be : Bootstrap3, Bootstrap4 (later Bulma) + * @param string $formTemplate The template to use + */ + public function formTemplate($formTemplate) + { + if ( + ! in_array( + $formTemplate, + array("Bootstrap3", "Bootstrap4") + ) + ) { + throw new \Exception("Unknown formTemplate provided", 500); } - } + $this->formTemplate = $formTemplate; + return $this; } - return $values; - } + /** The private method to log if the $this->loggingCallable is defined + * @param integer $prio The priority of the message + * @param string $msg The message to store + */ + private function loggingCallable($prio, $msg) + { + if (! is_callable($this->loggingCallable)) { + return; + } + $base = ""; + if ($this->loggingBasemsg !== "") { + $base = $this->loggingBasemsg . " "; + } + call_user_func($this->loggingCallable, $prio, $base . $msg); + } - /** 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
                - * @param string|null $method The method to use to transmit the form (POST, - * GET) - * @param array|null $values The default values of the fields - * @param array|null $errors The fields to put in error with the associated - * message - */ - public function printHTML ($method = 'post', $values = NULL, - $errors = array()) - { - if (count ($this->fields) === 0) + /** Save the array of 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, + * textarea + * text by default + * - [help] : The Help message (written below the field). Overwrited in + * case of error + * - [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 + * - [mandatory] : boolean to add a red star at end of label + * - [hidden] : hide the field (add a style='display:hidden' to the field) + * - [maxlength] : the maximum length of the content of the field in chars + * - [rows] : Number of rows + * - [cols] : Number of columns + * - [placeholder] : The text to be displayed in the placeholder + * + * @param array $fields The fields to be displayed + */ + public function fields($fields) { - $this->loggingCallable (LOG_ERR, - "Can't display a form without defined field"); - throw new \Exception ("Can't display a form without defined field", 500); + $this->fields = $fields; } - if (isset ($_SESSION)) - $_SESSION["domframework"]["form"][$this->formName]["fields"] = - $this->fields; - $this->method = strtolower ($method); - $res = ""; - $res = "fields as $field) + + /** Add a field to the form. For the details of a field, see the description + * in fields method + * @param object $field The field to add + */ + public function addfield($field) { - if ($field->type === "file") - { - $res .= "enctype='multipart/form-data'"; - break; - } + $this->fields[] = $field; } - if ($this->formName != "") - $res .= " id='$this->formName'"; - $res .= " class='".$this->formClass."'>\n"; - $group = ""; - if (isset ($_SESSION["domframework"]["form"][$this->formName]["values"])) + + /** Return the values provided by the user. Test the CSRF before continue + * NEVER read the values from $_POST in your codes or CSRF will not be + * checked + */ + public function values() { - $values = $_SESSION["domframework"]["form"][$this->formName]["values"]; - $errors = $_SESSION["domframework"]["form"][$this->formName]["errors"]; - unset ($_SESSION["domframework"]["form"][$this->formName]["values"]); - unset ($_SESSION["domframework"]["form"][$this->formName]["errors"]); + $values = array(); + if ($this->method === "post") { + if (isset($_POST[$this->formName])) { + $values = $_POST[$this->formName]; + } + } elseif ($this->method === "get") { + if (isset($_GET[$this->formName])) { + $values = $_GET[$this->formName]; + } + } else { + $this->loggingCallable( + LOG_ERR, + "Unknown FORM method (GET or POST allowed)" + ); + throw new \Exception(dgettext( + "domframework", + "Unknown FORM method (GET or POST allowed)" + )); + } + + if (count($values) !== 0 && $this->csrf === true) { + // CSRF protection + try { + $this->checkToken($values[$this->csrfField]); + } catch (\Exception $e) { + $this->loggingCallable(LOG_ERR, $e->getMessage()); + throw new \Exception(dgettext( + "domframework", + "Can not read the data from the form : " . + "Expired or missing CSRF Token" + ), 500); + } + // Remove the field CSRF : can not be used outside the form + unset($values[$this->csrfField]); + } + if (isset($_SESSION["domframework"]["form"][$this->formName]["fields"])) { + foreach ( + $_SESSION["domframework"]["form"][$this->formName]["fields"] as $field + ) { + if ( + $field->type === "hidden" || + ($field->readonly !== null && $field->readonly !== false) + ) { + if (isset($field->values)) { + $values[$field->name] = $field->values; + } elseif (isset($field->defaults)) { + $values[$field->name] = $field->defaults; + } + } + } + } + + return $values; } - foreach ($this->fields as $field) - { - $field->formName = $this->formName; - if (isset ($field->group) && $field->group !== $group && $group !== "" || - !isset ($field->group) && $group !== "") - { - $res .="\n"; + + /** 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 + * @param string|null $method The method to use to transmit the form (POST, + * GET) + * @param array|null $values The default values of the fields + * @param array|null $errors The fields to put in error with the associated + * message + */ + public function printHTML( + $method = 'post', + $values = null, + $errors = array() + ) { + if (count($this->fields) === 0) { + $this->loggingCallable( + LOG_ERR, + "Can't display a form without defined field" + ); + throw new \Exception("Can't display a form without defined field", 500); + } + if (isset($_SESSION)) { + $_SESSION["domframework"]["form"][$this->formName]["fields"] = + $this->fields; + } + $this->method = strtolower($method); + $res = ""; + $res = "fields as $field) { + if ($field->type === "file") { + $res .= "enctype='multipart/form-data'"; + break; + } + } + if ($this->formName != "") { + $res .= " id='$this->formName'"; + } + $res .= " class='" . $this->formClass . "'>\n"; $group = ""; - } - if (isset ($field->group) && $field->group !== $group) - { - $res .= "
                \n"; - $res .= " $field->group\n"; - $group = $field->group; - } - - $res .=" "; - if (isset ($values[$field->name]) && - $values[$field->name] !== "unset") - $field->values = $values[$field->name]; - if (isset ($errors[$field->name]) && - $errors[$field->name] !== "unset") - { - if (is_array ($errors[$field->name])) - $field->errors = $errors[$field->name]; - else - $field->errors = array ("error", $errors[$field->name]); - if ($field->type === "hidden") - { - $field->type = "text"; - $field->readonly = true; + if (isset($_SESSION["domframework"]["form"][$this->formName]["values"])) { + $values = $_SESSION["domframework"]["form"][$this->formName]["values"]; + $errors = $_SESSION["domframework"]["form"][$this->formName]["errors"]; + unset($_SESSION["domframework"]["form"][$this->formName]["values"]); + unset($_SESSION["domframework"]["form"][$this->formName]["errors"]); } - } - $field->titlewidth = $this->titlewidth; - $field->fieldwidth = $this->fieldwidth; - $field->formTemplate = $this->formTemplate; - $res .= $field->display (); - } + foreach ($this->fields as $field) { + $field->formName = $this->formName; + if ( + isset($field->group) && $field->group !== $group && $group !== "" || + !isset($field->group) && $group !== "" + ) { + $res .= "
                \n"; + $group = ""; + } + if (isset($field->group) && $field->group !== $group) { + $res .= "
                \n"; + $res .= " $field->group\n"; + $group = $field->group; + } - if ($group !== "") - { - $res .="
                \n"; - $group = ""; - } - - if ($this->csrf === TRUE) - { - $csrf = new Csrf (); - $csrf->field = $this->formName."[".$this->csrfField."]"; - $res .= $csrf->displayFormCSRF (); - $this->csrfToken = $csrf->getToken (); - } - - // Manage the focus. On the first visible element if there is no error, on - // the first error fields when there is one - $focusElement = null; - foreach ($this->fields as $field) - { - if ($field->type === "hidden" || $field->readonly === true) - continue; - if ($field->titles) - $focusElement = $field->name."_".key ($field->titles); - else - $focusElement = $field->name; - break; - } - if (count ($errors) > 0) - { - foreach ($errors as $fieldErr=>$error) - { - // If the field is numeric, it is a global error, and not an error due - // to a field: skip it ! - foreach ($this->fields as $field) - { - if ($field->name === $fieldErr) - { - $focusElement = $field->name; - break 2; - } + $res .= " "; + if ( + isset($values[$field->name]) && + $values[$field->name] !== "unset" + ) { + $field->values = $values[$field->name]; + } + if ( + isset($errors[$field->name]) && + $errors[$field->name] !== "unset" + ) { + if (is_array($errors[$field->name])) { + $field->errors = $errors[$field->name]; + } else { + $field->errors = array("error", $errors[$field->name]); + } + if ($field->type === "hidden") { + $field->type = "text"; + $field->readonly = true; + } + } + $field->titlewidth = $this->titlewidth; + $field->fieldwidth = $this->fieldwidth; + $field->formTemplate = $this->formTemplate; + $res .= $field->display(); } - } + + if ($group !== "") { + $res .= "\n"; + $group = ""; + } + + if ($this->csrf === true) { + $csrf = new Csrf(); + $csrf->field = $this->formName . "[" . $this->csrfField . "]"; + $res .= $csrf->displayFormCSRF(); + $this->csrfToken = $csrf->getToken(); + } + + // Manage the focus. On the first visible element if there is no error, on + // the first error fields when there is one + $focusElement = null; + foreach ($this->fields as $field) { + if ($field->type === "hidden" || $field->readonly === true) { + continue; + } + if ($field->titles) { + $focusElement = $field->name . "_" . key($field->titles); + } else { + $focusElement = $field->name; + } + break; + } + if (count($errors) > 0) { + foreach ($errors as $fieldErr => $error) { + // If the field is numeric, it is a global error, and not an error due + // to a field: skip it ! + foreach ($this->fields as $field) { + if ($field->name === $fieldErr) { + $focusElement = $field->name; + break 2; + } + } + } + } + if ($focusElement !== null) { + $res .= "\n"; + } + $res .= "
                \n"; + return $res; } - if ($focusElement !== null) - $res .= "\n"; - $res .= "\n"; - return $res; - } - /** Check the token from the user - * @param string $tokenFromUser The value form the user's token - */ - public function checkToken ($tokenFromUser) - { - $csrf = new Csrf (); - $csrf->field = $this->csrfField; - // The checkThenDeleteToken method check the token and except if there is a - // problem. If there is no problem, it delete the token - $csrf->checkThenDeleteToken ($tokenFromUser); - } - - /** Return the token generated in form - */ - public function getToken () - { - if ($this->csrfToken === "") - $this->createToken (); - return $this->csrfToken; - } - - /** Check if the parameters are correct with the defined fields - * Need the session ! - * @param array $values The values to check - * @param array|null $fields The fields definition (or use the session - * stored one if the value is null) - * @return array containing the errors - */ - public function verify ($values, $fields=array ()) - { - if (count ($fields) === 0) + /** Check the token from the user + * @param string $tokenFromUser The value form the user's token + */ + public function checkToken($tokenFromUser) { - if (! isset ($_SESSION["domframework"]["form"]["fields"])) - return array (); - $fields = $_SESSION["domframework"]["form"]["fields"]; + $csrf = new Csrf(); + $csrf->field = $this->csrfField; + // The checkThenDeleteToken method check the token and except if there is a + // problem. If there is no problem, it delete the token + $csrf->checkThenDeleteToken($tokenFromUser); } - $errors = array (); - foreach ($fields as $field) + + /** Return the token generated in form + */ + public function getToken() { - if ($field->mandatory !== null && - (! array_key_exists ($field->name, $values) || - trim ($values[$field->name]) === "")) - $errors[$field->name] = dgettext ("domframework", - "Field mandatory and not provided"); + if ($this->csrfToken === "") { + $this->createToken(); + } + return $this->csrfToken; } - return $errors; - } - /** If there is at least one error reported in $errors, save the old values - * and the errors in the session, and redirect to the provided url. - * If there is no error, do nothing - * @param array $values The values of the fields filled by the user - * @param array $errors The errors detected by a verify - * @param object $route the route object - * @param string|null $url The URL to redirect. If not provided, use the - * $route->requestURL () method to found the calling page - * - * Example : - $form = new \Domframework\form (); - $form->logging (array ('\apps\general\controllers\logging', 'log'), - $authHTML["email"]); - $values = $form->values (); - $errors = $spaceObj->verify ($values); - $form->redirectIfError ($values, $errors, $route, "/admin/space/"); - $spaceuuid = $spaceObj->spaceCreateConceal ($values["spacename"]); - $route->redirect ("/admin/space/"); - */ - public function redirectIfError ($values, $errors, $route, $url = "") - { - $this->saveValuesErrors ($values, $errors); - if ($url === "") - $url = "/".$route->requestURL (); - if (count ($errors)) $route->redirect ($url); - $this->saveValuesErrorsReset (); - } - - /** Save the values and errors to be displayed in the next page if the session - * is available - * Need the session to work - * @param array $values The values of the fields filled by the user - * @param array|null $errors The errors detected by a verify - */ - public function saveValuesErrors ($values, $errors=array ()) - { - if (isset ($_SESSION)) + /** Check if the parameters are correct with the defined fields + * Need the session ! + * @param array $values The values to check + * @param array|null $fields The fields definition (or use the session + * stored one if the value is null) + * @return array containing the errors + */ + public function verify($values, $fields = array()) { - $_SESSION["domframework"]["form"][$this->formName]["values"] = $values; - $_SESSION["domframework"]["form"][$this->formName]["errors"] = $errors; + if (count($fields) === 0) { + if (! isset($_SESSION["domframework"]["form"]["fields"])) { + return array(); + } + $fields = $_SESSION["domframework"]["form"]["fields"]; + } + $errors = array(); + foreach ($fields as $field) { + if ( + $field->mandatory !== null && + (! array_key_exists($field->name, $values) || + trim($values[$field->name]) === "") + ) { + $errors[$field->name] = dgettext( + "domframework", + "Field mandatory and not provided" + ); + } + } + return $errors; } - } - /** Reset the saved values to provide a clean form next page - * Need the session to work - */ - public function saveValuesErrorsReset () - { - unset ($_SESSION["domframework"]["form"][$this->formName]["values"]); - unset ($_SESSION["domframework"]["form"][$this->formName]["errors"]); - } - - /** Get the stored values if there is one. If there is no stored values, - * return the values provided as parameter - * @param array $values The values returned if there is no stored values - * @return array The values to use - */ - public function getOldValues ($values) - { - if (isset ($_SESSION["domframework"]["form"][$this->formName]["values"])) + /** If there is at least one error reported in $errors, save the old values + * and the errors in the session, and redirect to the provided url. + * If there is no error, do nothing + * @param array $values The values of the fields filled by the user + * @param array $errors The errors detected by a verify + * @param object $route the route object + * @param string|null $url The URL to redirect. If not provided, use the + * $route->requestURL () method to found the calling page + * + * Example : + $form = new \Domframework\form (); + $form->logging (array ('\apps\general\controllers\logging', 'log'), + $authHTML["email"]); + $values = $form->values (); + $errors = $spaceObj->verify ($values); + $form->redirectIfError ($values, $errors, $route, "/admin/space/"); + $spaceuuid = $spaceObj->spaceCreateConceal ($values["spacename"]); + $route->redirect ("/admin/space/"); + */ + public function redirectIfError($values, $errors, $route, $url = "") { - $values = $_SESSION["domframework"]["form"][$this->formName]["values"]; - unset ($_SESSION["domframework"]["form"][$this->formName]["values"]); + $this->saveValuesErrors($values, $errors); + if ($url === "") { + $url = "/" . $route->requestURL(); + } + if (count($errors)) { + $route->redirect($url); + } + $this->saveValuesErrorsReset(); } - return $values; - } - /** Get the stored errors if there is one. If there is no sorted errors, - * return the errors provided as parameter - * @param array $errors The values returned if there is no stored values - * @return array The errors to use - */ - public function getOldErrors ($errors) - { - if (isset ($_SESSION["domframework"]["form"][$this->formName]["errors"])) + /** Save the values and errors to be displayed in the next page if the session + * is available + * Need the session to work + * @param array $values The values of the fields filled by the user + * @param array|null $errors The errors detected by a verify + */ + public function saveValuesErrors($values, $errors = array()) { - $errors = $_SESSION["domframework"]["form"][$this->formName]["errors"]; - unset ($_SESSION["domframework"]["form"][$this->formName]["errors"]); + if (isset($_SESSION)) { + $_SESSION["domframework"]["form"][$this->formName]["values"] = $values; + $_SESSION["domframework"]["form"][$this->formName]["errors"] = $errors; + } } - return $errors; - } - /** Convert Date received in one format to another. - * If the provided string is not corresponding to the format, don't change - * anything. - * Format used http://php.net/manual/en/datetime.createfromformat.php - * @param string $inputDate The date to modify - * @param string $inputFormat The input format of the date - * @param string $outputFormat The output format of the date - * @return string - */ - public function convertDate ($inputDate, $inputFormat, $outputFormat) - { - $date = \DateTime::CreateFromFormat ($inputFormat, $inputDate); - if ($date === false) - return $inputDate; - $errors = $date->getLastErrors(); - if ($errors["warning_count"] > 0 || $errors["error_count"] > 0) - return $inputDate; - return $date->format ($outputFormat); - } + /** Reset the saved values to provide a clean form next page + * Need the session to work + */ + public function saveValuesErrorsReset() + { + unset($_SESSION["domframework"]["form"][$this->formName]["values"]); + unset($_SESSION["domframework"]["form"][$this->formName]["errors"]); + } + + /** Get the stored values if there is one. If there is no stored values, + * return the values provided as parameter + * @param array $values The values returned if there is no stored values + * @return array The values to use + */ + public function getOldValues($values) + { + if (isset($_SESSION["domframework"]["form"][$this->formName]["values"])) { + $values = $_SESSION["domframework"]["form"][$this->formName]["values"]; + unset($_SESSION["domframework"]["form"][$this->formName]["values"]); + } + return $values; + } + + /** Get the stored errors if there is one. If there is no sorted errors, + * return the errors provided as parameter + * @param array $errors The values returned if there is no stored values + * @return array The errors to use + */ + public function getOldErrors($errors) + { + if (isset($_SESSION["domframework"]["form"][$this->formName]["errors"])) { + $errors = $_SESSION["domframework"]["form"][$this->formName]["errors"]; + unset($_SESSION["domframework"]["form"][$this->formName]["errors"]); + } + return $errors; + } + + /** Convert Date received in one format to another. + * If the provided string is not corresponding to the format, don't change + * anything. + * Format used http://php.net/manual/en/datetime.createfromformat.php + * @param string $inputDate The date to modify + * @param string $inputFormat The input format of the date + * @param string $outputFormat The output format of the date + * @return string + */ + public function convertDate($inputDate, $inputFormat, $outputFormat) + { + $date = \DateTime::CreateFromFormat($inputFormat, $inputDate); + if ($date === false) { + return $inputDate; + } + $errors = $date->getLastErrors(); + if ($errors["warning_count"] > 0 || $errors["error_count"] > 0) { + return $inputDate; + } + return $date->format($outputFormat); + } } diff --git a/src/Formfield.php b/src/Formfield.php index a0359b8..227c04b 100644 --- a/src/Formfield.php +++ b/src/Formfield.php @@ -1,4 +1,5 @@ @@ -11,1659 +12,1809 @@ namespace Domframework; */ class Formfield { - /** The form name - */ - public $formName; - /** The name of the field - */ - public $name; - /** The label of the field - */ - public $label; - /** The titles of the field - */ - public $titles; - /** The defaults values of the field - */ - public $defaults; - /** The type of the field (text, password, checkbox, select) - */ - public $type="text"; - /** The state of the field : hidden or show - */ - public $hidden = false; - /** Allow a help message to be displayed below the field. In case of error, - * it is overrided by the error message - */ - public $help; - /** Display the placeholder if needed - */ - public $placeholder = false; - /** The multiplicity of selection of the field (available in select only) - */ - public $multiple; - /** The name of group for the fields - */ - public $group; - /** The read-only feature of the field - */ - public $readonly; - /** The field is mandatory - */ - public $mandatory; - /** The statut of error of the field - */ - public $error; - /** Number of rows - */ - public $rows; - /** Number of columns - */ - public $cols; - /** The Bootstrap width of the column of titles - */ - public $titlewidth = 2; - /** The Bootstrap width of the column of fields - */ - public $fieldwidth = 10; + /** The form name + */ + public $formName; + /** The name of the field + */ + public $name; + /** The label of the field + */ + public $label; + /** The titles of the field + */ + public $titles; + /** The defaults values of the field + */ + public $defaults; + /** The type of the field (text, password, checkbox, select) + */ + public $type = "text"; + /** The state of the field : hidden or show + */ + public $hidden = false; + /** Allow a help message to be displayed below the field. In case of error, + * it is overrided by the error message + */ + public $help; + /** Display the placeholder if needed + */ + public $placeholder = false; + /** The multiplicity of selection of the field (available in select only) + */ + public $multiple; + /** The name of group for the fields + */ + public $group; + /** The read-only feature of the field + */ + public $readonly; + /** The field is mandatory + */ + public $mandatory; + /** The statut of error of the field + */ + public $error; + /** Number of rows + */ + public $rows; + /** Number of columns + */ + public $cols; + /** The Bootstrap width of the column of titles + */ + public $titlewidth = 2; + /** The Bootstrap width of the column of fields + */ + public $fieldwidth = 10; - /** When adding a field, the name and the label are the minimum mandatory - * @param string $name Name of the field - * @param string|null $label Label of the field - */ - public function __construct ($name, $label = "") - { - $this->name = $name; - $this->label = $label; - } - - /** Display really the form - */ - public function display () - { - $func = "field".$this->formTemplate.$this->type; - return $this->$func (); - } - - // Setters for all the properties of the class - /** Set the type of the field - * @param string $val The value of the type of the field - */ - public function type ($val) - { - $this->type = $val; - return $this; - } - - /** Set the hidden of the field - * @param string $val The value of the hidden of the field - */ - public function hidden ($val) - { - $this->hidden = !! $val; - return $this; - } - - /** Set the help of the field - * @param string $val The value of the help of the field - */ - public function help ($val) - { - $this->help = $val; - return $this; - } - - /** Set the placeholder - * @param string $val The value of the placeholder - */ - public function placeholder ($val) - { - $this->placeholder = $val; - return $this; - } - - /** Set the multiple - * @param string $val The value of the multiple - */ - public function multiple ($val) - { - $this->multiple = $val; - return $this; - } - - /** Set the group - * @param string $val The value of the group - */ - public function group ($val) - { - $this->group = $val; - return $this; - } - - /** Set the readonly - * @param string $val The value of the readonly - */ - public function readonly ($val) - { - $this->readonly = !! $val; - return $this; - } - - /** Set the mandatory - * @param string $val The value of the mandatory - */ - public function mandatory ($val) - { - $this->mandatory = !! $val; - return $this; - } - - /** Set the rows - * @param string $val The value of the rows - */ - public function rows ($val) - { - $this->rows = $val; - return $this; - } - - /** Set the cols - * @param string $val The value of the cols - */ - public function cols ($val) - { - $this->cols = $val; - return $this; - } - - ////////////////////////// - //// BOOTSTRAP3 //// - ////////////////////////// - /** Return the checkbox defined - */ - private function fieldBootstrap3checkbox () - { - // No $this->multiple, $this->rows $this->cols $this->placeholder, - // $this->maxlength - if (! is_array ($this->titles) || count ($this->titles) === 0) - $titles = array (""); - else - $titles = $this->titles; - $res = ""; - $res .= "
                \n"; - if ($this->label !== "") + /** When adding a field, the name and the label are the minimum mandatory + * @param string $name Name of the field + * @param string|null $label Label of the field + */ + public function __construct($name, $label = "") { - $res .= " \n"; + $this->name = $name; + $this->label = $label; } - $res .= "
                \n"; - foreach ($titles as $key=>$val) + + /** Display really the form + */ + public function display() { - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]"; - if (count ($titles) > 1) - $res .= "[$key]"; - $res .= "' value='unset'"; - $res .= "/>"; - $res .= "
                \n"; // End form-group + return $res; } - if (isset ($this->errors) || isset ($this->help)) + /** Return the hidden field defined + */ + private function fieldBootstrap3hidden() { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; + $res = ""; + // No $this->label, $this->multiple, $this->readonly, $this->hidden, + // $this->rows $this->cols $this->placeholder $this->maxlength + $res .= "name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars($this->values) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults) . "'"; + } + $res .= "/>\n"; + return $res; } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - /** Return the hidden field defined - */ - private function fieldBootstrap3hidden () - { - $res = ""; - // No $this->label, $this->multiple, $this->readonly, $this->hidden, - // $this->rows $this->cols $this->placeholder $this->maxlength - $res .= "name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults)."'"; - $res .= "/>\n"; - return $res; - } - - /** Return the password field defined - */ - private function fieldBootstrap3password () - { - $res = ""; - // No $this->multiple, $this->rows $this->cols - $res .= "
                \n"; - if ($this->label !== "") + /** Return the password field defined + */ + private function fieldBootstrap3password() { - $res .= " \n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values, - ENT_QUOTES)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). + $res = ""; + // No $this->multiple, $this->rows $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " \n"; + } + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars( + $this->values, + ENT_QUOTES + ) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . "'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (isset ($this->cols)) - $res .= " size='".$this->cols."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (isset($this->cols)) { + $res .= " size='" . $this->cols . "'"; + } + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->errors) || isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . "'"; - $res .= "/>\n"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the radio field defined - */ - private function fieldBootstrap3radio () - { - $res = ""; - // No $this->multiple, $this->rows $this->cols $this->placeholder - // $this->maxlength - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " \n"; - } - $res .= "
                \n"; - if (is_string ($this->defaults)) - $this->defaults = array ($this->defaults); - $res .= " name, ENT_QUOTES)."]'"; - $res .= " value='unset'"; - $res .= "/>\n"; - foreach ($this->titles as $key=>$val) - { - $res .= "
                "; - $res .= " \n"; // End label radio - $res .= "
                "; - } - - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the checkbox defined - */ - private function fieldBootstrap3select () - { - // No $this->placeholder $this->maxlength - $res = ""; - // $values->$this, $this->cols - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " \n"; - } - $res .= "
                \n"; - if (isset ($this->defaults) && is_array ($this->defaults)) - { - if (isset ($this->readonly) && $this->readonly !== FALSE) - { - foreach ($this->defaults as $key=>$val) - { - $res .= " multiple) && $this->multiple !== FALSE) - { - $res .= " name='$this->formName"."["; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."][". - htmlspecialchars ($key, ENT_QUOTES)."]'"; - } - else - { - $res .= " name='$this->formName"."["; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."]'"; - } - $res .= " value='"; - $res .= htmlspecialchars ($key, ENT_QUOTES)."'"; - $res .= "/>\n"; } - } - - $res .= " name, ENT_QUOTES)."]"; - if (isset ($this->multiple) && $this->multiple !== FALSE) - $res .= "[]"; - $res .= "'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->multiple) && $this->multiple !== FALSE) - $res .= " multiple='multiple'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " disabled='disabled'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= " class='form-control'"; - if (isset ($this->rows)) - $res .= " size='".$this->rows."'"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - $res .= ">\n"; - foreach ($this->defaults as $key=>$val) - { - if (! is_string ($val)) - { - throw new \Exception ("Value as defaut for $this->name::$key is not ". - "a string (".gettype ($val).")"); + $res .= "/>\n"; + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; } - $res .= " \n"; - } - - $res .= " \n"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - else + + /** Return the radio field defined + */ + private function fieldBootstrap3radio() { - $res .= dgettext ("domframework", "No value provided"); + $res = ""; + // No $this->multiple, $this->rows $this->cols $this->placeholder + // $this->maxlength + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " \n"; + } + $res .= "
                \n"; + if (is_string($this->defaults)) { + $this->defaults = array($this->defaults); + } + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " value='unset'"; + $res .= "/>\n"; + foreach ($this->titles as $key => $val) { + $res .= "
                "; + $res .= " \n"; // End label radio + $res .= "
                "; + } + + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } + /** Return the checkbox defined + */ + private function fieldBootstrap3select() + { + // No $this->placeholder $this->maxlength + $res = ""; + // $values->$this, $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " \n"; + } + $res .= "
                \n"; + if (isset($this->defaults) && is_array($this->defaults)) { + if (isset($this->readonly) && $this->readonly !== false) { + foreach ($this->defaults as $key => $val) { + $res .= " multiple) && $this->multiple !== false) { + $res .= " name='$this->formName" . "["; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "][" . + htmlspecialchars($key, ENT_QUOTES) . "]'"; + } else { + $res .= " name='$this->formName" . "["; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "]'"; + } + $res .= " value='"; + $res .= htmlspecialchars($key, ENT_QUOTES) . "'"; + $res .= "/>\n"; + } + } - /** Return the submit defined - */ - private function fieldBootstrap3submit () - { - $res = ""; - // No $this->label, $this->multiple, $this->error, $this->rows, - // $this->cols $this->placeholder $this->maxlength - $res .= "
                \n"; - $res .= "
                formName" . "["; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "]"; + if (isset($this->multiple) && $this->multiple !== false) { + $res .= "[]"; + } + $res .= "'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->multiple) && $this->multiple !== false) { + $res .= " multiple='multiple'"; + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " disabled='disabled'"; + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= " class='form-control'"; + if (isset($this->rows)) { + $res .= " size='" . $this->rows . "'"; + } + if (isset($this->errors) || isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + $res .= ">\n"; + foreach ($this->defaults as $key => $val) { + if (! is_string($val)) { + throw new \Exception("Value as defaut for $this->name::$key is not " . + "a string (" . gettype($val) . ")"); + } + $res .= " \n"; + } + + $res .= " \n"; + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; + } + } else { + $res .= dgettext("domframework", "No value provided"); + } + + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; + } + + /** Return the submit defined + */ + private function fieldBootstrap3submit() + { + $res = ""; + // No $this->label, $this->multiple, $this->error, $this->rows, + // $this->cols $this->placeholder $this->maxlength + $res .= "
                \n"; + $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " disabled='disabled'"; - if (isset ($this->defaults)) - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " disabled='disabled'"; + } + if (isset($this->defaults)) { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . "'"; - elseif (isset ($this->label)) - $res .= " value='".htmlspecialchars ($this->label, ENT_QUOTES)."'"; - $res .= " class='form-control btn-primary'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - // Block the submit button 10s. The user can not double click on it and - // submit two times the POST to the server - // Re-enable after 15s, if there is a problem with the server - // This code is needed by Chrome and Edge which allow multiple submission of - // a form - $res .= " onclick='submit=this ; "; - $res .= " setTimeout(function() {"; - $res .= " submit.setAttribute(\"disabled\", \"disabled\");"; - $res .= " }, 1);"; - $res .= "'"; - $res .= "/>\n"; - $res .= "
                \n"; - $res .= "
                \n"; - return $res; - } - - /** Return the textarea defined - */ - private function fieldBootstrap3textarea () - { - $res = ""; - // No $this->multiple, $this->titles - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " \n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (!isset ($this->cols)) - $this->cols = 20; - $res .= " cols='".$this->cols."'"; - if (!isset ($this->rows)) - $this->rows = 4; - $res .= " rows='".$this->rows."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). - "'"; - $res .= ">"; - if (isset ($this->values)) - $res .= htmlspecialchars ($this->values, ENT_QUOTES); - else - $res .= htmlspecialchars ($this->defaults, ENT_QUOTES); - $res .= "\n"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the text defined - */ - private function fieldBootstrap3text () - { - $res = ""; - // No $this->multiple, $this->titles, $this->rows, $this->cols - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " \n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values, - ENT_QUOTES)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). - "'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (isset ($this->cols)) - $res .= " size='".$this->cols."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). - "'"; - $res .= "/>\n"; - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the file defined - */ - private function fieldBootstrap3file () - { - $res = ""; - // No $this->multiple, $this->titles, $this->rows, $this->cols - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " \n"; - } - $res .= "
                \n"; - if (isset ($this->defaults)) - { - $res .= " \n"; // End labels - if (isset ($this->errors) || isset ($this->help)) - { - $res .= " "; - if (isset ($this->help)) - $res .= "".$this->help.""; - if (isset ($this->help) && isset ($this->errors)) - $res .= "
                "; - if (isset ($this->errors)) - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - ////////////////////////// - //// BOOTSTRAP4 //// - ////////////////////////// - /** Return the checkbox defined - */ - private function fieldBootstrap4checkbox () - { - // No $this->multiple, $this->rows $this->cols $this->placeholder, - // $this->maxlength - if (! is_array ($this->titles) || count ($this->titles) === 0) - $this->titles = array (""); - $res = ""; - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - if (is_array ($this->titles) && count ($this->titles) == 1 && - reset ($this->titles) === "") - { - // If more than one title is set, the main label is unusable, so - // do not link it to the checkbox - // If there is no label on the checkbox, this label must be set - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES); + } elseif (isset($this->label)) { + $res .= " value='" . htmlspecialchars($this->label, ENT_QUOTES) . "'"; + } + $res .= " class='form-control btn-primary'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + // Block the submit button 10s. The user can not double click on it and + // submit two times the POST to the server + // Re-enable after 15s, if there is a problem with the server + // This code is needed by Chrome and Edge which allow multiple submission of + // a form + $res .= " onclick='submit=this ; "; + $res .= " setTimeout(function() {"; + $res .= " submit.setAttribute(\"disabled\", \"disabled\");"; + $res .= " }, 1);"; $res .= "'"; - } - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; + $res .= "/>\n"; + $res .= "
                \n"; + $res .= "
                \n"; + return $res; } - $res .= "
                \n"; - foreach ($this->titles as $key=>$val) + + /** Return the textarea defined + */ + private function fieldBootstrap3textarea() { - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]"; - if (count ($this->titles) > 1) - $res .= "[$key]"; - $res .= "' value='unset'"; - $res .= "/>\n"; - $res .= " name, ENT_QUOTES)."]"; - if (count ($this->titles) > 1) - $res .= "[$key]"; - $res .= "' id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES); - if (count ($this->titles) > 1) - $res .= "_$key"; - $res .= "'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " disabled='disabled'"; - // Do not check by default ! - // Check is enable if not null and not false and not "unset" and not "" - if (count ($this->titles) === 1) - { - if (isset ($this->values) && - $this->values !== null && - $this->values !== false && - $this->values !== "unset" && - $this->values !== "") - $res .= " checked='checked'"; - elseif (isset ($this->defaults) && - $this->defaults !== null && - $this->defaults !== false && - $this->defaults !== "unset" && - $this->defaults !== "") - $res .= " checked='checked'"; - } - else - { - if (isset ($this->values[$key])) - { - if ($this->values[$key] !== null && - $this->values[$key] !== false && - $this->values[$key] !== "unset" && - $this->values[$key] !== "") - $res .= " checked='checked'"; + $res = ""; + // No $this->multiple, $this->titles + $res .= "
                label !== "") { + $res .= " \n"; } - } - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= " class='form-check-input"; - if (isset ($this->errors)) - { - $res .= " is-invalid"; - } - $res .= "'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - $res .= "/>\n"; - $res .= "
                \n"; - } - - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the hidden field defined - */ - private function fieldBootstrap4hidden () - { - $res = ""; - // No $this->label, $this->multiple, $this->readonly, $this->hidden, - // $this->rows $this->cols $this->placeholder $this->maxlength - $res .= "name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults)."'"; - $res .= "/>\n"; - return $res; - } - - /** Return the password field defined - */ - private function fieldBootstrap4password () - { - $res = ""; - // No $this->multiple, $this->rows $this->cols - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values, - ENT_QUOTES)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (!isset($this->cols)) { + $this->cols = 20; + } + $res .= " cols='" . $this->cols . "'"; + if (!isset($this->rows)) { + $this->rows = 4; + } + $res .= " rows='" . $this->rows . "'"; + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->errors) || isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . "'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control"; - if (isset ($this->errors)) - $res .= " is-invalid"; - $res .= "'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (isset ($this->cols)) - $res .= " size='".$this->cols."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). - "'"; - $res .= "/>\n"; - if (isset ($this->errors)) - { - $res .= "
                "; - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the radio field defined - */ - private function fieldBootstrap4radio () - { - $res = ""; - // No $this->multiple, $this->rows $this->cols $this->placeholder - // $this->maxlength - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - if (is_array ($this->titles) && count ($this->titles) == 1 && - reset ($this->titles) === "") - { - // If more than one title is set, the main label is unusable, so - // do not link it to the radio - // If there is no label on the checkbox, this label must be set - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES); - $res .= "'"; - } - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - if (is_string ($this->defaults)) - $this->defaults = array ($this->defaults); - $res .= " name, ENT_QUOTES)."]'"; - $res .= " value='unset'"; - $res .= "/>\n"; - foreach ($this->titles as $key=>$val) - { - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_$key'"; - $res .= " value='".htmlspecialchars ($val, ENT_QUOTES)."'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - if (isset ($this->values) && - $this->values === $val) - $res .= " checked='checked'"; - elseif (isset ($this->defaults[0]) && - $this->defaults[0] === $val) - $res .= " checked='checked'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= " class='form-check-input"; - if (isset ($this->errors)) - $res .= " is-invalid"; - $res .= "'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - $res .= "/>\n"; - $res .= " \n"; // End label radio - if (isset ($this->errors) && $key === count ($this->titles) - 1) - { - $res .= "
                "; - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - $res .= "
                \n"; - } - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - - /** Return the checkbox defined - */ - private function fieldBootstrap4select () - { - // No $this->placeholder $this->maxlength - $res = ""; - // $values->$this, $this->cols - $res .= "
                \n"; - if ($this->label !== "") - { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - if (isset ($this->defaults) && is_array ($this->defaults)) - { - if (isset ($this->readonly) && $this->readonly !== FALSE) - { - foreach ($this->defaults as $key=>$val) - { - $res .= " multiple) && $this->multiple !== FALSE) - { - $res .= " name='$this->formName"."["; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."][". - htmlspecialchars ($key, ENT_QUOTES)."]'"; - } - else - { - $res .= " name='$this->formName"."["; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."]'"; - } - $res .= " value='"; - $res .= htmlspecialchars ($key, ENT_QUOTES)."'"; - $res .= "/>\n"; } - } - - $res .= " name, ENT_QUOTES)."]"; - if (isset ($this->multiple) && $this->multiple !== FALSE) - $res .= "[]"; - $res .= "'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->multiple) && $this->multiple !== FALSE) - $res .= " multiple='multiple'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " disabled='disabled'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= " class='form-control"; - if (isset ($this->errors)) - $res .= " is-invalid"; - $res .= "'"; - if (isset ($this->rows)) - $res .= " size='".$this->rows."'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - $res .= ">\n"; - foreach ($this->defaults as $key=>$val) - { - if (! is_string ($val)) - { - throw new \Exception ("Value as defaut for $this->name::$key is not ". - "a string (".gettype ($val).")"); - } - $res .= " \n"; - } - - $res .= " \n"; - if (isset ($this->errors)) - { - $res .= "
                "; - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; - } - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } + if (isset($this->values)) { + $res .= htmlspecialchars($this->values, ENT_QUOTES); + } else { + $res .= htmlspecialchars($this->defaults, ENT_QUOTES); + } + $res .= "\n"; + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - else + + /** Return the text defined + */ + private function fieldBootstrap3text() { - $res .= dgettext ("domframework", "No value provided"); + $res = ""; + // No $this->multiple, $this->titles, $this->rows, $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " \n"; + } + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars( + $this->values, + ENT_QUOTES + ) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . + "'"; + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (isset($this->cols)) { + $res .= " size='" . $this->cols . "'"; + } + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->errors) || isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . + "'"; + } + $res .= "/>\n"; + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } + /** Return the file defined + */ + private function fieldBootstrap3file() + { + $res = ""; + // No $this->multiple, $this->titles, $this->rows, $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " \n"; + } + $res .= "
                \n"; + if (isset($this->defaults)) { + $res .= " \n"; + } // End labels + if (isset($this->errors) || isset($this->help)) { + $res .= " "; + if (isset($this->help)) { + $res .= "" . $this->help . ""; + } + if (isset($this->help) && isset($this->errors)) { + $res .= "
                "; + } + if (isset($this->errors)) { + $res .= htmlspecialchars($this->errors[1]); + } + $res .= "
                \n"; + } - /** Return the submit defined - */ - private function fieldBootstrap4submit () - { - $res = ""; - // No $this->label, $this->multiple, $this->error, $this->rows, - // $this->cols $this->placeholder $this->maxlength - $res .= "
                \n"; - $res .= "
                errors)) { + $res .= " has-" . $this->errors[0]; + } + if ($this->titlewidth > 0) { + $res .= " row"; + } + $res .= "'>\n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + if ( + is_array($this->titles) && count($this->titles) == 1 && + reset($this->titles) === "" + ) { + // If more than one title is set, the main label is unusable, so + // do not link it to the checkbox + // If there is no label on the checkbox, this label must be set + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES); + $res .= "'"; + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + foreach ($this->titles as $key => $val) { + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]"; + if (count($this->titles) > 1) { + $res .= "[$key]"; + } + $res .= "' value='unset'"; + $res .= "/>\n"; + $res .= " name, ENT_QUOTES) . "]"; + if (count($this->titles) > 1) { + $res .= "[$key]"; + } + $res .= "' id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES); + if (count($this->titles) > 1) { + $res .= "_$key"; + } + $res .= "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " disabled='disabled'"; + } + // Do not check by default ! + // Check is enable if not null and not false and not "unset" and not "" + if (count($this->titles) === 1) { + if ( + isset($this->values) && + $this->values !== null && + $this->values !== false && + $this->values !== "unset" && + $this->values !== "" + ) { + $res .= " checked='checked'"; + } elseif ( + isset($this->defaults) && + $this->defaults !== null && + $this->defaults !== false && + $this->defaults !== "unset" && + $this->defaults !== "" + ) { + $res .= " checked='checked'"; + } + } else { + if (isset($this->values[$key])) { + if ( + $this->values[$key] !== null && + $this->values[$key] !== false && + $this->values[$key] !== "unset" && + $this->values[$key] !== "" + ) { + $res .= " checked='checked'"; + } + } elseif (isset($this->defaults[$key])) { + if ( + $this->defaults[$key] !== null && + $this->defaults[$key] !== false && + $this->defaults[$key] !== "unset" && + $this->defaults[$key] !== "" + ) { + $res .= " checked='checked'"; + } + } + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= " class='form-check-input"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + $res .= "/>\n"; + $res .= "
                \n"; + } + + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; + } + + /** Return the hidden field defined + */ + private function fieldBootstrap4hidden() + { + $res = ""; + // No $this->label, $this->multiple, $this->readonly, $this->hidden, + // $this->rows $this->cols $this->placeholder $this->maxlength + $res .= "name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars($this->values) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults) . "'"; + } + $res .= "/>\n"; + return $res; + } + + /** Return the password field defined + */ + private function fieldBootstrap4password() + { + $res = ""; + // No $this->multiple, $this->rows $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars( + $this->values, + ENT_QUOTES + ) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . + "'"; + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (isset($this->cols)) { + $res .= " size='" . $this->cols . "'"; + } + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . + "'"; + } + $res .= "/>\n"; + if (isset($this->errors)) { + $res .= "
                "; + $res .= htmlspecialchars($this->errors[1]); + $res .= "
                \n"; + } + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; + } + + /** Return the radio field defined + */ + private function fieldBootstrap4radio() + { + $res = ""; + // No $this->multiple, $this->rows $this->cols $this->placeholder + // $this->maxlength + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + if ( + is_array($this->titles) && count($this->titles) == 1 && + reset($this->titles) === "" + ) { + // If more than one title is set, the main label is unusable, so + // do not link it to the radio + // If there is no label on the checkbox, this label must be set + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES); + $res .= "'"; + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + if (is_string($this->defaults)) { + $this->defaults = array($this->defaults); + } + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " value='unset'"; + $res .= "/>\n"; + foreach ($this->titles as $key => $val) { + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_$key'"; + $res .= " value='" . htmlspecialchars($val, ENT_QUOTES) . "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + if ( + isset($this->values) && + $this->values === $val + ) { + $res .= " checked='checked'"; + } elseif ( + isset($this->defaults[0]) && + $this->defaults[0] === $val + ) { + $res .= " checked='checked'"; + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= " class='form-check-input"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + $res .= "/>\n"; + $res .= " \n"; // End label radio + if (isset($this->errors) && $key === count($this->titles) - 1) { + $res .= "
                "; + $res .= htmlspecialchars($this->errors[1]); + $res .= "
                \n"; + } + $res .= "
                \n"; + } + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; + } + + /** Return the checkbox defined + */ + private function fieldBootstrap4select() + { + // No $this->placeholder $this->maxlength + $res = ""; + // $values->$this, $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + if (isset($this->defaults) && is_array($this->defaults)) { + if (isset($this->readonly) && $this->readonly !== false) { + foreach ($this->defaults as $key => $val) { + $res .= " multiple) && $this->multiple !== false) { + $res .= " name='$this->formName" . "["; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "][" . + htmlspecialchars($key, ENT_QUOTES) . "]'"; + } else { + $res .= " name='$this->formName" . "["; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "]'"; + } + $res .= " value='"; + $res .= htmlspecialchars($key, ENT_QUOTES) . "'"; + $res .= "/>\n"; + } + } + + $res .= " name, ENT_QUOTES) . "]"; + if (isset($this->multiple) && $this->multiple !== false) { + $res .= "[]"; + } + $res .= "'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->multiple) && $this->multiple !== false) { + $res .= " multiple='multiple'"; + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " disabled='disabled'"; + } + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= " class='form-control"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->rows)) { + $res .= " size='" . $this->rows . "'"; + } + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + $res .= ">\n"; + foreach ($this->defaults as $key => $val) { + if (! is_string($val)) { + throw new \Exception("Value as defaut for $this->name::$key is not " . + "a string (" . gettype($val) . ")"); + } + $res .= " \n"; + } + + $res .= " \n"; + if (isset($this->errors)) { + $res .= "
                "; + $res .= htmlspecialchars($this->errors[1]); + $res .= "
                \n"; + } + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + } else { + $res .= dgettext("domframework", "No value provided"); + } + + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; + } + + /** Return the submit defined + */ + private function fieldBootstrap4submit() + { + $res = ""; + // No $this->label, $this->multiple, $this->error, $this->rows, + // $this->cols $this->placeholder $this->maxlength + $res .= "
                \n"; + $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " disabled='disabled'"; - if (isset ($this->defaults)) - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " disabled='disabled'"; + } + if (isset($this->defaults)) { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . "'"; - elseif (isset ($this->label)) - $res .= " value='".htmlspecialchars ($this->label, ENT_QUOTES)."'"; - $res .= " class='form-control btn-primary'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - // Block the submit button 10s. The user can not double click on it and - // submit two times the POST to the server - // Re-enable after 15s, if there is a problem with the server - // This code is needed by Chrome and Edge which allow multiple submission of - // a form - $res .= " onclick='submit=this ; "; - $res .= " setTimeout(function() {"; - $res .= " submit.setAttribute(\"disabled\", \"disabled\");"; - $res .= " }, 1);"; - $res .= "'"; - $res .= "/>\n"; - $res .= "
                \n"; - $res .= "
                \n"; - return $res; - } + } elseif (isset($this->label)) { + $res .= " value='" . htmlspecialchars($this->label, ENT_QUOTES) . "'"; + } + $res .= " class='form-control btn-primary'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + // Block the submit button 10s. The user can not double click on it and + // submit two times the POST to the server + // Re-enable after 15s, if there is a problem with the server + // This code is needed by Chrome and Edge which allow multiple submission of + // a form + $res .= " onclick='submit=this ; "; + $res .= " setTimeout(function() {"; + $res .= " submit.setAttribute(\"disabled\", \"disabled\");"; + $res .= " }, 1);"; + $res .= "'"; + $res .= "/>\n"; + $res .= "
                \n"; + $res .= "
                \n"; + return $res; + } - /** Return the textarea defined - */ - private function fieldBootstrap4textarea () - { - $res = ""; - // No $this->multiple, $this->titles - $res .= "
                \n"; - if ($this->label !== "") + /** Return the textarea defined + */ + private function fieldBootstrap4textarea() { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control"; - if (isset ($this->errors)) - $res .= " is-invalid"; - $res .= "'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (!isset ($this->cols)) - $this->cols = 20; - $res .= " cols='".$this->cols."'"; - if (!isset ($this->rows)) - $this->rows = 4; - $res .= " rows='".$this->rows."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). + $res = ""; + // No $this->multiple, $this->titles + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (!isset($this->cols)) { + $this->cols = 20; + } + $res .= " cols='" . $this->cols . "'"; + if (!isset($this->rows)) { + $this->rows = 4; + } + $res .= " rows='" . $this->rows . "'"; + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . "'"; - $res .= ">"; - if (isset ($this->values)) - $res .= htmlspecialchars ($this->values, ENT_QUOTES); - else - $res .= htmlspecialchars ($this->defaults, ENT_QUOTES); - $res .= "\n"; - if (isset ($this->errors)) - { - $res .= "
                "; - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; + } + $res .= ">"; + if (isset($this->values)) { + $res .= htmlspecialchars($this->values, ENT_QUOTES); + } else { + $res .= htmlspecialchars($this->defaults, ENT_QUOTES); + } + $res .= "\n"; + if (isset($this->errors)) { + $res .= "
                "; + $res .= htmlspecialchars($this->errors[1]); + $res .= "
                \n"; + } + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - /** Return the text defined - */ - private function fieldBootstrap4text () - { - $res = ""; - // No $this->multiple, $this->titles, $this->rows, $this->cols - $res .= "
                \n"; - if ($this->label !== "") + /** Return the text defined + */ + private function fieldBootstrap4text() { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - $res .= " name, ENT_QUOTES)."]'"; - $res .= " id='$this->formName"."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->values)) - $res .= " value='".htmlspecialchars ($this->values, - ENT_QUOTES)."'"; - else - $res .= " value='".htmlspecialchars ($this->defaults, ENT_QUOTES). + $res = ""; + // No $this->multiple, $this->titles, $this->rows, $this->cols + $res .= "
                \n"; + if ($this->label !== "") { + $res .= " titlewidth > 0) { + $res .= " class='col-sm-$this->titlewidth col-form-label'"; + } + $res .= " for='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + $res .= ">"; + $res .= htmlspecialchars($this->label); + if (isset($this->mandatory) && $this->mandatory !== false) { + $res .= " *"; + } else { + $res .= " "; + } + $res .= "\n"; + } + $res .= "
                \n"; + $res .= " name, ENT_QUOTES) . "]'"; + $res .= " id='$this->formName" . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "'"; + if (isset($this->values)) { + $res .= " value='" . htmlspecialchars( + $this->values, + ENT_QUOTES + ) . "'"; + } else { + $res .= " value='" . htmlspecialchars($this->defaults, ENT_QUOTES) . "'"; - if (isset ($this->readonly) && $this->readonly !== FALSE) - $res .= " readonly='readonly'"; - $res .= " class='form-control"; - if (isset ($this->errors)) - $res .= " is-invalid"; - $res .= "'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - if (isset ($this->cols)) - $res .= " size='".$this->cols."'"; - if (isset ($this->maxlength)) - $res .= " maxlength='".$this->maxlength."'"; - if (isset ($this->help)) - { - $res .= " aria-describedby='".$this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."_help'"; - } - if (isset ($this->placeholder) && $this->placeholder !== FALSE) - $res .= " placeholder='".htmlentities ($this->placeholder, ENT_QUOTES). + } + if (isset($this->readonly) && $this->readonly !== false) { + $res .= " readonly='readonly'"; + } + $res .= " class='form-control"; + if (isset($this->errors)) { + $res .= " is-invalid"; + } + $res .= "'"; + if (isset($this->hidden) && $this->hidden !== false) { + $res .= " style='display:none'"; + } + if (isset($this->cols)) { + $res .= " size='" . $this->cols . "'"; + } + if (isset($this->maxlength)) { + $res .= " maxlength='" . $this->maxlength . "'"; + } + if (isset($this->help)) { + $res .= " aria-describedby='" . $this->formName . "_"; + $res .= htmlspecialchars($this->name, ENT_QUOTES) . "_help'"; + } + if (isset($this->placeholder) && $this->placeholder !== false) { + $res .= " placeholder='" . htmlentities($this->placeholder, ENT_QUOTES) . "'"; - $res .= "/>\n"; - if (isset ($this->errors)) - { - $res .= "
                "; - $res .= htmlspecialchars ($this->errors[1]); - $res .= "
                \n"; + } + $res .= "/>\n"; + if (isset($this->errors)) { + $res .= "
                "; + $res .= htmlspecialchars($this->errors[1]); + $res .= "
                \n"; + } + if (isset($this->help)) { + $res .= " name, ENT_QUOTES) . "_help'>"; + $res .= $this->help; + $res .= "\n"; + } + $res .= "
                \n"; // End controls + $res .= "
                \n"; // End form-group + return $res; } - if (isset ($this->help)) - { - $res .= " name, ENT_QUOTES)."_help'>"; - $res .= $this->help; - $res .= "\n"; - } - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - /** Return the file defined - */ - private function fieldBootstrap4file () - { - $res = ""; - // No $this->multiple, $this->titles, $this->rows, $this->cols - $res .= "
                \n"; - if ($this->label !== "") + /** Return the file defined + */ + private function fieldBootstrap4file() { - $res .= " titlewidth > 0) - $res .= " class='col-sm-$this->titlewidth col-form-label'"; - $res .= " for='". $this->formName."_"; - $res .= htmlspecialchars ($this->name, ENT_QUOTES)."'"; - if (isset ($this->hidden) && $this->hidden !== FALSE) - $res .= " style='display:none'"; - $res .= ">"; - $res .= htmlspecialchars ($this->label); - if (isset ($this->mandatory) && $this->mandatory !== FALSE) - $res .= " *"; - else - $res .= " "; - $res .= "\n"; - } - $res .= "
                \n"; - if (isset ($this->defaults)) - { - $res .= "
                \n"; // End controls - $res .= "
                \n"; // End form-group - return $res; - } - } diff --git a/src/Fts.php b/src/Fts.php index 6203f3f..b834e54 100644 --- a/src/Fts.php +++ b/src/Fts.php @@ -1,4 +1,5 @@ @@ -18,341 +19,383 @@ namespace Domframework; */ class Fts { - /////////////////////////// - //// PROPERTIES //// - /////////////////////////// - /** The minimum length of a token to search - */ - public $minLength = 3; + /////////////////////////// + //// PROPERTIES //// + /////////////////////////// + /** The minimum length of a token to search + */ + public $minLength = 3; - /** The tokens found in the query, with the minus state if the user do not - * want the provided token - */ - private $tokens = null; + /** The tokens found in the query, with the minus state if the user do not + * want the provided token + */ + private $tokens = null; - /** The tokens without the too small tokens - */ - private $tokensMin =null; + /** The tokens without the too small tokens + */ + private $tokensMin = null; - /** The regexes created by the parser - */ - private $regexes = null; + /** The regexes created by the parser + */ + private $regexes = null; - /** The callable method to run on each word of the query - */ - private $callTokenWord = null; + /** The callable method to run on each word of the query + */ + private $callTokenWord = null; - /** The callable method to run on each sentence of the query - */ - private $callTokenSentence = null; + /** The callable method to run on each sentence of the query + */ + private $callTokenSentence = null; - //////////////////////////// - //// CONSTRUCTOR //// - //////////////////////////// - /** The constructor check the availability of the MB module - */ - public function __construct () - { - if (! function_exists ("mb_strlen")) - throw new \Exception ("PHP don't have the MB Support. Please add it !", - 500); - } - - //////////////////////// - //// GETTERS //// - //////////////////////// - /** Get the tokens store after the search - */ - public function getTokens () - { - return $this->tokens; - } - - /** Get the tokens store after the search, without the too small ones - */ - public function getTokensMin () - { - return $this->tokensMin; - } - - /** Get the regexes defined after the analyzer - */ - public function getRegexes () - { - return $this->regexes; - } - - /** Set the method to call on tokens word only - * The method must return the token updated - * @param callable $callable The callable method - * @return $this - */ - public function callTokenWord ($callable) - { - if (! is_callable ($callable)) - throw new \Exception (dgettext ("domframework", - "SSE : callTokenWord : provided method is not callable"), 500); - $this->callTokenWord = $callable; - return $this; - } - - /** Set the method to call on tokens sentence only - * The method must return the token updated - * @param callable $callable The callable method - * @return $this - */ - public function callTokenSentence ($callable) - { - if (! is_callable ($callable)) - throw new \Exception (dgettext ("domframework", - "SSE : callTokenSentence : provided method is not callable"), 500); - $this->callTokenSentence = $callable; - return $this; - } - - ////////////////////////////// - //// PUBLIC METHODS //// - ////////////////////////////// - /** Explode the query text provided in $query, to be used to search in - * database, file... - * @param string $query The text to found in the database - * @return array The operator and the associated regex value to search - */ - public function search ($query) - { - $query = trim ($query); - $this->tokens = $this->tokenizer ($query); - foreach ($this->tokens["tokens"] as $key => &$token) + //////////////////////////// + //// CONSTRUCTOR //// + //////////////////////////// + /** The constructor check the availability of the MB module + */ + public function __construct() { - if ($this->tokens["sentences"][$key] === true && $this->callTokenSentence) - $token = call_user_func ($this->callTokenSentence, $token); - elseif ($this->tokens["sentences"][$key] === false && - $this->callTokenWord) - $token = call_user_func ($this->callTokenWord, $token); - } - $this->tokensMin = $this->tokenMinLength ($this->tokens["tokens"], - $this->tokens["minuses"]); - $this->regexes = $this->regex ($this->tokensMin["tokens"], - $this->tokensMin["minuses"]); - return $this->regexes; - } - - /** Construct the query based on the tokens. - * The tokens can be updated by methods so the query may be modified by the - * external methods - * @return string - */ - public function getQuery () - { - $res = ""; - foreach ($this->tokens["tokens"] as $key => $token) - { - if ($key > 0) - $res .= " "; - if ($this->tokens["sentences"][$key] === true) - $res .= "\"$token\""; - else - $res .= "$token"; - } - return $res; - } - - /** Return $line if the $query match against $line, or false if not - * @param string $line The line to examine - * @param string $query The query to apply on it - * @return string|false The $line if match, false - */ - public function searchString ($line, $query) - { - $regexes = $this->search ($query); - if (empty ($this->tokens)) - return false; - foreach ($this->tokens["tokens"] as $key => $searchPart) - { - if (trim ($searchPart) === "") - continue; - $match = (strpos ($line, $searchPart) !== false); - if ($this->tokens["minuses"][$key] === "" && $match == 0) - return false; - if ($this->tokens["minuses"][$key] === "-" && $match == 1) - return false; - } - return $line; - } - - /** Search in SQL - * @param string $query The text to found in the database - * @param object $dblayeroo The dblayeroo object to query - * @param array|null $fields The fields in $dblayeroo to look for data. If - * null, look in all the fields defined in the dblayeroo object - * @return array The result of the query - */ - public function searchSQL ($query, $dblayeroo, $fields) - { - $regexes = $this->search ($query); - if (empty ($regexes["operator"])) - return array (); - // Clone the object to not modify a previously defined query - $dbl = clone $dblayeroo; - $dbl->clearRequest (); - $dbl->select (); - if ($fields === null) - $fields = array_keys ($dbl->fields ()); - $i = 0; - foreach ($fields as $field) - { - if (! array_key_exists ($field, $dbl->fields ())) - throw new \Exception (sprintf (dgettext ("domframework", - "The field '%s' doesn't exists in database"), $field), 500); - if ($i > 0) - $dbl->whereAddOR (); - $dbl->whereAddParenthesisOpen (); - $j = 0; - foreach ($regexes["operator"] as $key=>$operator) - { - if ($j > 0) - $dbl->whereAddAND (); - $dbl->whereAdd ($field, $operator, $regexes["value"][$key]); - $j++; - } - $dbl->whereAddParenthesisClose (); - $i++; - } - // Look for the order by date if provided - foreach ($dbl->fields () as $field=>$params) - { - if ($params[0] == "date" || $params[0] == "datetime" || - $params[0] == "time") - { - $dbl->orderAdd ($field, "DESC"); - break; - } - } - return $dbl->execute (); - } - - /////////////////////////////// - //// PRIVATE METHODS //// - /////////////////////////////// - /** Create the regex associated to the provided tokens and minuses - * @param array $tokens The token list - * @param array $minuses The minuses list - * @return array The operator and the associated regex value to search - */ - private function regex ($tokens, $minuses) - { - if (! is_array ($tokens)) - throw new \Exception ("Invalid tokens provided to fts:tokenMinLength", - 500); - if (! is_array ($minuses)) - throw new \Exception ("Invalid minuses provided to fts:tokenMinLength", - 500); - $operator = array (); - $value = array (); - foreach ($tokens as $key=>$token) - { - if ($minuses[$key] === "-") - $operator[$key] = "NOT REGEXP"; - else - $operator[$key] = "REGEXP"; - $value[$key] = "(^|[<> \[\]\(\"',.;/:!?\r\n])". - preg_quote ($token). - "([<> \[\]\)\"',.;/:!?\r\n]|$)"; - } - return array ("operator"=>$operator, "value"=>$value); - } - - /** Remove the tokens with too small length. Remove the not desired minuses - * too. - * @param array $tokens The token list - * @param array $minuses The minuses list - * @return array tokens and minuses - */ - private function tokenMinLength ($tokens, $minuses) - { - if (! is_array ($tokens)) - throw new \Exception ("Invalid tokens provided to fts:tokenMinLength", - 500); - if (! is_array ($minuses)) - throw new \Exception ("Invalid minuses provided to fts:tokenMinLength", - 500); - $newTokens = array (); - $newMinuses = array (); - foreach ($tokens as $key=>$token) - { - if (mb_strlen ($token) >= $this->minLength) - { - $newTokens[] = $token; - $newMinuses[] = $minuses[$key]; - } - } - return array ("tokens"=>$newTokens, "minuses"=>$newMinuses); - } - - /** Return an array with the $query tokenized - * @param string $query The text to tokenize - * @return array tokens and minuses - */ - private function tokenizer ($query) - { - if (! is_string ($query)) - throw new \Exception ("Invalid query provided to fts:tokenizer", 500); - $debug = false; - $tokens = array (); - $sentences = array (); - $minuses = array (); - // Look for sentences - $offset = 0; - if ($debug) echo "\n012345678901234567890123456789\n$query\n"; - while ($offset <= mb_strlen ($query)) - { - if ($debug) echo "OFFSET=$offset\n"; - if (substr ($query, $offset, 1) === "-") - { - if ($debug) echo "MINUS\n"; - $minus = "-"; - $offset++; - } - else - $minus = ""; - $start = strpos ($query, "\"", $offset); - if ($start === $offset) - { - // Sentence, see if there is a end - $end = strpos ($query, "\"", $offset + 1); - if ($end !== false) - { - // Complete sentence (with ending double quote) - $nbchars = $end - $offset - 1; - if ($debug) - echo "COMPLETE SENTENCE (Start ".($offset+1). - " with $nbchars chars)\n"; - $token = substr ($query, $offset + 1, $nbchars); - $tokens[] = $token; - $sentences[] = true; - $minuses[] = $minus; - $offset = $end + 1; - continue; + if (! function_exists("mb_strlen")) { + throw new \Exception( + "PHP don't have the MB Support. Please add it !", + 500 + ); } - } - // Word analysis - $end = strpos ($query, " ", $offset); - if ($end === false) - $end = strlen ($query); - $nbchars = $end - $offset; - if ($nbchars > 0) - { - if ($debug) echo "WORD FOUND (Start $offset with $nbchars chars)\n"; - $token = substr ($query, $offset, $nbchars); - $tokens[] = $token; - $sentences[] = false; - $minuses[] = $minus; - } - $offset = $end + 1; } - if ($debug) print_r ($tokens); - return array ("tokens" => $tokens, + + //////////////////////// + //// GETTERS //// + //////////////////////// + /** Get the tokens store after the search + */ + public function getTokens() + { + return $this->tokens; + } + + /** Get the tokens store after the search, without the too small ones + */ + public function getTokensMin() + { + return $this->tokensMin; + } + + /** Get the regexes defined after the analyzer + */ + public function getRegexes() + { + return $this->regexes; + } + + /** Set the method to call on tokens word only + * The method must return the token updated + * @param callable $callable The callable method + * @return $this + */ + public function callTokenWord($callable) + { + if (! is_callable($callable)) { + throw new \Exception(dgettext( + "domframework", + "SSE : callTokenWord : provided method is not callable" + ), 500); + } + $this->callTokenWord = $callable; + return $this; + } + + /** Set the method to call on tokens sentence only + * The method must return the token updated + * @param callable $callable The callable method + * @return $this + */ + public function callTokenSentence($callable) + { + if (! is_callable($callable)) { + throw new \Exception(dgettext( + "domframework", + "SSE : callTokenSentence : provided method is not callable" + ), 500); + } + $this->callTokenSentence = $callable; + return $this; + } + + ////////////////////////////// + //// PUBLIC METHODS //// + ////////////////////////////// + /** Explode the query text provided in $query, to be used to search in + * database, file... + * @param string $query The text to found in the database + * @return array The operator and the associated regex value to search + */ + public function search($query) + { + $query = trim($query); + $this->tokens = $this->tokenizer($query); + foreach ($this->tokens["tokens"] as $key => &$token) { + if ($this->tokens["sentences"][$key] === true && $this->callTokenSentence) { + $token = call_user_func($this->callTokenSentence, $token); + } elseif ( + $this->tokens["sentences"][$key] === false && + $this->callTokenWord + ) { + $token = call_user_func($this->callTokenWord, $token); + } + } + $this->tokensMin = $this->tokenMinLength( + $this->tokens["tokens"], + $this->tokens["minuses"] + ); + $this->regexes = $this->regex( + $this->tokensMin["tokens"], + $this->tokensMin["minuses"] + ); + return $this->regexes; + } + + /** Construct the query based on the tokens. + * The tokens can be updated by methods so the query may be modified by the + * external methods + * @return string + */ + public function getQuery() + { + $res = ""; + foreach ($this->tokens["tokens"] as $key => $token) { + if ($key > 0) { + $res .= " "; + } + if ($this->tokens["sentences"][$key] === true) { + $res .= "\"$token\""; + } else { + $res .= "$token"; + } + } + return $res; + } + + /** Return $line if the $query match against $line, or false if not + * @param string $line The line to examine + * @param string $query The query to apply on it + * @return string|false The $line if match, false + */ + public function searchString($line, $query) + { + $regexes = $this->search($query); + if (empty($this->tokens)) { + return false; + } + foreach ($this->tokens["tokens"] as $key => $searchPart) { + if (trim($searchPart) === "") { + continue; + } + $match = (strpos($line, $searchPart) !== false); + if ($this->tokens["minuses"][$key] === "" && $match == 0) { + return false; + } + if ($this->tokens["minuses"][$key] === "-" && $match == 1) { + return false; + } + } + return $line; + } + + /** Search in SQL + * @param string $query The text to found in the database + * @param object $dblayeroo The dblayeroo object to query + * @param array|null $fields The fields in $dblayeroo to look for data. If + * null, look in all the fields defined in the dblayeroo object + * @return array The result of the query + */ + public function searchSQL($query, $dblayeroo, $fields) + { + $regexes = $this->search($query); + if (empty($regexes["operator"])) { + return array(); + } + // Clone the object to not modify a previously defined query + $dbl = clone $dblayeroo; + $dbl->clearRequest(); + $dbl->select(); + if ($fields === null) { + $fields = array_keys($dbl->fields()); + } + $i = 0; + foreach ($fields as $field) { + if (! array_key_exists($field, $dbl->fields())) { + throw new \Exception(sprintf(dgettext( + "domframework", + "The field '%s' doesn't exists in database" + ), $field), 500); + } + if ($i > 0) { + $dbl->whereAddOR(); + } + $dbl->whereAddParenthesisOpen(); + $j = 0; + foreach ($regexes["operator"] as $key => $operator) { + if ($j > 0) { + $dbl->whereAddAND(); + } + $dbl->whereAdd($field, $operator, $regexes["value"][$key]); + $j++; + } + $dbl->whereAddParenthesisClose(); + $i++; + } + // Look for the order by date if provided + foreach ($dbl->fields() as $field => $params) { + if ( + $params[0] == "date" || $params[0] == "datetime" || + $params[0] == "time" + ) { + $dbl->orderAdd($field, "DESC"); + break; + } + } + return $dbl->execute(); + } + + /////////////////////////////// + //// PRIVATE METHODS //// + /////////////////////////////// + /** Create the regex associated to the provided tokens and minuses + * @param array $tokens The token list + * @param array $minuses The minuses list + * @return array The operator and the associated regex value to search + */ + private function regex($tokens, $minuses) + { + if (! is_array($tokens)) { + throw new \Exception( + "Invalid tokens provided to fts:tokenMinLength", + 500 + ); + } + if (! is_array($minuses)) { + throw new \Exception( + "Invalid minuses provided to fts:tokenMinLength", + 500 + ); + } + $operator = array(); + $value = array(); + foreach ($tokens as $key => $token) { + if ($minuses[$key] === "-") { + $operator[$key] = "NOT REGEXP"; + } else { + $operator[$key] = "REGEXP"; + } + $value[$key] = "(^|[<> \[\]\(\"',.;/:!?\r\n])" . + preg_quote($token) . + "([<> \[\]\)\"',.;/:!?\r\n]|$)"; + } + return array("operator" => $operator, "value" => $value); + } + + /** Remove the tokens with too small length. Remove the not desired minuses + * too. + * @param array $tokens The token list + * @param array $minuses The minuses list + * @return array tokens and minuses + */ + private function tokenMinLength($tokens, $minuses) + { + if (! is_array($tokens)) { + throw new \Exception( + "Invalid tokens provided to fts:tokenMinLength", + 500 + ); + } + if (! is_array($minuses)) { + throw new \Exception( + "Invalid minuses provided to fts:tokenMinLength", + 500 + ); + } + $newTokens = array(); + $newMinuses = array(); + foreach ($tokens as $key => $token) { + if (mb_strlen($token) >= $this->minLength) { + $newTokens[] = $token; + $newMinuses[] = $minuses[$key]; + } + } + return array("tokens" => $newTokens, "minuses" => $newMinuses); + } + + /** Return an array with the $query tokenized + * @param string $query The text to tokenize + * @return array tokens and minuses + */ + private function tokenizer($query) + { + if (! is_string($query)) { + throw new \Exception("Invalid query provided to fts:tokenizer", 500); + } + $debug = false; + $tokens = array(); + $sentences = array(); + $minuses = array(); + // Look for sentences + $offset = 0; + if ($debug) { + echo "\n012345678901234567890123456789\n$query\n"; + } + while ($offset <= mb_strlen($query)) { + if ($debug) { + echo "OFFSET=$offset\n"; + } + if (substr($query, $offset, 1) === "-") { + if ($debug) { + echo "MINUS\n"; + } + $minus = "-"; + $offset++; + } else { + $minus = ""; + } + $start = strpos($query, "\"", $offset); + if ($start === $offset) { + // Sentence, see if there is a end + $end = strpos($query, "\"", $offset + 1); + if ($end !== false) { + // Complete sentence (with ending double quote) + $nbchars = $end - $offset - 1; + if ($debug) { + echo "COMPLETE SENTENCE (Start " . ($offset + 1) . + " with $nbchars chars)\n"; + } + $token = substr($query, $offset + 1, $nbchars); + $tokens[] = $token; + $sentences[] = true; + $minuses[] = $minus; + $offset = $end + 1; + continue; + } + } + // Word analysis + $end = strpos($query, " ", $offset); + if ($end === false) { + $end = strlen($query); + } + $nbchars = $end - $offset; + if ($nbchars > 0) { + if ($debug) { + echo "WORD FOUND (Start $offset with $nbchars chars)\n"; + } + $token = substr($query, $offset, $nbchars); + $tokens[] = $token; + $sentences[] = false; + $minuses[] = $minus; + } + $offset = $end + 1; + } + if ($debug) { + print_r($tokens); + } + return array("tokens" => $tokens, "sentences" => $sentences, "minuses" => $minuses); - } + } } diff --git a/src/Getopts.php b/src/Getopts.php index 61e148b..b2b4652 100644 --- a/src/Getopts.php +++ b/src/Getopts.php @@ -1,4 +1,5 @@ @@ -18,520 +19,645 @@ namespace Domframework; */ class Getopts { - /** The list of options to check - */ - private $options = array (); + /** The list of options to check + */ + private $options = array(); - /** The simulate line entry - */ - private $simulate; + /** The simulate line entry + */ + private $simulate; - /** The parameters scanned from the command line or from the simulate entry - */ - private $parameters; + /** The parameters scanned from the command line or from the simulate entry + */ + private $parameters; - /** The rest of the line which is not analyzed - */ - private $restOfLine; + /** The rest of the line which is not analyzed + */ + private $restOfLine; - /** The name of the program called ($argv[0]) - */ - private $programName; + /** The name of the program called ($argv[0]) + */ + private $programName; - /** The constructor check the availability of the MB module - */ - public function __construct () - { - if (! function_exists ("mb_strlen")) - throw new \Exception ("PHP don't have the MB Support. Please add it !", - 500); - } - - /** Set/Get the simulate value - * @param string|null $simulate The simulate to get/set - */ - public function simulate ($simulate = null) - { - if ($simulate === null) - return $this->simulate; - if (! is_string ($simulate)) - throw new \Exception ("Simulate provided to getopts is not a string", - 500); - if ($simulate === "") - $simulate = null; - $this->simulate = $simulate; - return $this; - } - - /** Add a new option to check - * @param string $identifier The identifier of the options - * @param string $short The short options (one letter with/without - * semi-colon) to check - * @param array|string $long The long options without double dash, - * with/without semi-colon to check. If string, use colon to separate the - * options - * @param string $description The description of the option - * @param string $paramName The description (or name) of the parameter - * @param integer $multiple The same identifier can be called multiple time. - * Set $multiple to set the maximum number of values - */ - public function add ($identifier, $short, $long, $description, - $paramName = "", $multiple = 0) - { - if (! is_string ($identifier)) - throw new \Exception ("Identifier provided to getopts is not a string", - 500); - if (strlen (trim ($identifier)) === 0) - throw new \Exception ("Identifier provided to getopts is too short", 500); - if (! is_string ($short)) - throw new \Exception ("Short option provided to getopts is not a string", - 500); - if (! is_array ($long) && ! is_string ($long)) - throw new \Exception ( - "Long option provided to getopts is not a string or an array", 500); - if (! is_string ($description)) - throw new \Exception ( - "Description of option provided to getopts is not a string", 500); - if (! is_string ($paramName)) - throw new \Exception ( - "paramName of option provided to getopts is not a string", 500); - if (is_string ($long)) + /** The constructor check the availability of the MB module + */ + public function __construct() { - if (trim ($long) !== "") - $long = explode (",", $long); - else - $long = array (); - } - if (substr ($short, 0, 1) !== false && substr ($short, 0, 1) !== "" && - $short[0] === ":") - throw new \Exception ("Short option can't start by semi-colon", 500); - if ((strpos ($short, ":") !== false || - strpos (implode ($long), ":") !== false) && - trim ($paramName) === "") - throw new \Exception ( - "One parameter is waiting, but there is no paramName defined", 500); - if (strspn ($paramName, "abcdefghijklmnopqrstuvwxyz". - "ABCDEFGHIJKLMNOPQRSTUVWXYZ". - "0123456789-_.") !== strlen ($paramName)) - throw new \Exception ( - "paramName of option provided to getopts contains invalid chars", 500); - if (! is_int ($multiple) && - \verify::staticIs_integer ("$multiple") === false) - throw new \Exception ("Multiple option must be an integer", 500); - preg_match_all ("#[\S]:?#u", $short, $matches); - if (! array_key_exists (0, $matches)) - throw new \Exception ("Short parameter is invalid", 500); - $short = $matches[0]; - foreach ($short as $key=>$s) - { - if (substr ($s, 1) !== false && substr ($s, 1) !== ":" && - substr ($s, 1) !== "") - throw new \Exception ( - "Short parameter is invalid : only one letter allowed", 500); - $short[$key] = "-".$s; - } - foreach ($long as $key=>$l) - { - $long[$key] = "--".$l; - } - $optShort = array (); - $optLong = array (); - foreach ($this->options as $opt) - { - // Do not allow to add if the short is already defined (with : or :: or - // without any) - if ($opt["identifier"] === $identifier) - throw new \Exception ("The identifier is already defined", 500); - // Do not allow to add if the short is already defined - $optShort = array_merge ($optShort, $opt["short"]); - $optLong = array_merge ($optLong, $opt["long"]); - } - foreach ($short as $s) - { - if (count (preg_grep ("#^".str_replace (":", "", - str_replace ("?", "\\?", $s)).":?:?$#", - $optShort))) - throw new \Exception (sprintf ( - "The short option '%s' is already defined in '%s'", - $s, $opt["identifier"]), 500); + if (! function_exists("mb_strlen")) { + throw new \Exception( + "PHP don't have the MB Support. Please add it !", + 500 + ); + } } - // Do not allow to add if the long is already defined (with : or :: or - // without any) - foreach ($long as $l) + /** Set/Get the simulate value + * @param string|null $simulate The simulate to get/set + */ + public function simulate($simulate = null) { - if (count (preg_grep ("#^".str_replace (":", "", - str_replace ("?", "\\?", $l)).":?:?$#", $optLong))) - throw new \Exception (sprintf ( - "The long option '%s' is already defined in '%s'", - $l, $opt["identifier"]), 500); + if ($simulate === null) { + return $this->simulate; + } + if (! is_string($simulate)) { + throw new \Exception( + "Simulate provided to getopts is not a string", + 500 + ); + } + if ($simulate === "") { + $simulate = null; + } + $this->simulate = $simulate; + return $this; } - // Do not allow a parameter to be defined multiple times in the new option - foreach ($short as $s) - { - if (strspn (substr ($s, 1), "abcdefghijklmnopqrstuvwxyz". - "ABCDEFGHIJKLMNOPQRSTUVWXYZ". - "0123456789?_.:") !== strlen ($s) -1) - throw new \Exception (sprintf ( - "Short option '%s' to getopts contains invalid chars", $s), 500); - $regex = "#^".str_replace (":", "", str_replace ("?", "\\?", $s)). + /** Add a new option to check + * @param string $identifier The identifier of the options + * @param string $short The short options (one letter with/without + * semi-colon) to check + * @param array|string $long The long options without double dash, + * with/without semi-colon to check. If string, use colon to separate the + * options + * @param string $description The description of the option + * @param string $paramName The description (or name) of the parameter + * @param integer $multiple The same identifier can be called multiple time. + * Set $multiple to set the maximum number of values + */ + public function add( + $identifier, + $short, + $long, + $description, + $paramName = "", + $multiple = 0 + ) { + if (! is_string($identifier)) { + throw new \Exception( + "Identifier provided to getopts is not a string", + 500 + ); + } + if (strlen(trim($identifier)) === 0) { + throw new \Exception("Identifier provided to getopts is too short", 500); + } + if (! is_string($short)) { + throw new \Exception( + "Short option provided to getopts is not a string", + 500 + ); + } + if (! is_array($long) && ! is_string($long)) { + throw new \Exception( + "Long option provided to getopts is not a string or an array", + 500 + ); + } + if (! is_string($description)) { + throw new \Exception( + "Description of option provided to getopts is not a string", + 500 + ); + } + if (! is_string($paramName)) { + throw new \Exception( + "paramName of option provided to getopts is not a string", + 500 + ); + } + if (is_string($long)) { + if (trim($long) !== "") { + $long = explode(",", $long); + } else { + $long = array(); + } + } + if ( + substr($short, 0, 1) !== false && substr($short, 0, 1) !== "" && + $short[0] === ":" + ) { + throw new \Exception("Short option can't start by semi-colon", 500); + } + if ( + (strpos($short, ":") !== false || + strpos(implode($long), ":") !== false) && + trim($paramName) === "" + ) { + throw new \Exception( + "One parameter is waiting, but there is no paramName defined", + 500 + ); + } + if ( + strspn($paramName, "abcdefghijklmnopqrstuvwxyz" . + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . + "0123456789-_.") !== strlen($paramName) + ) { + throw new \Exception( + "paramName of option provided to getopts contains invalid chars", + 500 + ); + } + if ( + ! is_int($multiple) && + \verify::staticIs_integer("$multiple") === false + ) { + throw new \Exception("Multiple option must be an integer", 500); + } + preg_match_all("#[\S]:?#u", $short, $matches); + if (! array_key_exists(0, $matches)) { + throw new \Exception("Short parameter is invalid", 500); + } + $short = $matches[0]; + foreach ($short as $key => $s) { + if ( + substr($s, 1) !== false && substr($s, 1) !== ":" && + substr($s, 1) !== "" + ) { + throw new \Exception( + "Short parameter is invalid : only one letter allowed", + 500 + ); + } + $short[$key] = "-" . $s; + } + foreach ($long as $key => $l) { + $long[$key] = "--" . $l; + } + $optShort = array(); + $optLong = array(); + foreach ($this->options as $opt) { + // Do not allow to add if the short is already defined (with : or :: or + // without any) + if ($opt["identifier"] === $identifier) { + throw new \Exception("The identifier is already defined", 500); + } + // Do not allow to add if the short is already defined + $optShort = array_merge($optShort, $opt["short"]); + $optLong = array_merge($optLong, $opt["long"]); + } + foreach ($short as $s) { + if ( + count(preg_grep( + "#^" . str_replace( + ":", + "", + str_replace("?", "\\?", $s) + ) . ":?:?$#", + $optShort + )) + ) { + throw new \Exception(sprintf( + "The short option '%s' is already defined in '%s'", + $s, + $opt["identifier"] + ), 500); + } + } + + // Do not allow to add if the long is already defined (with : or :: or + // without any) + foreach ($long as $l) { + if ( + count(preg_grep("#^" . str_replace( + ":", + "", + str_replace("?", "\\?", $l) + ) . ":?:?$#", $optLong)) + ) { + throw new \Exception(sprintf( + "The long option '%s' is already defined in '%s'", + $l, + $opt["identifier"] + ), 500); + } + } + + // Do not allow a parameter to be defined multiple times in the new option + foreach ($short as $s) { + if ( + strspn(substr($s, 1), "abcdefghijklmnopqrstuvwxyz" . + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . + "0123456789?_.:") !== strlen($s) - 1 + ) { + throw new \Exception(sprintf( + "Short option '%s' to getopts contains invalid chars", + $s + ), 500); + } + $regex = "#^" . str_replace(":", "", str_replace("?", "\\?", $s)) . ":?:?$#"; - if (count (preg_grep ($regex, $short)) !== 1) - throw new \Exception (sprintf ( - "The short option '%s' can not be defined multiple time in '%s'", - str_replace (":", "", $s), $identifier), 500); - } - foreach ($long as $l) - { - if (strspn (substr ($l, 2), "abcdefghijklmnopqrstuvwxyz". - "ABCDEFGHIJKLMNOPQRSTUVWXYZ". - "0123456789?_.:") !== strlen ($l) -2) - throw new \Exception (sprintf ( - "Long option '%s' to getopts contains invalid chars", $l), 500); - $regex = "#^".str_replace (":", "", str_replace ("?", "\\?", $l)). + if (count(preg_grep($regex, $short)) !== 1) { + throw new \Exception(sprintf( + "The short option '%s' can not be defined multiple time in '%s'", + str_replace(":", "", $s), + $identifier + ), 500); + } + } + foreach ($long as $l) { + if ( + strspn(substr($l, 2), "abcdefghijklmnopqrstuvwxyz" . + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . + "0123456789?_.:") !== strlen($l) - 2 + ) { + throw new \Exception(sprintf( + "Long option '%s' to getopts contains invalid chars", + $l + ), 500); + } + $regex = "#^" . str_replace(":", "", str_replace("?", "\\?", $l)) . ":?:?$#"; - if (count (preg_grep ($regex, $long)) !== 1) - throw new \Exception (sprintf ( - "The long option '%s' can not be defined multiple time in '%s'", - str_replace (":", "", $l), $identifier), 500); - } + if (count(preg_grep($regex, $long)) !== 1) { + throw new \Exception(sprintf( + "The long option '%s' can not be defined multiple time in '%s'", + str_replace(":", "", $l), + $identifier + ), 500); + } + } - $this->options[] = array ("identifier" => $identifier, + $this->options[] = array("identifier" => $identifier, "short" => $short, "long" => $long, - "description" => trim ($description), - "paramName" => trim ($paramName), + "description" => trim($description), + "paramName" => trim($paramName), "multiple" => $multiple); - return $this; - } + return $this; + } - /** Scan the command line and fill the parameters. - * Use the simulate line if provided or use the $argv if not - * Set the parameters property to an array - * @return $this; - */ - public function scan () - { - global $argv; - if ($argv === null) + /** Scan the command line and fill the parameters. + * Use the simulate line if provided or use the $argv if not + * Set the parameters property to an array + * @return $this; + */ + public function scan() { - // getopts is launched in WebServer. Can not analyze anything - $this->programName = ""; - $this->parameters = array (); - $this->restOfLine = array (); - return $this; - } - if ($this->simulate !== null) - $commandLine = $this->simulate; - else - { - $args = array (); - foreach ($argv as $arg) - { - if (strpos ($arg, " ") !== false || $arg === "") - $args[] = "\"$arg\""; - else - $args[] = $arg; - } - $commandLine = implode (" ", $args); - } - $debug = false; - $tokens = array (); - $prevToken = ""; - // Look for sentences in the arguments of the command line - $offset = 0; - if ($debug) echo "\n012345678901234567890123456789\n$commandLine\n"; - while ($offset < mb_strlen ($commandLine)) - { - if ($debug) echo "OFFSET=$offset\n"; - $start = strpos ($commandLine, "\"", $offset); - if ($start === $offset) - { - // Sentence, see if there is a end - $end = strpos ($commandLine, "\"", $offset + 1); - if ($end !== false) - { - // Complete sentence (with ending double quote) - $nbchars = $end - $offset - 1; - if ($debug) - echo "COMPLETE SENTENCE (Start ".($offset+1). - " with $nbchars chars)\n"; - $token = substr ($commandLine, $offset + 1, $nbchars); - $tokens[] = $token; - $offset = $end + 2; - continue; + global $argv; + if ($argv === null) { + // getopts is launched in WebServer. Can not analyze anything + $this->programName = ""; + $this->parameters = array(); + $this->restOfLine = array(); + return $this; } - } - // Word analysis - $end = strpos ($commandLine, " ", $offset); - if ($end === false) - $end = strlen ($commandLine); - $nbchars = $end - $offset; - $token = substr ($commandLine, $offset, $nbchars); - if ($debug) - echo "WORD FOUND (Start $offset with $nbchars chars): $token\n"; - // The '\ ' are token concatenation. Remove the \ in the parameters - if (substr ($token, -1) === "\\") - { - $prevToken .= substr ($token, 0, -1)." "; - $offset = $end + 1; - continue; - } - if ($prevToken !== "") - { - $token = "$prevToken$token"; + if ($this->simulate !== null) { + $commandLine = $this->simulate; + } else { + $args = array(); + foreach ($argv as $arg) { + if (strpos($arg, " ") !== false || $arg === "") { + $args[] = "\"$arg\""; + } else { + $args[] = $arg; + } + } + $commandLine = implode(" ", $args); + } + $debug = false; + $tokens = array(); $prevToken = ""; - } - //if ($this->restOfLine !== null) - // $this->restOfLine[] = $token; - //elseif (trim ($token) !== "") - $tokens[] = $token; - $offset = $end + 1; - } - if ($debug) print_r ($tokens); - - // Analyze the tokens to fill the $this->parameters - if ($this->restOfLine === null) - $this->restOfLine = array (); - if (! array_key_exists (0, $tokens)) - throw new \Exception ("Can not find the program name (\$argv[0]", 500); - $this->programName = array_shift ($tokens); - foreach ($this->options as $option) - { - foreach (array ("short", "long") as $len) - { - foreach ($option[$len] as $opt) - { - if ($option["multiple"] < 2) - { - if ($debug) echo "CHECK $opt UNIQUE -> "; - $keys = array_keys ($tokens, str_replace (":", "", $opt)); - if (count ($keys) === 0) - { - if ($debug) echo "Option Not found\n"; - continue; - } - if (count ($keys) > 1) - throw new \Exception (sprintf (dgettext ("domframework", - "Too much identical parameters provided: %s"), $opt), 500); - $pos = reset ($keys); - // Look for parameter in this option. Can't start by dash - if (strpos ($opt, ":") === false) - { - if ($debug) echo "FOUND UNIQUE without param\n"; - $this->parameters[$option["identifier"]] = true; - unset ($tokens[$pos]); - } - elseif (strpos ($opt, "::") !== false && - array_key_exists ($pos+1, $tokens) && - array_key_exists ($pos+2, $tokens) && - $tokens[$pos+1] === "--") - { - if ($debug) - echo "FOUND UNIQUE with optional param filled ". - "and double-dash\n"; - $this->parameters[$option["identifier"]] = $tokens[$pos+2]; - unset ($tokens[$pos]); - unset ($tokens[$pos+1]); - unset ($tokens[$pos+2]); - } - elseif (strpos ($opt, "::") !== false && - array_key_exists ($pos+1, $tokens) && - substr ($tokens[$pos+1], 0, 1) !== "-") - { - if ($debug) echo "FOUND UNIQUE with optional param filled\n"; - $this->parameters[$option["identifier"]] = $tokens[$pos+1]; - unset ($tokens[$pos]); - unset ($tokens[$pos+1]); - } - elseif (strpos ($opt, ":") !== false) - { - if (array_key_exists ($pos+1, $tokens) && - $tokens[$pos+1] === "--" && - ! array_key_exists ($pos+2, $tokens)) - throw new \Exception (sprintf (dgettext ("domframework", - "Mandatory value for parameter '%s' is not provided after double-dash"), - $opt), 500); - if (! array_key_exists ($pos+1, $tokens) || - substr ($tokens[$pos+1], 0, 1) === "-") - throw new \Exception (dgettext ("domframework", - "Mandatory value for parameter '$opt' is not provided"), 500); - if ($debug) echo "FOUND UNIQUE with mandatory param filled\n"; - $this->parameters[$option["identifier"]] = $tokens[$pos+1]; - unset ($tokens[$pos]); - unset ($tokens[$pos+1]); - } - else - { - if ($debug) echo "Not found\n"; - } - } - else - { - if ($debug) echo "CHECK $opt MULTIPLE -> "; - $keys = array_keys ($tokens, str_replace (":", "", $opt)); - if (count ($keys) === 0) - { - if ($debug) echo "Option Not found\n"; - continue; - } - if (count ($keys) > $option["multiple"]) - throw new \Exception (sprintf (dgettext ("domframework", - "Too much multiple parameters provided: %s"), $opt), 500); - foreach ($keys as $pos) - { - // Look for parameter in this option. Can't start by dash - if (strpos ($opt, ":") === false) - { - if ($debug) echo "FOUND MUTLIPLE without param\n"; - $this->parameters[$option["identifier"]][] = true; - unset ($tokens[$pos]); - } - elseif (strpos ($opt, "::") !== false && - array_key_exists ($pos+1, $tokens) && - substr ($tokens[$pos+1], 0, 1) !== "-") - { - if ($debug) echo "FOUND MUTLIPLE with optional param filled\n"; - $this->parameters[$option["identifier"]][] = $tokens[$pos+1]; - unset ($tokens[$pos]); - unset ($tokens[$pos+1]); - } - elseif (strpos ($opt, ":") !== false) - { - if (! array_key_exists ($pos+1, $tokens) || - substr ($tokens[$pos+1], 0, 1) === "-") - throw new \Exception (sprintf (dgettext ("domframework", - "Mandatory value for parameter '%s' is not provided"), - $opt), 500); - if ($debug) echo "FOUND MUTLIPLE with mandatory param filled\n"; - $this->parameters[$option["identifier"]][] = $tokens[$pos+1]; - unset ($tokens[$pos]); - unset ($tokens[$pos+1]); - } - else - { - if ($debug) echo "Not found\n"; - } - } - } + // Look for sentences in the arguments of the command line + $offset = 0; + if ($debug) { + echo "\n012345678901234567890123456789\n$commandLine\n"; } - } - } - - // Manage the restOfLine - foreach ($tokens as $key=>$tok) - { - if ($tok === "--" && array_key_exists ($key+1, $tokens)) - { - $this->restOfLine[] = $tokens[$key+1]; - unset ($tokens[$key]); - unset ($tokens[$key+1]); - continue; - } - if (substr ($tok, 0, 1) === "-") - continue; - $this->restOfLine[] = $tok; - unset ($tokens[$key]); - } - if (count ($tokens)) - { - throw new \Exception (sprintf (dgettext ("domframework", - "Provided tokens are not known: %s"), implode (",", $tokens)), 500); - } - if ($this->parameters === null) - $this->parameters = array (); - return $this; - } - - /** Get the value of the option if set in the command line. If simulate is - * defined, use it. - * Return false if the option is not set - * Return true if the option is set without parameter - * Return the content of the parameter if the option is set and parameter is - * defined - * Throw an exception if the identifier is not set - * @param string $identifier The identifier option to get - */ - public function get ($identifier) - { - $exists = false; - foreach ($this->options as $opt) - { - if ($opt["identifier"] === $identifier) - { - $exists = true; - break; - } - } - if ($exists === false) - throw new \Exception (sprintf (dgettext ("domframework", - "Provided parameter is not known: %s"), $identifier), 500); - if ($this->parameters === null) - $this->scan (); - if (array_key_exists ($identifier, $this->parameters)) - return $this->parameters[$identifier]; - if ($opt["multiple"] > 1) - return array (); - return false; - } - - /** Get the value found in the rest of line (after the double dashes) - */ - public function restOfLine () - { - if ($this->restOfLine === null) - $this->scan (); - return $this->restOfLine; - } - - /** Get the name of the program found in the command line - */ - public function programName () - { - if ($this->programName === null) - $this->scan (); - return $this->programName; - } - - /** Get the Help message with all the descriptions and options - */ - public function help () - { - if (count ($this->options) === 0) - return dgettext ("domframework", "No option defined")."\n"; - $d = ""; - foreach ($this->options as $opt) - { - $i = 0; - foreach (array ("short", "long") as $len) - { - foreach ($opt[$len] as $option) - { - if (strpos ($option, ":") !== false) - $param = true; - else - $param = false; - if (strpos ($option, "::") !== false) - $paramOptional = true; - else - $paramOptional = false; - if ($i > 0) - $d .= ", "; - $d .= str_replace (":", "", $option); - if ($param) - { - $d .= " "; - if ($paramOptional) $d .= "["; - $d .= $opt["paramName"]; - if ($paramOptional) $d .= "]"; - } - $i++; + while ($offset < mb_strlen($commandLine)) { + if ($debug) { + echo "OFFSET=$offset\n"; + } + $start = strpos($commandLine, "\"", $offset); + if ($start === $offset) { + // Sentence, see if there is a end + $end = strpos($commandLine, "\"", $offset + 1); + if ($end !== false) { + // Complete sentence (with ending double quote) + $nbchars = $end - $offset - 1; + if ($debug) { + echo "COMPLETE SENTENCE (Start " . ($offset + 1) . + " with $nbchars chars)\n"; + } + $token = substr($commandLine, $offset + 1, $nbchars); + $tokens[] = $token; + $offset = $end + 2; + continue; + } + } + // Word analysis + $end = strpos($commandLine, " ", $offset); + if ($end === false) { + $end = strlen($commandLine); + } + $nbchars = $end - $offset; + $token = substr($commandLine, $offset, $nbchars); + if ($debug) { + echo "WORD FOUND (Start $offset with $nbchars chars): $token\n"; + } + // The '\ ' are token concatenation. Remove the \ in the parameters + if (substr($token, -1) === "\\") { + $prevToken .= substr($token, 0, -1) . " "; + $offset = $end + 1; + continue; + } + if ($prevToken !== "") { + $token = "$prevToken$token"; + $prevToken = ""; + } + //if ($this->restOfLine !== null) + // $this->restOfLine[] = $token; + //elseif (trim ($token) !== "") + $tokens[] = $token; + $offset = $end + 1; } - } - $d .= "\n\t".$opt["description"]; - $d .= "\n"; + if ($debug) { + print_r($tokens); + } + + // Analyze the tokens to fill the $this->parameters + if ($this->restOfLine === null) { + $this->restOfLine = array(); + } + if (! array_key_exists(0, $tokens)) { + throw new \Exception("Can not find the program name (\$argv[0]", 500); + } + $this->programName = array_shift($tokens); + foreach ($this->options as $option) { + foreach (array("short", "long") as $len) { + foreach ($option[$len] as $opt) { + if ($option["multiple"] < 2) { + if ($debug) { + echo "CHECK $opt UNIQUE -> "; + } + $keys = array_keys($tokens, str_replace(":", "", $opt)); + if (count($keys) === 0) { + if ($debug) { + echo "Option Not found\n"; + } + continue; + } + if (count($keys) > 1) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Too much identical parameters provided: %s" + ), $opt), 500); + } + $pos = reset($keys); + // Look for parameter in this option. Can't start by dash + if (strpos($opt, ":") === false) { + if ($debug) { + echo "FOUND UNIQUE without param\n"; + } + $this->parameters[$option["identifier"]] = true; + unset($tokens[$pos]); + } elseif ( + strpos($opt, "::") !== false && + array_key_exists($pos + 1, $tokens) && + array_key_exists($pos + 2, $tokens) && + $tokens[$pos + 1] === "--" + ) { + if ($debug) { + echo "FOUND UNIQUE with optional param filled " . + "and double-dash\n"; + } + $this->parameters[$option["identifier"]] = $tokens[$pos + 2]; + unset($tokens[$pos]); + unset($tokens[$pos + 1]); + unset($tokens[$pos + 2]); + } elseif ( + strpos($opt, "::") !== false && + array_key_exists($pos + 1, $tokens) && + substr($tokens[$pos + 1], 0, 1) !== "-" + ) { + if ($debug) { + echo "FOUND UNIQUE with optional param filled\n"; + } + $this->parameters[$option["identifier"]] = $tokens[$pos + 1]; + unset($tokens[$pos]); + unset($tokens[$pos + 1]); + } elseif (strpos($opt, ":") !== false) { + if ( + array_key_exists($pos + 1, $tokens) && + $tokens[$pos + 1] === "--" && + ! array_key_exists($pos + 2, $tokens) + ) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Mandatory value for parameter '%s' is not provided after double-dash" + ), + $opt + ), 500); + } + if ( + ! array_key_exists($pos + 1, $tokens) || + substr($tokens[$pos + 1], 0, 1) === "-" + ) { + throw new \Exception(dgettext( + "domframework", + "Mandatory value for parameter '$opt' is not provided" + ), 500); + } + if ($debug) { + echo "FOUND UNIQUE with mandatory param filled\n"; + } + $this->parameters[$option["identifier"]] = $tokens[$pos + 1]; + unset($tokens[$pos]); + unset($tokens[$pos + 1]); + } else { + if ($debug) { + echo "Not found\n"; + } + } + } else { + if ($debug) { + echo "CHECK $opt MULTIPLE -> "; + } + $keys = array_keys($tokens, str_replace(":", "", $opt)); + if (count($keys) === 0) { + if ($debug) { + echo "Option Not found\n"; + } + continue; + } + if (count($keys) > $option["multiple"]) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Too much multiple parameters provided: %s" + ), $opt), 500); + } + foreach ($keys as $pos) { + // Look for parameter in this option. Can't start by dash + if (strpos($opt, ":") === false) { + if ($debug) { + echo "FOUND MUTLIPLE without param\n"; + } + $this->parameters[$option["identifier"]][] = true; + unset($tokens[$pos]); + } elseif ( + strpos($opt, "::") !== false && + array_key_exists($pos + 1, $tokens) && + substr($tokens[$pos + 1], 0, 1) !== "-" + ) { + if ($debug) { + echo "FOUND MUTLIPLE with optional param filled\n"; + } + $this->parameters[$option["identifier"]][] = $tokens[$pos + 1]; + unset($tokens[$pos]); + unset($tokens[$pos + 1]); + } elseif (strpos($opt, ":") !== false) { + if ( + ! array_key_exists($pos + 1, $tokens) || + substr($tokens[$pos + 1], 0, 1) === "-" + ) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Mandatory value for parameter '%s' is not provided" + ), + $opt + ), 500); + } + if ($debug) { + echo "FOUND MUTLIPLE with mandatory param filled\n"; + } + $this->parameters[$option["identifier"]][] = $tokens[$pos + 1]; + unset($tokens[$pos]); + unset($tokens[$pos + 1]); + } else { + if ($debug) { + echo "Not found\n"; + } + } + } + } + } + } + } + + // Manage the restOfLine + foreach ($tokens as $key => $tok) { + if ($tok === "--" && array_key_exists($key + 1, $tokens)) { + $this->restOfLine[] = $tokens[$key + 1]; + unset($tokens[$key]); + unset($tokens[$key + 1]); + continue; + } + if (substr($tok, 0, 1) === "-") { + continue; + } + $this->restOfLine[] = $tok; + unset($tokens[$key]); + } + if (count($tokens)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Provided tokens are not known: %s" + ), implode(",", $tokens)), 500); + } + if ($this->parameters === null) { + $this->parameters = array(); + } + return $this; + } + + /** Get the value of the option if set in the command line. If simulate is + * defined, use it. + * Return false if the option is not set + * Return true if the option is set without parameter + * Return the content of the parameter if the option is set and parameter is + * defined + * Throw an exception if the identifier is not set + * @param string $identifier The identifier option to get + */ + public function get($identifier) + { + $exists = false; + foreach ($this->options as $opt) { + if ($opt["identifier"] === $identifier) { + $exists = true; + break; + } + } + if ($exists === false) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Provided parameter is not known: %s" + ), $identifier), 500); + } + if ($this->parameters === null) { + $this->scan(); + } + if (array_key_exists($identifier, $this->parameters)) { + return $this->parameters[$identifier]; + } + if ($opt["multiple"] > 1) { + return array(); + } + return false; + } + + /** Get the value found in the rest of line (after the double dashes) + */ + public function restOfLine() + { + if ($this->restOfLine === null) { + $this->scan(); + } + return $this->restOfLine; + } + + /** Get the name of the program found in the command line + */ + public function programName() + { + if ($this->programName === null) { + $this->scan(); + } + return $this->programName; + } + + /** Get the Help message with all the descriptions and options + */ + public function help() + { + if (count($this->options) === 0) { + return dgettext("domframework", "No option defined") . "\n"; + } + $d = ""; + foreach ($this->options as $opt) { + $i = 0; + foreach (array("short", "long") as $len) { + foreach ($opt[$len] as $option) { + if (strpos($option, ":") !== false) { + $param = true; + } else { + $param = false; + } + if (strpos($option, "::") !== false) { + $paramOptional = true; + } else { + $paramOptional = false; + } + if ($i > 0) { + $d .= ", "; + } + $d .= str_replace(":", "", $option); + if ($param) { + $d .= " "; + if ($paramOptional) { + $d .= "["; + } + $d .= $opt["paramName"]; + if ($paramOptional) { + $d .= "]"; + } + } + $i++; + } + } + $d .= "\n\t" . $opt["description"]; + $d .= "\n"; + } + return $d; } - return $d; - } } diff --git a/src/Graph.php b/src/Graph.php index c8c2a05..34dbf25 100644 --- a/src/Graph.php +++ b/src/Graph.php @@ -1,4 +1,5 @@ @@ -14,2591 +15,438 @@ namespace Domframework; */ class Graph { - /** The X axis object - */ - public $axisX=null; + /** The X axis object + */ + public $axisX = null; - /** The main Y axis object - */ - public $axisY1=null; + /** The main Y axis object + */ + public $axisY1 = null; - /** The optional secondary Y axis object - */ - public $axisY2=null; + /** The optional secondary Y axis object + */ + public $axisY2 = null; - /** The legend object - */ - public $legend=null; + /** The legend object + */ + public $legend = null; - /** The graph title object - */ - public $title=null; + /** The graph title object + */ + public $title = null; - /** The height of the graph (150px by default) - */ - private $height = 200; + /** The height of the graph (150px by default) + */ + private $height = 200; - /** The width of the graph (200px by default) - */ - private $width = 300; + /** The width of the graph (200px by default) + */ + private $width = 300; - /** The background color of the graph (white by default) - */ - private $bgcolor = "whitesmoke"; + /** The background color of the graph (white by default) + */ + private $bgcolor = "whitesmoke"; - /** The graph style by default. Each serie can define another value - */ - private $style = null; + /** The graph style by default. Each serie can define another value + */ + private $style = null; - /** The data object - */ - public $data = null; + /** The data object + */ + public $data = null; - /** The series object - */ - public $series = null; + /** The series object + */ + public $series = null; - /** Constructor : create the objects - */ - public function __construct () - { - if (! function_exists ("imagecreatetruecolor")) - throw new \Exception (dgettext ("domframework", - "No GD support in PHP : can't create image"), 500); - if (! function_exists ("bccomp")) - throw new \Exception (dgettext ("domframework", - "No BCMath support in PHP : can't create image"), 500); - $this->title = new GraphTitle (); - $this->legend = new GraphLegend (); - $this->data = new GraphData (); - $this->series = new GraphSeries (); - $this->axisX = new GraphAxisX (); - $this->axisY1 = new GraphAxisY1 (); - $this->axisY2 = new GraphAxisY2 (); - // Default values - $defaultTitleFontFile = "/usr/share/fonts/truetype/liberation/". + /** Constructor : create the objects + */ + public function __construct() + { + if (! function_exists("imagecreatetruecolor")) { + throw new \Exception(dgettext( + "domframework", + "No GD support in PHP : can't create image" + ), 500); + } + if (! function_exists("bccomp")) { + throw new \Exception(dgettext( + "domframework", + "No BCMath support in PHP : can't create image" + ), 500); + } + $this->title = new GraphTitle(); + $this->legend = new GraphLegend(); + $this->data = new GraphData(); + $this->series = new GraphSeries(); + $this->axisX = new GraphAxisX(); + $this->axisY1 = new GraphAxisY1(); + $this->axisY2 = new GraphAxisY2(); + // Default values + $defaultTitleFontFile = "/usr/share/fonts/truetype/liberation/" . "LiberationSans-Bold.ttf"; - $defaultFontFile = "/usr/share/fonts/truetype/liberation/". + $defaultFontFile = "/usr/share/fonts/truetype/liberation/" . "LiberationSans-Regular.ttf"; - $this->title->fontfile ($defaultTitleFontFile); - $this->legend->fontfile ($defaultFontFile); - $this->axisX->fontfile ($defaultFontFile); - $this->axisY1->fontfile ($defaultFontFile); - $this->axisY2->fontfile ($defaultFontFile); - $this->axisX->axisColor ("grey"); - $this->axisY1->axisColor ("grey"); - $this->axisY1->gridColor ("grey"); - $this->axisY2->axisColor ("grey"); - $this->style ("line"); - $this->style()->palette ("basic"); - } - - /** Set the title position of the graph if the parameter is provided. - * Get the title position of the graph if the parameter is not provided - * @param string|null $titlePosition The title position of the graph - */ - public function titlePosition ($titlePosition = null) - { - if ($titlePosition === null) - return $this->titlePosition; - if (! is_string ($titlePosition) || - ( $titlePosition !== "top" && $titlePosition !== "bottom")) - throw new \Exception (dgettext ("domframework", - "Invalid titlePosition provided to graph"), 406); - $this->titlePosition = $titlePosition; - return $this; - } - - /** Set the height of the graph if the parameter is provided. - * Get the height of the graph if the parameter is not provided - * @param integer|null $height The height of the graph - */ - public function height ($height = null) - { - if ($height === null) - return $this->height; - if (! is_integer ($height) || $height < 0 || $height > 3000) - throw new \Exception (dgettext ("domframework", - "Invalid height provided to graph"), 406); - $this->height = $height; - return $this; - } - - /** Set the background-color of the graph if the parameter is provided. - * Get the background-color of the graph if the parameter is not provided - * @param string|null $bgcolor The background-color of the graph - */ - public function bgcolor ($bgcolor = null) - { - if ($bgcolor === null) - return $this->bgcolor; - if (! is_string ($bgcolor) || - ! in_array ($bgcolor, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid bgcolor provided to graph"), 406); - $this->bgcolor = $bgcolor; - return $this; - } - - /** Set the width of the graph if the parameter is provided. - * Get the width of the graph if the parameter is not provided - * @param integer|null $width The width of the graph - */ - public function width ($width = null) - { - if ($width === null) - return $this->width; - if (! is_integer ($width) || $width < 0 || $width > 3000) - throw new \Exception (dgettext ("domframework", - "Invalid width provided to graph"), 406); - $this->width = $width; - return $this; - } - - /** Set the default style of the graph if the parameter is provided. - * Get the default style of the graph if the parameter is not provided - * @param string|null $style The style of the graph - */ - public function style ($style = null) - { - if ($style === null) - return $this->style; - if (! is_string ($style) || - ! in_array ($style, array ("line", "points", "linePoints"))) - throw new \Exception (dgettext ("domframework", - "Invalid style provided to graph"), 406); - $styleClass = __NAMESPACE__."\\GraphStyle".ucfirst($style); - if ($this->style === null || $this->style ()->name () !== $style) - { - $this->style = new $styleClass (); - $this->style()->palette ("basic"); - } - return $this->style; - } - - /** Draw the graph to the screen with the previous defined parameters - */ - private function drawReal () - { - // Read the data - $series = $this->data->getSeries (); - foreach ($this->series->getList () as $serie) - { - // Remove the previous defined series which doesn't exists in the data - if (! array_key_exists ($serie, $series)) - $this->series->remove ($serie); + $this->title->fontfile($defaultTitleFontFile); + $this->legend->fontfile($defaultFontFile); + $this->axisX->fontfile($defaultFontFile); + $this->axisY1->fontfile($defaultFontFile); + $this->axisY2->fontfile($defaultFontFile); + $this->axisX->axisColor("grey"); + $this->axisY1->axisColor("grey"); + $this->axisY1->gridColor("grey"); + $this->axisY2->axisColor("grey"); + $this->style("line"); + $this->style()->palette("basic"); } - // Look for the min/max of the axis and use the data maximum if the user - // doesn't define it previously. The min/max are defined on ALL the series - // can not be defined by the axis directely - $minValueX = null; - $maxValueX = null; - $minValueY1 = null; - $maxValueY1 = null; - $minValueY2 = null; - $maxValueY2 = null; - foreach ($series as $serie=>$data) + /** Set the title position of the graph if the parameter is provided. + * Get the title position of the graph if the parameter is not provided + * @param string|null $titlePosition The title position of the graph + */ + public function titlePosition($titlePosition = null) { - // Add the data to the series or create them if they doesn't exists - $this->series->serie ($serie)->data ($data); - // Look for min/max and set the data for X axis - $this->axisX->data (array_keys ($data)); - if ($minValueX === null) - $minValueX = $this->series->serie ($serie)->minKey (); - $minValueX = min ($minValueX, - $this->series->serie ($serie)->minKey ()); - if ($maxValueX === null) - $maxValueX = $this->series->serie ($serie)->maxKey (); - $maxValueX = max ($maxValueX, - $this->series->serie ($serie)->maxKey ()); - if (! $this->series->serie ($serie)->axisYsecondary ()) - { - // Look for min/max for Y1 axis - if ($minValueY1 === null) - $minValueY1 = $this->series->serie ($serie)->minValue (); - $minValueY1 = min ($minValueY1, - $this->series->serie ($serie)->minValue ()); - $maxValueY1 = max ($maxValueY1, - $this->series->serie ($serie)->maxValue ()); - } - else - { - // Look for min/max for Y2 axis - if ($minValueY2 === null) - $minValueY2 = $this->series->serie ($serie)->minValue (); - $minValueY2 = min ($minValueY2, - $this->series->serie ($serie)->minValue ()); - $maxValueY2 = max ($maxValueY2, - $this->series->serie ($serie)->maxValue ()); - } - } - - // Force the graph to display the 0 value - //if ($minValueY1 > 0 && $maxValueY1 > 0) - // $minValueY1 = 0; - //if ($minValueY1 < 0 && $maxValueY1 < 0) - // $minValueY1 = 0; - //if ($minValueY2 > 0 && $maxValueY2 > 0) - // $minValueY2 = 0; - //if ($minValueY2 < 0 && $maxValueY2 < 0) - // $minValueY2 = 0; - - // Look for numeric or labeled axis - $numericalX = null; - $numericalY1 = null; - $numericalY2 = null; - foreach ($series as $serie=>$data) - { - $numericalKey = $this->series->serie ($serie)->numericalKey (); - if ($numericalX === null || $numericalX === true) - { - if ($numericalKey === false) - $numericalX = false; - else - $numericalX = true; - } - $numericalValue = $this->series->serie ($serie)->numericalValue (); - if (! $this->series->serie ($serie)->axisYsecondary ()) - { - if ($numericalY1 === null || $numericalY1 === true) - { - if ($numericalValue === false) - $numericalY1 = false; - else - $numericalY1 = true; + if ($titlePosition === null) { + return $this->titlePosition; } - } - else - { - if ($numericalY2 === null || $numericalY2 === true) - { - if ($numericalValue === false) - $numericalY2 = false; - else - $numericalY2 = true; + if ( + ! is_string($titlePosition) || + ($titlePosition !== "top" && $titlePosition !== "bottom") + ) { + throw new \Exception(dgettext( + "domframework", + "Invalid titlePosition provided to graph" + ), 406); } - } - } - $this->axisX->numerical ($numericalX); - $this->axisY1->numerical ($numericalY1); - $this->axisY2->numerical ($numericalY2); - - if ($minValueX !== null && $this->axisX->min () === null) - $this->axisX->min ($minValueX); - if ($maxValueX !== null && $this->axisX->max () === null) - $this->axisX->max ($maxValueX); - if ($minValueY1 !== null && $this->axisY1->min () === null) - $this->axisY1->min ($minValueY1); - if ($maxValueY1 !== null && $this->axisY1->max () === null) - $this->axisY1->max ($maxValueY1); - if ($minValueY2 !== null && $this->axisY2->min () === null) - $this->axisY2->min ($minValueY2); - if ($maxValueY2 !== null && $this->axisY2->max () === null) - $this->axisY2->max ($maxValueY2); - - // Manage the styles for each serie - foreach ($this->series->getList () as $number=>$serie) - { - if ($this->series->serie ($serie)->style () === null) - $this->series->serie ($serie)->style ($this->style); - if ($this->series->serie ($serie)->style ()->palette () === null) - $this->series->serie ($serie)->style ()->palette ( - $this->style->palette ()); - $this->series->serie ($serie)->style ()->number ($number); + $this->titlePosition = $titlePosition; + return $this; } - // Create the image - $gd = imagecreatetruecolor ($this->width, $this->height); - // Put the background color - imagefilledrectangle ($gd, 0, 0, $this->width - 1 , $this->height - 1 , - Color::allocateFromText ($gd, $this->bgcolor)); - // The coordinates of the free space. Will be modified each time something - // is drawing on the graph - // xtop, ytop, xbottom, ybottom - $free = array (0, 0, imagesx ($gd), imagesy ($gd)); - // Add the title on top - $free = $this->title->draw ($gd, $free); - // Add the legend on right - $free = $this->legend->draw ($gd, $free, $this->series); - - // If there is no title, add an offset of 10px to display correctely the - // first label of the Y axis - if ($free[1] === 0) - $free[1] = 10; - - // Add the axis - // Need two passes as the X axis can modify the Y axes - $this->axisX->top ($free[1]); - $this->axisX->bottom ($free[3] - 1); - $this->axisY1->top ($free[1]); - $this->axisY2->top ($free[1]); - $this->axisY1->bottom ($free[3] - 1); - $this->axisY2->bottom ($free[3] - 1); - $Xleft = $this->axisY1->getWidth ($gd); - $Xright = $free[2] - $this->axisY2->getWidth ($gd); - $this->axisX->left ($Xleft); - $this->axisX->right ($Xright); - $Ybottom = $this->height - $this->axisX->getHeight ($gd); - $this->axisY1->right ($Xright); - $this->axisY1->bottom ($Ybottom); - //$this->axisY1->left (???); - $this->axisY2->right ($Xleft); - $this->axisY2->bottom ($Ybottom); - $this->axisY2->left ($Xright); - - // Draw the axis - $this->axisX->draw ($gd); - $this->axisY1->draw ($gd); - $this->axisY2->draw ($gd); - - // Add the graph part for each serie - $lastFree = $free; - foreach ($this->series->getList () as $number=>$serie) + /** Set the height of the graph if the parameter is provided. + * Get the height of the graph if the parameter is not provided + * @param integer|null $height The height of the graph + */ + public function height($height = null) { - // As the series are superposed, do not update the $free each time - if (! $this->series->serie ($serie)->axisYsecondary ()) - $lastFree = $this->series->serie ($serie)->draw ($gd, $free, - $this->axisX, $this->axisY1); - else - $lastFree = $this->series->serie ($serie)->draw ($gd, $free, - $this->axisX, $this->axisY2); - } - $free = $lastFree; - imagepng ($gd); - imagedestroy ($gd); - } - - /** Draw the graph to the screen with the previous defined parameters - */ - public function drawImage () - { - header ('Content-Type: image/png'); - $this->drawReal (); - } - - /** Return the image coded in base64 - * @return string The base64 string - */ - public function drawBase64 () - { - ob_start (); - $this->drawReal (); - return base64_encode (ob_get_clean()); - } -} - -/** The series objects */ -class GraphSeries -{ - /** The series stored */ - private $series = array (); - - /** Return the serie object choosed. If doesn't exists, it is created before - * be returned - * @param string $name The name of the serie to create - */ - public function serie ($name) - { - if (is_integer ($name)) - $name = dgettext ("domframework", "Serie")." $name"; - if (! is_string ($name)) - throw new \Exception (dgettext ("domframework", - "Can't get a serie if the name is not a string"), - 406); - if (! array_key_exists ($name, $this->series)) - $this->series[$name] = new GraphSerie ($name); - return $this->series[$name]; - } - - /** Get the list of the defined series - */ - public function getList () - { - $series = []; - foreach ($this->series as $name => $serie) - { - if ($serie->hide() === true) - continue; - $series[] = $name; - } - return $series; - } - - /** Remove an existing serie - * @param string $name The name of the serie to remove - */ - public function remove ($name) - { - if (! is_string ($name)) - throw new \Exception (dgettext ("domframework", - "Can't remove a serie if the name is not a string"), - 406); - if (array_key_exists ($name, $this->series)) - unset ($this->series[$name]); - } -} - -/** The serie object */ -class GraphSerie -{ - /** The name of the serie - */ - private $name; - - /** The data values for the serie - */ - private $data; - - /** The numericalKey is true if all the keys are numeric - */ - private $numericalKey =null; - - /** The minimum key of the serie - */ - private $minKey = null; - - /** The maximum key of the serie - */ - private $maxKey = null; - - /** The numericalValue is true if all the values are numeric - */ - private $numericalValue =null; - - /** The minimum value of the serie - */ - private $minValue = null; - - /** The maximum value of the serie - */ - private $maxValue = null; - - /** The style object for the serie - */ - private $style; - /** If set, hide this serie and do not display it - */ - private $hide; - - /** The axis used to draw the serie. - * If false for main Y axis - * If true for secondary Y axis - */ - private $axisYsecondary = false; - - /** When creating the serie, save the name - * @param string $name The name of the serie - */ - public function __construct ($name) - { - if (! is_string ($name)) - throw new \Exception (dgettext ("domframework", - "Can't create a serie if the name is not a string"), - 406); - $this->name = $name; - } - - /** Set the data for the serie - If the parameter is not provided, return the actual $data value - * @param array|null $data The data to store in the serie - */ - public function data ($data = null) - { - if ($data === null) - return $this->data; - if (! is_array ($data)) - throw new \Exception (dgettext ("domframework", - "Can't create a serie data if the value is not an array"), - 406); - $this->data = $data; - $this->minmax (); - return $this; - } - - /** Get the minimum and maximum values and keys - */ - private function minmax () - { - if ($this->data === null) - return null; - foreach ($this->data as $key=>$value) - { - if ($this->minValue === null && is_numeric ($value)) - $this->minValue = $value; - if ($this->minKey === null && is_numeric ($key)) - $this->minKey = $key; - if (is_numeric ($value)) - { - $this->minValue = min ($this->minValue, $value); - $this->maxValue = max ($this->maxValue, $value); - } - if (is_numeric ($key)) - { - $this->minKey = min ($this->minKey, $key); - $this->maxKey = max ($this->maxKey, $key); - } - if (! is_numeric ($key) && $this->numericalKey === null) - $this->numericalKey = false; - if (! is_numeric ($value) && $value !== null && - $this->numericalValue === null) - $this->numericalValue = false; - } - if ($this->numericalKey === null) - $this->numericalKey = true; - if ($this->numericalValue === null) - $this->numericalValue = true; - } - - /** Set/get the numeric value of the serie - * If the parameter is not provided, return the actual state - * @param boolean|null $numericalValue The state of the numeric value - */ - public function numericalValue ($numericalValue = null) - { - if ($numericalValue === null) - return $this->numericalValue; - if (! is_bool ($numericalValue)) - throw new \Exception (dgettext ("domframework", - "Invalid numericalValue provided to serie"), 406); - $this->numericalValue = $numericalValue; - return $this; - } - - /** The minimum value of the serie - */ - public function minValue () - { - if ($this->minValue === null && $this->data !== null) - $this->minmax (); - return $this->minValue; - } - - /** The maximum value of the serie - */ - public function maxValue () - { - if ($this->maxValue === null && $this->data !== null) - $this->minmax (); - return $this->maxValue; - } - - /** Set/get the numeric key of the serie - * If the parameter is not provided, return the actual state - * @param boolean|null $numericalKey The state of the numeric key - */ - public function numericalKey ($numericalKey = null) - { - if ($numericalKey === null) - return $this->numericalKey; - if (! is_bool ($numericalKey)) - throw new \Exception (dgettext ("domframework", - "Invalid numericalKey provided to serie"), 406); - $this->numericalKey = $numericalKey; - return $this; - } - - /** The minimum key of the serie - */ - public function minKey () - { - if ($this->minKey === null && $this->data !== null) - $this->minmax (); - return $this->minKey; - } - - /** The maximum key of the serie - */ - public function maxKey () - { - if ($this->maxKey === null && $this->data !== null) - $this->minmax (); - return $this->maxKey; - } - - /** The number of elements in the serie - */ - public function count () - { - return count ($this->data); - } - - /** Set/Get the graph style for the serie - * If the parameter is not provided, return the actual state - * @param string|object|null $style The graph style - */ - public function style ($style = null) - { - if ($style === null) - return $this->style; - if (is_object ($style)) - { - $this->style = clone $style; - return $this->style; - } - if (! is_string ($style) || - ! in_array ($style, array ("line", "points", "linePoints"))) - throw new \Exception (dgettext ("domframework", - "Invalid style provided to serie"), 406); - $styleClass = "GraphStyle".$style; - if ($this->style === null) - $this->style = new $styleClass (); - return $this->style; - } - /** Set/Get the hidden state of the serie - * If the parameter is not provided, return the actual state - * @param boolean|null $hide The hidden state - */ - public function hide ($hide = null) - { - if ($hide === null) - return $this->hide; - if (! is_bool ($hide)) - throw new \Exception (dgettext ("domframework", - "Invalid hide mode provided to serie"), 406); - $this->hide = $hide; - return $this; - } - - /** The serie is based on the secondary Y axis - * Set the value if the parameter is provided, get the value if the parameter - * is not set - * @param boolean|null $axisYsecondary The Serie on secondary Y axis - */ - public function axisYsecondary ($axisYsecondary = null) - { - if ($axisYsecondary === null) - return $this->axisYsecondary; - if (! is_bool ($axisYsecondary)) - throw new \Exception (dgettext ("domframework", - "Invalid axisYsecondary provided to graph axisYsecondary"), - 406); - $this->axisYsecondary = $axisYsecondary; - return $this; - } - - /** Draw the serie with the defined style class - * @param resource $gd The resource to modify - * @param array $free The free space coordinates on the graphic - * @param object $axisX The axis X used on the graph - * @param object $axisY The axis Y used on the graph - */ - public function draw ($gd, $free, $axisX, $axisY) - { - if ($this->hide === true) - return; - $this->style->draw ($gd, $free, $this->data, $axisX, $axisY); - } -} - -/** Read the data */ -class GraphData -{ - /** Store the data when the user provided them. Store them in array form - */ - private $data; - - /** The titles are on the first line - */ - private $titlesOnFirstLine = null; - - /** The titles are on the first column - */ - private $titlesOnFirstColumn = null; - - /** The data are stored horizontally - */ - private $horizontalData = null; - - /** Get the data from an indexed array - * @param array $array The data array to graph - */ - public function arrayIndexed ($array) - { - $this->data = $array; - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "Invalid Array Parameter provided: not an array"), - 406); - return $this; - } - - /** Get the data from an associative array - * The associative array are provided by database results - * @param array $array The data array to graph - */ - public function arrayAssociative ($array) - { - if (! is_array ($array)) - throw new \Exception (dgettext ("domframework", - "Invalid Array Parameter provided: not an array"), - 406); - $titles = array (); - $this->data = array (); - foreach ($array as $line=>$lineArr) - { - foreach ($lineArr as $key=>$cell) - { - $titles[$key] = ""; - $this->data[$line][] = $cell; - } - - } - array_unshift ($this->data, array_keys ($titles)); - return $this; - } - - /** Get the data from a CSV string - * @param string $csv The CSV string - */ - public function csv ($csv) - { - $csv = trim ($csv); - $lines = preg_split ('/( *\R)+/s', $csv); - $this->data = array_map('str_getcsv', $lines); - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "Invalid CSV provided: not converted to array"), - 406); - return $this; - } - - /** Get the data from a JSON string - * @param string $json The JSON string - */ - public function json ($json) - { - $this->data = json_decode ($json, true); - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "Invalid JSON provided: not converted to array"), - 406); - return $this; - } - - /** Titles on first line - * Set the value if the parameter is provided, get the value if the parameter - * is not set - * @param boolean|null $titlesOnFirstLine The titles on first line - */ - public function titlesOnFirstLine ($titlesOnFirstLine = null) - { - if ($titlesOnFirstLine === null) - return $this->titlesOnFirstLine; - if (! is_bool ($titlesOnFirstLine)) - throw new \Exception (dgettext ("domframework", - "Invalid titlesOnFirstLine provided to graph titlesOnFirstLine"), - 406); - $this->titlesOnFirstLine = $titlesOnFirstLine; - return $this; - } - - /** Titles on first column - * Set the value if the parameter is provided, get the value if the parameter - * is not set - * @param boolean|null $titlesOnFirstColumn The titles on first column - */ - public function titlesOnFirstColumn ($titlesOnFirstColumn = null) - { - if ($titlesOnFirstColumn === null) - return $this->titlesOnFirstColumn; - if (! is_bool ($titlesOnFirstColumn)) - throw new \Exception (dgettext ("domframework", - "Invalid titlesOnFirstColumn provided to graph titlesOnFirstColumn"), - 406); - $this->titlesOnFirstColumn = $titlesOnFirstColumn; - return $this; - } - - /** The data are stored horizontally in the array - * Set the value if the parameter is provided, get the value if the parameter - * is not set - * @param boolean|null $horizontalData The data are stored horizontally - */ - public function horizontalData ($horizontalData = null) - { - if ($horizontalData === null) - return $this->horizontalData; - if (! is_bool ($horizontalData)) - throw new \Exception (dgettext ("domframework", - "Invalid horizontalData provided to graph horizontalData"), - 406); - $this->horizontalData = $horizontalData; - return $this; - } - - /** Get the series in an array with the associated values - */ - public function getSeries () - { - // 0. If there is no data to graph, nothing to do - if (count ($this->data) === 0) - return array (); - - // 1. If $this->titlesOnFirstLine === null, look if the first line contains - // titles - if ($this->titlesOnFirstLine === null) - { - $this->titlesOnFirstLine = true; - if (count ($this->data) === 1) - $this->titlesOnFirstLine = false; - if (is_array ($this->data[0])) - { - foreach ($this->data[0] as $cell) - { - if (is_numeric ($cell)) - { - $this->titlesOnFirstLine = false; - break; - } + if ($height === null) { + return $this->height; } - } - else - { - $this->titlesOnFirstLine = false; - } + if (! is_integer($height) || $height < 0 || $height > 3000) { + throw new \Exception(dgettext( + "domframework", + "Invalid height provided to graph" + ), 406); + } + $this->height = $height; + return $this; } - // 2. If $this->titlesOnFirstColumn === null, look if the first column - // contains titles - if ($this->titlesOnFirstColumn === null) + /** Set the background-color of the graph if the parameter is provided. + * Get the background-color of the graph if the parameter is not provided + * @param string|null $bgcolor The background-color of the graph + */ + public function bgcolor($bgcolor = null) { - if (count ($this->data[0]) === 1) - $this->titlesOnFirstColumn = false; - else - { - $this->titlesOnFirstColumn = true; - foreach ($this->data as $lineArr) - { - if (is_numeric ($lineArr[0])) - { - $this->titlesOnFirstColumn = false; - break; - } + if ($bgcolor === null) { + return $this->bgcolor; } - } + if ( + ! is_string($bgcolor) || + ! in_array($bgcolor, Color::colorList()) + ) { + throw new \Exception(dgettext( + "domframework", + "Invalid bgcolor provided to graph" + ), 406); + } + $this->bgcolor = $bgcolor; + return $this; } - // 3. If $this->horizontalData === null, look for orientation with the - // titles states - if ($this->horizontalData === null) + /** Set the width of the graph if the parameter is provided. + * Get the width of the graph if the parameter is not provided + * @param integer|null $width The width of the graph + */ + public function width($width = null) { - if ($this->titlesOnFirstColumn === true || - ! array_key_exists (1, $this->data)) - $this->horizontalData = true; - else - $this->horizontalData = false; + if ($width === null) { + return $this->width; + } + if (! is_integer($width) || $width < 0 || $width > 3000) { + throw new \Exception(dgettext( + "domframework", + "Invalid width provided to graph" + ), 406); + } + $this->width = $width; + return $this; } - // 4. Create the series - $colTitles = array (); - $lineTitles = array (); - $series = array (); - foreach ($this->data as $linePos => $lineArr) + /** Set the default style of the graph if the parameter is provided. + * Get the default style of the graph if the parameter is not provided + * @param string|null $style The style of the graph + */ + public function style($style = null) { - if (! is_array ($lineArr)) - $lineArr = array ($lineArr); - if ($linePos === 0) - { - if ($this->titlesOnFirstLine) - { - $colTitles = $lineArr; - if ($this->horizontalData === false) - { - // First line with titles and vertical data: get the series names - $series = array_flip ($lineArr); - foreach ($series as &$value) - $value = array (); - if ($this->titlesOnFirstColumn) - array_shift ($series); - } - continue; + if ($style === null) { + return $this->style; } - else - { - foreach ($lineArr as $i=>$value) - $colTitles[$i] = $i; + if ( + ! is_string($style) || + ! in_array($style, array("line", "points", "linePoints")) + ) { + throw new \Exception(dgettext( + "domframework", + "Invalid style provided to graph" + ), 406); } - } - elseif (count ($lineArr) !== count ($colTitles)) - throw new \Exception (sprintf (dgettext ("domframework", - "Invalid data provided: line %d doesn't have the same number ". - "of elements as the first line (%d != %d elements)"), - $linePos+1, count ($lineArr), count ($colTitles)), 406); - foreach ($lineArr as $colPos => $cell) - { - $cell = trim ($cell); - if ($colPos === 0) - { - if ($this->titlesOnFirstColumn) - { - $lineTitles[$linePos] = $cell; - if ($this->horizontalData === true) - { - $series[$cell] = array (); + $styleClass = __NAMESPACE__ . "\\GraphStyle" . ucfirst($style); + if ($this->style === null || $this->style()->name() !== $style) { + $this->style = new $styleClass(); + $this->style()->palette("basic"); + } + return $this->style; + } + + /** Draw the graph to the screen with the previous defined parameters + */ + private function drawReal() + { + // Read the data + $series = $this->data->getSeries(); + foreach ($this->series->getList() as $serie) { + // Remove the previous defined series which doesn't exists in the data + if (! array_key_exists($serie, $series)) { + $this->series->remove($serie); } - continue; - } - else - { - $lineTitles[$linePos] = $linePos; - } - } - if (! is_numeric ($cell)) - $cell = null; - else - $cell = $cell+0.0; - if ($this->horizontalData === false) - $series[$colTitles[$colPos]][$lineTitles[$linePos]] = $cell; - else - $series[$lineTitles[$linePos]][$colTitles[$colPos]] = $cell; - } - } - return $series; - } -} - -/** The graphTitle object */ -class GraphTitle -{ - /** The title text - */ - private $text = null; - - /** The TTF fontfile to use - */ - private $fontfile = null; - - /** The font size to use - */ - private $fontsize = 14; - - /** The title color - */ - private $color = "black"; - - /** The padding arround the title (in px) - */ - private $padding = 10; - - /** Set the text of the title if the parameter is provided. - * Get the text of the title if the parameter is not provided - * @param string|null $text The text of the title - */ - public function text ($text = null) - { - if ($text === null) - return $this->text; - if (! is_string ($text) || strlen ($text) < 0 || strlen ($text) > 50) - throw new \Exception (dgettext ("domframework", - "Invalid text provided to graph title"), 406); - $this->text = $text; - return $this; - } - - /** Set the fontfile of the title if the parameter is provided. - * Get the fontfile of the title if the parameter is not provided - * @param string|null $fontfile The fontfile of the title - */ - public function fontfile ($fontfile = null) - { - if ($fontfile === null) - return $this->fontfile; - if (! is_string ($fontfile) || strlen ($fontfile) < 0 || - ! file_exists ($fontfile) || ! is_readable ($fontfile)) - throw new \Exception (dgettext ("domframework", - "Invalid fontfile provided to graph title"), 406); - $this->fontfile = $fontfile; - return $this; - } - - /** Set the font size of the title if the parameter is provided. - * Get the font size of the title if the parameter is not provided - * @param integer|null $fontsize The font size of the title - */ - public function fontsize ($fontsize = null) - { - if ($fontsize === null) - return $this->fontsize; - if (! is_integer ($fontsize) || $fontsize < 2 || $fontsize > 100) - throw new \Exception (dgettext ("domframework", - "Invalid fontsize provided to graph title"), 406); - $this->fontsize = $fontsize; - return $this; - } - - /** Set the color of the title if the parameter is provided. - * Get the color of the title if the parameter is not provided - * @param string|null $color The color of the title - */ - public function color ($color = null) - { - if ($color === null) - return $this->color; - if (! is_string ($color) || - ! in_array ($color, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid color provided to graph title"), 406); - $this->color = $color; - return $this; - } - - /** Set the padding of the title if the parameter is provided. - * Get the padding of the title if the parameter is not provided - * @param integer|null $padding The padding of the title - */ - public function padding ($padding = null) - { - if ($padding === null) - return $this->padding; - if (! is_integer ($padding) || $padding < 0 || $padding > 200) - throw new \Exception (dgettext ("domframework", - "Invalid padding provided to graph title"), 406); - $this->padding = $padding; - return $this; - } - - /** Draw the title in the $gd resource provided - * @param resource $gd The resource to modify - * @param array $free The free space coordinates on the graphic - * @return array the new free coordinates array - */ - public function draw ($gd, $free) - { - if ($this->text === null) - return $free; - // Look for the bounding box around the text. The bounding is not write on - // the image and return the coordinates for the text box - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, $this->text); - // Calculate the position of the text to be centered on the graph - // The padding is only on vertical : the x is centered - $x = floor (($free[2] - $free[0] - abs ($bbox[4] - $bbox[0])) / 2); - $y = ceil ($free[1] + abs ($bbox[5] - $bbox[1])) + $this->padding; - $x += $free[0]; - $y += $free[1]; - imagettftext ($gd, $this->fontsize, 0, $x, $y, - Color::allocateFromText ($gd, $this->color), - $this->fontfile, $this->text); - return array (intval ($free[0]), intval ($free[1] + $y + $this->padding), - intval ($free[2]), intval ($free[3])); - } -} - -/** The graphLegend object */ -class GraphLegend -{ - /** Show the legend (no legend by default) - */ - private $show = false; - - /** The TTF fontfile to use - */ - private $fontfile = null; - - /** The font size to use - */ - private $fontsize = 10; - - /** The legend color for the font - */ - private $color = "black"; - - /** The legend background-color - */ - private $bgcolor = "white"; - - /** The legend border color - */ - private $borderColor = "black"; - - /** The padding arround the title (in px) - */ - private $padding = 10; - - /** Set the legend display status if the parameter is provided. - * Get the legend display status if the parameter is not provided - * @param boolean|null $show The legend display status - */ - public function show ($show = null) - { - if ($show === null) - return $this->show; - if (! is_bool ($show)) - throw new \Exception (dgettext ("domframework", - "Invalid show value provided to graph legend"), 406); - $this->show = $show; - return $this; - } - - /** Set the fontfile of the legend if the parameter is provided. - * Get the fontfile of the legend if the parameter is not provided - * @param string|null $fontfile The fontfile of the legend - */ - public function fontfile ($fontfile = null) - { - if ($fontfile === null) - return $this->fontfile; - if (! is_string ($fontfile) || strlen ($fontfile) < 0 || - ! file_exists ($fontfile) || ! is_readable ($fontfile)) - throw new \Exception (dgettext ("domframework", - "Invalid fontfile provided to graph legend"), 406); - $this->fontfile = $fontfile; - return $this; - } - - /** Set the font size of the legend if the parameter is provided. - * Get the font size of the legend if the parameter is not provided - * @param integer|null $fontsize The font size of the legend - */ - public function fontsize ($fontsize = null) - { - if ($fontsize === null) - return $this->fontsize; - if (! is_integer ($fontsize) || $fontsize < 2 || $fontsize > 100) - throw new \Exception (dgettext ("domframework", - "Invalid fontsize provided to graph legend"), 406); - $this->fontsize = $fontsize; - return $this; - } - - /** Set the color of the legend if the parameter is provided. - * Get the color of the legend if the parameter is not provided - * @param string|null $color The color of the legend - */ - public function color ($color = null) - { - if ($color === null) - return $this->color; - if (! is_string ($color) || - ! in_array ($color, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid color provided to graph legend"), 406); - $this->color = $color; - return $this; - } - - /** Set the background-color of the legend if the parameter is provided. - * Get the background-color of the legend if the parameter is not provided - * @param string|null $bgcolor The background-color of the legend - */ - public function bgcolor ($bgcolor = null) - { - if ($bgcolor === null) - return $this->bgcolor; - if (! is_string ($bgcolor) || - ! in_array ($bgcolor, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid bgcolor provided to graph legend"), 406); - $this->bgcolor = $bgcolor; - return $this; - } - - /** Set the border color of the legend if the parameter is provided. - * Get the border color of the legend if the parameter is not provided - * @param string|null $borderColor The border color of the legend - */ - public function borderColor ($borderColor = null) - { - if ($borderColor === null) - return $this->borderColor; - if (! is_string ($borderColor) || - ! in_array ($borderColor, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid borderColor provided to graph legend"), 406); - $this->borderColor = $borderColor; - return $this; - } - - /** Set the padding of the legend if the parameter is provided. - * Get the padding of the legend if the parameter is not provided - * @param integer|null $padding The padding of the legend - */ - public function padding ($padding = null) - { - if ($padding === null) - return $this->padding; - if (! is_integer ($padding) || $padding < 0 || $padding > 200) - throw new \Exception (dgettext ("domframework", - "Invalid padding provided to graph legend"), 406); - $this->padding = $padding; - return $this; - } - - /** Draw the legend in the $gd resource provided - * @param resource $gd The resource to modify - * @param array $free The free space coordinates on the graphic - * @param object $series The series to graph - * @return array the new free coordinates array - */ - public function draw ($gd, $free, $series) - { - if ($this->show === false) - return $free; - // Look for maxmimum width of the labels - $maxwidth = 0; - $height = 0; - foreach ($series->getList () as $number=>$serie) - { - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, $serie); - $width = abs ($bbox[4] - $bbox[0]); - // TODO : If the serie name is too long, split it ! - // 20px for the sample + the space before the label - if ((20 + $maxwidth) > (($free[2] - $free[0]) / 2)) - throw new \Exception (dgettext ("domframework", - "The serie name in legend must not takes more than half of the graph"), - 500); - if ($number > 0) - $height += $this->padding; - $height += abs ($bbox[5] - $bbox[1]); - $maxwidth = max ($maxwidth, $width); - } - - $x1 = $free[2] - $maxwidth - 20 - $this->padding * 2; - $x2 = $free[2] - $this->padding; - $y1 = $free[1] + $this->padding; - $y2 = $y1 + $height + $this->padding; - - // Size of the border : 1px - $border = 1; - // Draw the background rectangle - imagefilledrectangle ($gd, $x1, $y1, $x2, $y2, - Color::allocateFromText ($gd, $this->borderColor)); - imagefilledrectangle ($gd, $x1+$border, $y1+$border, - $x2-$border, $y2-$border, - Color::allocateFromText ($gd, $this->bgcolor)); - - // Display the serie names - $y = $y1; - foreach ($series->getList () as $number=>$serie) - { - // Write the label - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, $serie); - $height = abs ($bbox[5] - $bbox[1]); - $y += $height; - imagettftext ($gd, $this->fontsize, 0, - $x1 + 30, intval ($y + $height / 2), - Color::allocateFromText ($gd, $this->color), - $this->fontfile, $serie); - // Draw the sample - $series->serie ($serie)->style ()->sample ($gd, $x1 + 15, $y); - $y += $this->padding; - } - $free = array ($free[0], $free[1], $x1 - 5, $free[3]); - return $free; - } -} - -/** The general axis management */ -class GraphAxisGeneral -{ - /** The min value of the axis. Do not use it if the axis is composed of labels - */ - protected $min = null; - - /** The max value of the axis. Do not use it if the axis is composed of labels - */ - protected $max = null; - - /** The label max to display - */ - protected $labelMax; - - /** The label min to display - */ - protected $labelMin; - - /** The data displayed as values on the axis - */ - protected $data; - - /** Set if the axis is only numerical (true) or is composed of labels (false) - */ - protected $numerical; - - /** The minimum bottom position in pixels. Used on vertical axis - */ - protected $bottom; - - /** The maximum top position in pixels. Used on vertical axis - */ - protected $top; - - /** The minimum left position in pixels. Used on horizontal axis - */ - protected $left; - - /** The maximum right position in pixels. Used on horizontal axis - */ - protected $right; - - /** The fontfile to write the labels - */ - protected $fontfile; - - /** The fontsize to write the labels - */ - protected $fontsize = 8; - - /** Axis color - */ - protected $axisColor; - - /** Grid color on the axis - * Can be set to null or "transparent" to not display the grid - */ - protected $gridColor; - - /** Set the min value of the axis if the parameter is provided. - * Get the min value of the axis if the parameter is not provided - * @param integer|null $min The min value of the axis - */ - public function min ($min = null) - { - if ($min === null) - return $this->min; - if (! is_numeric ($min)) - throw new \Exception (dgettext ("domframework", - "Invalid min provided to graph Axis")." ".get_class ($this), 406); - $this->min = $min; - return $this; - } - - /** Set the max value of the axis if the parameter is provided. - * Get the max value of the axis if the parameter is not provided - * @param integer|null $max The max value of the axis - */ - public function max ($max = null) - { - if ($max === null) - return $this->max; - if (! is_numeric ($max)) - throw new \Exception (dgettext ("domframework", - "Invalid max provided to graph Axis")." ".get_class ($this), 406); - $this->max = $max; - return $this; - } - - /** Set the data of the axis if the parameter is provided. - * Get the data of the axis if the parameter is not provided - * @param array|null $data The data of the axis - */ - public function data ($data = null) - { - if ($data === null) - return $this->data; - if (! is_array ($data)) - throw new \Exception (dgettext ("domframework", - "Invalid data provided to graph Axis")." ".get_class ($this), 406); - $this->data = $data; - if ($this->numerical === null) - { - // Look if the provided data are only numerical. Then define the numerical - // property - foreach ($data as $d) - { - if (! is_numeric ($d)) - { - $this->numerical = false; - break; - } - } - if ($this->numerical === null) - $this->numerical = true; - } - return $this; - } - - /** Set if the axis is numerical or composed of labels if the parameter is - * provided. - * Get if the axis is numerical if the parameter is not provided - * @param boolean|null $numerical the axis is numerical - */ - public function numerical ($numerical = null) - { - if ($numerical === null) - return $this->numerical; - if (! is_bool ($numerical)) - throw new \Exception (dgettext ("domframework", - "Invalid numerical parameter provided to graph Axis")." ". - get_class ($this), 406); - $this->numerical = $numerical; - return $this; - } - - /** Set the bottom position of the axis if the parameter is provided. - * Get the bottom position of the axis if the parameter is not provided - * @param integer|null $bottom The bottom position of the axis - */ - public function bottom ($bottom = null) - { - if ($bottom === null) - return $this->bottom; - if (! is_integer ($bottom) || $bottom < 0 || $bottom > 5000) - throw new \Exception (dgettext ("domframework", - "Invalid bottom provided to graph Axis")." ".get_class ($this), 406); - $this->bottom = $bottom; - return $this; - } - - /** Set the top position of the axis if the parameter is provided. - * Get the top position of the axis if the parameter is not provided - * @param integer|null $top The top position of the axis - */ - public function top ($top = null) - { - if ($top === null) - return $this->top; - if (! is_integer ($top) || $top < 0 || $top > 5000) - throw new \Exception (dgettext ("domframework", - "Invalid top provided to graph Axis")." ".get_class ($this), 406); - $this->top = $top; - return $this; - } - - /** Set the left position of the axis if the parameter is provided. - * Get the left position of the axis if the parameter is not provided - * @param integer|null $left The left position of the axis - */ - public function left ($left = null) - { - if ($left === null) - return $this->left; - if (! is_integer ($left) || $left < 0 || $left > 5000) - throw new \Exception (dgettext ("domframework", - "Invalid left provided to graph Axis")." ".get_class ($this), 406); - $this->left = $left; - return $this; - } - - /** Set the right position of the axis if the parameter is provided. - * Get the right position of the axis if the parameter is not provided - * @param integer|null $right The right position of the axis - */ - public function right ($right = null) - { - if ($right === null) - return $this->right; - if (! is_integer ($right) || $right < 0 || $right > 5000) - throw new \Exception (dgettext ("domframework", - "Invalid right provided to graph Axis")." ".get_class ($this), 406); - $this->right = $right; - return $this; - } - - /** Set the fontfile of the labels if the parameter is provided. - * Get the fontfile of the labels if the parameter is not provided - * @param string|null $fontfile The fontfile of the title - */ - public function fontfile ($fontfile = null) - { - if ($fontfile === null) - return $this->fontfile; - if (! is_string ($fontfile) || strlen ($fontfile) < 0 || - ! file_exists ($fontfile) || ! is_readable ($fontfile)) - throw new \Exception (dgettext ("domframework", - "Invalid fontfile provided to graph title"), 406); - $this->fontfile = $fontfile; - return $this; - } - - /** Set the font size of the labels if the parameter is provided. - * Get the font size of the labels if the parameter is not provided - * @param integer|null $fontsize The font size of the title - */ - public function fontsize ($fontsize = null) - { - if ($fontsize === null) - return $this->fontsize; - if (! is_integer ($fontsize) || $fontsize < 2 || $fontsize > 100) - throw new \Exception (dgettext ("domframework", - "Invalid fontsize provided to graph title"), 406); - $this->fontsize = $fontsize; - return $this; - } - - /** Set the axis color if the parameter is provided. - * Get the axis color if the parameter is not provided - * @param string|null $axisColor The axis color - */ - public function axisColor ($axisColor = null) - { - if ($axisColor === null) - return $this->axisColor; - if (! is_string ($axisColor) || - ! in_array ($axisColor, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid axisColor provided to graph axis"), 406); - $this->axisColor = $axisColor; - return $this; - } - - /** Set the grid color if the parameter is provided. - * Get the grid color if the parameter is not provided - * @param string|null $gridColor The grid color - */ - public function gridColor ($gridColor = null) - { - if ($gridColor === null) - return $this->gridColor; - if (! is_string ($gridColor) || - ! in_array ($gridColor, Color::colorList ())) - throw new \Exception (dgettext ("domframework", - "Invalid gridColor provided to graph grid"), 406); - $this->gridColor = $gridColor; - return $this; - } - - /** Calculate the labels that will be displayed on the axis - * @param integer $nbMaxValues The maximum number of values to return - * @return array The array of labels to display - */ - protected function labels ($nbMaxValues) - { - // Activate the debug of this method - $deb = false; - if (! is_int ($nbMaxValues)) - throw new \Exception ( - "Invalid parameter nbMaxValues provided to graphAxisGeneral::labels", - 500); - if ($deb) echo "=========== LABELS\n"; - if ($this->min > 0) - $minLabel = $this->min * 0.90; - else - $minLabel = $this->min * 1.05; - if ($this->max > 0) - $maxLabel = $this->max * 1.05; - else - $maxLabel = $this->max * 0.90; - - $minBase = intval (log10 ($minLabel)) - 1; - $maxBase = intval (log10 ($maxLabel)) - 1; - $base = max ($minBase, $maxBase); - if ($deb) echo "minBase=$minBase, maxBase=$maxBase ===> base = $base\n"; - - if ($base < 0 && $base > -1) - $base = $base - 1; - // The while loop reduce the base to not explode the number of labels - // If there is too much labels, remove one digit and retry - while (1) - { - $this->labelMin = null; - $this->labelMax = null; - $min = round ($minLabel, -1 * $base); - $max = round ($maxLabel, -1 * $base); - if ($deb) echo "min = $min, max = $max\n"; - - $scale = pow (10, $base); - if ($deb) echo "BASE=".($base).", SCALE = $scale\n"; - if ($scale === 0 || $scale === 0.0) - die ("Scale equal 0 on line ".__LINE__."\n"); - $labels = array (); - if ($this->min <= 0 && $this->max >= 0) - { - // Return the 0 label and the values arround it - $zeroAlreadyDraw = false; - for ($i = 0 ; - \bccomp ($i, 1.2 * $max, abs ($base) + 1) < 1 ; - $i += $scale) - { - if ($i === 0) - $zeroAlreadyDraw = true; - if ($deb) echo "Values with Zero : add pos val $i\n"; - $labels[] = $i; - } - for ($i = 0 ; - \bccomp ($i, 1.4 * $min, abs ($base) + 1) >= 0 ; - $i -= $scale) - { - if ($zeroAlreadyDraw === true && $i === 0) - continue; - if ($deb) echo "Values with Zero : add neg val $i\n"; - $labels[] = $i; - } - } - else - { - // No 0 Axis : From $this->min to $this->max - for ($i = $min ; - \bccomp ($i, $max, abs ($base) + 1) < 1 ; - $i += $scale) - { - if ($deb) echo "Values no Zero : add val $i\n"; - $labels[] = $i; - } - } - if (count ($labels) <= $nbMaxValues) - { - foreach ($labels as &$label) - { - if ($base < 0) - $label = sprintf ("%0.".intval (abs ($base))."f", $label); - else - $label = sprintf ("%".intval ($base)."d", $label); - if ($this->labelMin === null || - \bccomp ($this->labelMin, $label, abs ($base) + 1) >= 0) - $this->labelMin = $label; - if ($this->labelMax === null || - \bccomp ($this->labelMax, $label, abs ($base) + 1) <= 0) - $this->labelMax = $label; } - if (\bccomp ($this->labelMin, $this->min, abs ($base) + 1) > 0) - { - // Add a label in the minimum - $this->labelMin = $this->labelMin - $scale; - if ($deb) echo "Force Add Min $this->labelMin\n"; - if ($base < 0) - $labels[] = sprintf ("%0.".intval (abs ($base))."f", - $this->labelMin); - else - $labels[] = sprintf ("%".intval ($base)."d", $this->labelMin); + // Look for the min/max of the axis and use the data maximum if the user + // doesn't define it previously. The min/max are defined on ALL the series + // can not be defined by the axis directely + $minValueX = null; + $maxValueX = null; + $minValueY1 = null; + $maxValueY1 = null; + $minValueY2 = null; + $maxValueY2 = null; + foreach ($series as $serie => $data) { + // Add the data to the series or create them if they doesn't exists + $this->series->serie($serie)->data($data); + // Look for min/max and set the data for X axis + $this->axisX->data(array_keys($data)); + if ($minValueX === null) { + $minValueX = $this->series->serie($serie)->minKey(); + } + $minValueX = min( + $minValueX, + $this->series->serie($serie)->minKey() + ); + if ($maxValueX === null) { + $maxValueX = $this->series->serie($serie)->maxKey(); + } + $maxValueX = max( + $maxValueX, + $this->series->serie($serie)->maxKey() + ); + if (! $this->series->serie($serie)->axisYsecondary()) { + // Look for min/max for Y1 axis + if ($minValueY1 === null) { + $minValueY1 = $this->series->serie($serie)->minValue(); + } + $minValueY1 = min( + $minValueY1, + $this->series->serie($serie)->minValue() + ); + $maxValueY1 = max( + $maxValueY1, + $this->series->serie($serie)->maxValue() + ); + } else { + // Look for min/max for Y2 axis + if ($minValueY2 === null) { + $minValueY2 = $this->series->serie($serie)->minValue(); + } + $minValueY2 = min( + $minValueY2, + $this->series->serie($serie)->minValue() + ); + $maxValueY2 = max( + $maxValueY2, + $this->series->serie($serie)->maxValue() + ); + } } - if (\bccomp ($this->labelMax, $this->max, abs ($base) + 1) < 0) - { - $this->labelMax = $this->labelMax + $scale; - if ($deb) echo "Force Add Max $this->labelMax\n"; - if ($base < 0) - $labels[] = sprintf ("%0.".intval (abs ($base))."f", - $this->labelMax); - else - $labels[] = sprintf ("%".intval ($base)."d", $this->labelMax); + + // Force the graph to display the 0 value + //if ($minValueY1 > 0 && $maxValueY1 > 0) + // $minValueY1 = 0; + //if ($minValueY1 < 0 && $maxValueY1 < 0) + // $minValueY1 = 0; + //if ($minValueY2 > 0 && $maxValueY2 > 0) + // $minValueY2 = 0; + //if ($minValueY2 < 0 && $maxValueY2 < 0) + // $minValueY2 = 0; + + // Look for numeric or labeled axis + $numericalX = null; + $numericalY1 = null; + $numericalY2 = null; + foreach ($series as $serie => $data) { + $numericalKey = $this->series->serie($serie)->numericalKey(); + if ($numericalX === null || $numericalX === true) { + if ($numericalKey === false) { + $numericalX = false; + } else { + $numericalX = true; + } + } + $numericalValue = $this->series->serie($serie)->numericalValue(); + if (! $this->series->serie($serie)->axisYsecondary()) { + if ($numericalY1 === null || $numericalY1 === true) { + if ($numericalValue === false) { + $numericalY1 = false; + } else { + $numericalY1 = true; + } + } + } else { + if ($numericalY2 === null || $numericalY2 === true) { + if ($numericalValue === false) { + $numericalY2 = false; + } else { + $numericalY2 = true; + } + } + } } - if ($this->labelMin > $this->min) - die ("labelMin > min ($this->labelMin > $this->min)\n"); - if ($this->labelMax < $this->max) - die ("labelMax < max ($this->labelMax < $this->max)\n"); - if (count ($labels) <= $nbMaxValues) - { - $labels = array_unique ($labels); - if ($deb) print_r ($labels); - return $labels; + $this->axisX->numerical($numericalX); + $this->axisY1->numerical($numericalY1); + $this->axisY2->numerical($numericalY2); + + if ($minValueX !== null && $this->axisX->min() === null) { + $this->axisX->min($minValueX); } - } - if ($deb) echo "LOOP == ".count ($labels)." > $nbMaxValues ==========\n"; - $base = $base + 0.1; - } - } -} - -/** The graph Axis Horizontal class */ -class GraphAxisHorizontal extends GraphAxisGeneral -{ - /** Calculate the position in pixels for a value - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function position ($value) - { - if ($value === null) - return null; - if (! is_numeric ($value) && ! is_string ($value)) - throw new \Exception (dgettext ("domframework", - "Invalid value provided to graph Axis for position")." ". - get_class ($this), 406); - if ($this->numerical === null) - throw new \Exception (dgettext ("domframework", - "No numerical type defined for Axis")." ".get_class ($this), 406); - if ($this->numerical) - { - // Numerical axis, use a standard scale - if ($value < $this->min || $value > $this->max) - return null; - if (($this->max - $this->min) == 0) - $dividor = 1; - else - $dividor = ($this->max - $this->min); - $scale = ($value - $this->min) / $dividor; - return intval ($this->left + $scale * ($this->right - $this->left)); - } - else - { - // Label axis, count them - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->right - $this->left) / count ($this->data); - return intval ($this->left + $width * $pos + $width / 2); - } - } - - /** Calculate the positionMin, used for labeled axies - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function positionMin ($value) - { - if ($this->numerical) - return $posCenter; - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->right - $this->left) / count ($this->data); - return intval ($this->left + $width * $pos); - } - - /** Calculate the positionMax, used for labeled axies - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function positionMax ($value) - { - $posCenter = $this->position ($value); - if ($this->numerical) - return $posCenter; - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->right - $this->left) / count ($this->data); - return intval ($this->left + $width * $pos + $width); - } -} - -/** The X axis management */ -class GraphAxisX extends GraphAxisHorizontal -{ - /** The angle choosed to draw the graph - */ - private $angle; - - /** The padding between the label and the axis - */ - private $padding = 7; - - /** The heigth of the labels + padding (it is the base of the graph) in pixels - */ - private $height; - - /** The number of chars to be displayed in one label - */ - protected $nbcharsLabel = 0; - - /** Look for the height of the X axis based on the angle of the text when it - * will be drawn - * @param resource $gd The resource to modify - */ - public function getHeight ($gd) - { - // Look for the angle of the value. Start Horizontally (angle=0), then - // try 45°, then finish at 90°. As all the values must in the same angle, - // test all the values. If one is bad, change the angle and retry all the - // values - $width = null; - if ($this->numerical) - { - if ($this->max === null) - throw new \Exception (dgettext ("domframework", - "The max is not defined for graphAxisHorizontal"), 406); - $powMax = intval (log10 ($this->max)); - $tenPercent = round ($this->max / pow (10, $powMax), 1) + 0.1; - $labelMax = $tenPercent * pow (10, $powMax); - $this->nbcharsLabel = strlen ($labelMax); - $bbox = imagettfbbox ($this->fontsize, $this->angle, $this->fontfile, - $labelMax); - $height = abs ($bbox[4] - $bbox[0]); - $this->height = $height + 2 * $this->padding; - return $this->height; - } - else - { - if ($this->data === null) - return 0; - foreach (array (0, 45, 90) as $this->angle) - { - $bboxMaxHeight = 0; - foreach ($this->data as $key=>$value) - { - if ($width === null) - $width = $this->positionMax ($value) - $this->positionMin ($value); - // Look for the bounding box around the text. The bounding is not - // write on the image and return the coordinates for the text box - $bbox = imagettfbbox ($this->fontsize, $this->angle, $this->fontfile, - $value); - if (abs ($bbox[4] - $bbox[0]) > $width) - continue 2; - $bboxMaxHeight = max ($bboxMaxHeight, abs ($bbox[5] - $bbox[1])); + if ($maxValueX !== null && $this->axisX->max() === null) { + $this->axisX->max($maxValueX); } - // All the values are OK : we have found the angle : break the angle - // loop - break; - } - } - $this->height = $bboxMaxHeight + 2 * $this->padding; - return $bboxMaxHeight + 2 * $this->padding; - } - - /** Draw the axis - * @param resource $gd The resource to modify - */ - public function draw ($gd) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - if ($this->numerical) - { - if ($this->angle === null) - $this->getHeight ($gd); - if ($this->data === null) - return; - foreach ($this->data as $key=>$value) - { - $position = $this->position ($value); - - // Draw the labels - $bbox = imagettfbbox ($this->fontsize, $this->angle, $this->fontfile, - $value); - $width = abs ($bbox[4] - $bbox[0]); - $x = $position - $width / 2; - $y = $this->bottom - $this->padding; - // The font color is forced to black - imagettftext ($gd, $this->fontsize, $this->angle, $x, $y, - Color::allocateFromText ($gd, "black"), - $this->fontfile, $value); - - // Draw the scale - imageline ($gd, - $position, $this->bottom - $this->height + 1, - $position, - $this->bottom - $this->height + 1 + $this->padding, - $axisColor); - - // Draw the grid - $this->drawGrid ($gd, $this->bottom - $this->height, $position); - } - - // Draw the axis - $y = $this->bottom - $this->height + 1; - imageline ($gd, $this->left, $y, $this->right, $y, $axisColor); - } - else - { - if ($this->angle === null) - $this->getHeight ($gd); - if ($this->data === null) - return; - foreach ($this->data as $key=>$value) - { - $position = $this->position ($value); - - // Draw the labels - $bbox = imagettfbbox ($this->fontsize, $this->angle, $this->fontfile, - $value); - $width = abs ($bbox[4] - $bbox[0]); - $x = $position - $width / 2; - $y = $this->bottom - $this->padding; - // The font color is forced to black - imagettftext ($gd, $this->fontsize, $this->angle, $x, $y, - Color::allocateFromText ($gd, "black"), - $this->fontfile, $value); - - // Draw the separators - $y = $this->bottom - $this->height + 1; - $xmin = $this->positionMin ($value); - $xmax = $this->positionMax ($value); - imageline ($gd, $xmin, $y, $xmin, $y + $this->padding, $axisColor); - imageline ($gd, $xmax, $y, $xmax, $y + $this->padding, $axisColor); - - // Draw the grid - $this->drawGrid ($gd, $this->bottom - $this->height, $position); - } - - // Draw the axis - $y = $this->bottom - $this->height + 1; - imageline ($gd, $this->left, $y, $this->right, $y, $axisColor); - } - } - - /** Draw the grid - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - * @param integer|float $position The position to draw - */ - protected function drawGrid ($gd, $width, $position) - { - if ($this->gridColor === null || $this->gridColor === "transparent") - return; - $gridColor = Color::allocateFromText ($gd, $this->gridColor); - if ($position === null) - return; - $y = $this->bottom - $this->height; - imageline ($gd, $position, $y, $position, $this->top, $gridColor); - } -} - -/** Manage the vertical axis */ -class GraphAxisVertical extends GraphAxisGeneral -{ - /** The angle choosed to draw the graph - */ - private $angle; - - /** The padding between the label and the axis - */ - protected $padding = 7; - - /** The width of the labels + padding (it is the base of the graph) in pixels - */ - protected $width; - - /** The number of chars to be displayed in one label - */ - protected $nbcharsLabel = 0; - - /** Look for the width of the Y axis - * @param resource $gd The resource to modify - */ - public function getWidth ($gd) - { - if ($this->numerical) - { - if ($this->max === null) - throw new \Exception (dgettext ("domframework", - "The max is not defined for graphAxisVertical"), 406); - // Look at the minimum distance between two labeled values - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, "NOT"); - $height = abs ($bbox[5] - $bbox[1]) + $this->padding; - for ($nbMaxValues = 10 ; $nbMaxValues > 2 ; $nbMaxValues--) - { - if ($nbMaxValues * $height < abs ($this->top - $this->bottom)) - break; - } - $labels = $this->labels ($nbMaxValues); - $labelBiggest = ""; - $this->nbcharsLabel = 0; - foreach ($labels as $label) - { - if (strlen ($label) > $this->nbcharsLabel) - { - $this->nbcharsLabel = strlen ($label); - $labelBiggest = $label; + if ($minValueY1 !== null && $this->axisY1->min() === null) { + $this->axisY1->min($minValueY1); + } + if ($maxValueY1 !== null && $this->axisY1->max() === null) { + $this->axisY1->max($maxValueY1); + } + if ($minValueY2 !== null && $this->axisY2->min() === null) { + $this->axisY2->min($minValueY2); + } + if ($maxValueY2 !== null && $this->axisY2->max() === null) { + $this->axisY2->max($maxValueY2); } - } - $bbox = imagettfbbox ($this->fontsize, $this->angle, $this->fontfile, - $labelBiggest); - $width = abs ($bbox[4] - $bbox[0]); - $this->width = $width + 2 * $this->padding; - return $this->width; - } - else - { - if ($this->data === null) - return $this->padding; - die ("TODO : getWidth in labeled line ".__LINE__."\n"); - } - } - /** Calculate the position in pixels for a value - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function position ($value) - { - if ($value === null) - return null; - if (! is_numeric ($value) && ! is_string ($value)) - throw new \Exception (dgettext ("domframework", - "Invalid value provided to graph Axis for position")." ". - get_class ($this), 406); - if ($this->numerical === null) - throw new \Exception (dgettext ("domframework", - "No numerical type defined for Axis")." ".get_class ($this), 406); - if ($this->numerical) - { - // Numerical axis, use a standard scale - if ($value > $this->labelMax || $value < $this->labelMin) - return null; - $scale = ($value - $this->labelMin) / ($this->labelMax - $this->labelMin); - $pos = intval ($this->bottom + $scale * ($this->top - $this->bottom)); - return $pos; - } - else - { - // Label axis, count them - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->top - $this->bottom) / count ($this->data); - $pos = intval ($this->bottom + $width * $pos + $width / 2); - return $pos; - } - } + // Manage the styles for each serie + foreach ($this->series->getList() as $number => $serie) { + if ($this->series->serie($serie)->style() === null) { + $this->series->serie($serie)->style($this->style); + } + if ($this->series->serie($serie)->style()->palette() === null) { + $this->series->serie($serie)->style()->palette( + $this->style->palette() + ); + } + $this->series->serie($serie)->style()->number($number); + } - /** Calculate the positionMin, used for labeled axies - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function positionMin ($value) - { - if ($this->numerical) - return $posCenter; - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->top - $this->bottom) / count ($this->data); - return intval ($this->bottom + $width * $pos); - } + // Create the image + $gd = imagecreatetruecolor($this->width, $this->height); + // Put the background color + imagefilledrectangle( + $gd, + 0, + 0, + $this->width - 1, + $this->height - 1, + Color::allocateFromText($gd, $this->bgcolor) + ); + // The coordinates of the free space. Will be modified each time something + // is drawing on the graph + // xtop, ytop, xbottom, ybottom + $free = array(0, 0, imagesx($gd), imagesy($gd)); + // Add the title on top + $free = $this->title->draw($gd, $free); + // Add the legend on right + $free = $this->legend->draw($gd, $free, $this->series); - /** Calculate the positionMax, used for labeled axies - * If the value is out of range, return null to not draw the point - * @param string|float|integer $value The value to position - */ - public function positionMax ($value) - { - $posCenter = $this->position ($value); - if ($this->numerical) - return $posCenter; - if (! is_array ($this->data)) - throw new \Exception (dgettext ("domframework", - "No data defined for Axis")." ".get_class ($this), 406); - $pos = array_search ($value, $this->data); - if ($pos === false) - return null; - $width = ($this->top - $this->bottom) / count ($this->data); - return intval ($this->bottom + $width * $pos + $width); - } + // If there is no title, add an offset of 10px to display correctely the + // first label of the Y axis + if ($free[1] === 0) { + $free[1] = 10; + } - /** Draw the axis labels and lines - * @param resource $gd The resource to modify - */ - public function draw ($gd) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - if ($this->numerical) - { - // Look at the minimum distance between two labeled values - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, "NOT"); - $height = abs ($bbox[5] - $bbox[1]) + $this->padding; - for ($nbMaxValues = 10 ; $nbMaxValues > 2 ; $nbMaxValues--) - { - if ($nbMaxValues * $height < abs ($this->top - $this->bottom)) - break; - } + // Add the axis + // Need two passes as the X axis can modify the Y axes + $this->axisX->top($free[1]); + $this->axisX->bottom($free[3] - 1); + $this->axisY1->top($free[1]); + $this->axisY2->top($free[1]); + $this->axisY1->bottom($free[3] - 1); + $this->axisY2->bottom($free[3] - 1); + $Xleft = $this->axisY1->getWidth($gd); + $Xright = $free[2] - $this->axisY2->getWidth($gd); + $this->axisX->left($Xleft); + $this->axisX->right($Xright); + $Ybottom = $this->height - $this->axisX->getHeight($gd); + $this->axisY1->right($Xright); + $this->axisY1->bottom($Ybottom); + //$this->axisY1->left (???); + $this->axisY2->right($Xleft); + $this->axisY2->bottom($Ybottom); + $this->axisY2->left($Xright); - $width = $this->getWidth ($gd); - $labels = $this->labels ($nbMaxValues); - if (count ($labels) > $nbMaxValues) - die ("Too much labels to display (". - count ($labels)." > $nbMaxValues)\n"); - foreach ($labels as $label) - { - $this->drawOne ($gd, $width, $label); - $this->drawGrid ($gd, $width, $label); - } - $this->drawAxis ($gd, $width); + // Draw the axis + $this->axisX->draw($gd); + $this->axisY1->draw($gd); + $this->axisY2->draw($gd); + + // Add the graph part for each serie + $lastFree = $free; + foreach ($this->series->getList() as $number => $serie) { + // As the series are superposed, do not update the $free each time + if (! $this->series->serie($serie)->axisYsecondary()) { + $lastFree = $this->series->serie($serie)->draw( + $gd, + $free, + $this->axisX, + $this->axisY1 + ); + } else { + $lastFree = $this->series->serie($serie)->draw( + $gd, + $free, + $this->axisX, + $this->axisY2 + ); + } + } + $free = $lastFree; + imagepng($gd); + imagedestroy($gd); } - else + + /** Draw the graph to the screen with the previous defined parameters + */ + public function drawImage() { - // Labeled - // If there is no data, there is nothing to draw : return - if ($this->data === null) - return; - die ("graphAxisVertical::draw labeled TBD line ".__LINE__."\n"); + header('Content-Type: image/png'); + $this->drawReal(); + } + + /** Return the image coded in base64 + * @return string The base64 string + */ + public function drawBase64() + { + ob_start(); + $this->drawReal(); + return base64_encode(ob_get_clean()); } - } -} - -/** The Y1 axis management */ -class GraphAxisY1 extends GraphAxisVertical -{ - /** Draw one value on the axis - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - * @param integer|float $val The value to draw - */ - protected function drawOne ($gd, $width, $val) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - if ($this->numerical) - { - // Do not allow the label to be longer than $this->max - if (strlen ($val) > $this->nbcharsLabel) - $itmp = rtrim (substr ($val, 0, $this->nbcharsLabel), "."); - else - $itmp = $val; - // Write the labels align to right - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, $itmp); - $labelwidth = abs ($bbox[4] - $bbox[0]) + $this->padding; - $labelheight = abs ($bbox[5] - $bbox[1]); - $y = $this->position ($val); - if ($y === null) - return; - // The color is forced to black - imagettftext ($gd, $this->fontsize, 0, - $width - $labelwidth, - $y + $labelheight / 2, - Color::allocateFromText ($gd, "black"), - $this->fontfile, $itmp); - - // Display the separators - imageline ($gd, $width - $this->padding, $y, - $width, $y, $axisColor); - } - else - { -die ("graphAxisY1:: drawOne NOT numerical line ".__LINE__."\n"); - } - } - - /** Draw the axis - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - */ - protected function drawAxis ($gd, $width) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - imageline ($gd, $width, $this->bottom, $width, $this->top, $axisColor); - } - - /** Draw the grid - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - * @param integer|float $val The value to draw - */ - protected function drawGrid ($gd, $width, $val) - { - if ($this->gridColor === null || $this->gridColor === "transparent") - return; - $gridColor = Color::allocateFromText ($gd, $this->gridColor); - if ($this->numerical) - { - $y = $this->position ($val); - if ($y === null) - return; - imageline ($gd, $width, $y, $this->right, $y, $gridColor); - } - else - { -die ("graphAxisY1:: drawGrid NOT numerical line ".__LINE__."\n"); - } - } -} - -/** The Y2 axis management */ -class GraphAxisY2 extends GraphAxisVertical -{ - /** Draw one value on the axis - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - * @param integer|float $val The value to draw - */ - protected function drawOne ($gd, $width, $val) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - if ($this->numerical) - { - // Do not allow the label to be longer than $this->max - if (strlen ($val) > $this->nbcharsLabel) - $itmp = rtrim (substr ($val, 0, $this->nbcharsLabel), "."); - else - $itmp = $val; - // Write the labels align to left - $bbox = imagettfbbox ($this->fontsize, 0, $this->fontfile, $itmp); - $labelwidth = abs ($bbox[4] - $bbox[0]) + $this->padding; - $labelheight = abs ($bbox[5] - $bbox[1]); - $y = $this->position ($val); - if ($y === null) - return; - // The color is forced to black - imagettftext ($gd, $this->fontsize, 0, - $this->left + $this->padding + 3, - $y + $labelheight / 2, - Color::allocateFromText ($gd, "black"), - $this->fontfile, $itmp); - - // Display the separators - imageline ($gd, $this->left, $y, - $this->left + $this->padding, $y, $axisColor); - } - else - { -die ("graphAxisY2:: drawOne NOT numerical line ".__LINE__."\n"); - } - } - - /** Draw the axis - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - */ - protected function drawAxis ($gd, $width) - { - $axisColor = Color::allocateFromText ($gd, $this->axisColor); - imageline ($gd, $this->left, $this->bottom, - $this->left, $this->top, $axisColor); - } - - /** Draw the grid - * @param resource $gd The resource to modify - * @param integer $width The width of the labels on the axis - * @param integer|float $val The value to draw - */ - protected function drawGrid ($gd, $width, $val) - { - // The grid can't be graphed for Y2 axis : only the Y1 axis is allowed - return; - } -} - -/** The graphStyleLine : draw a graph with lines */ -class GraphStyleLinePoints -{ - /** The line color. To hide the lines, choose "transparent" - */ - protected $lineColor; - - /** The point color background. To hide the points, choose "transparent" - */ - protected $pointBgcolor; - - /** The point color border - */ - protected $pointColor; - - /** The point shape (square, circle, triangle, lozenge) - */ - protected $pointShape; - - /** The point width in pixel - */ - protected $pointWidth; - - /** The number of the colors/shapes to use - */ - protected $number; - - /** The allowed shapes */ - protected $allowedShapes = array ("square", "circle", "triangle", "lozenge"); - - /** The palette to use */ - protected $palette; - - /** Return the name of the style */ - public function name () - { - return "lineAndPoints"; - } - - /** Set the line color if the parameter is provided. - * Get the line color if the parameter is not provided - * @param string|null $lineColor The line color - */ - public function lineColor ($lineColor = null) - { - if ($lineColor === null) - return $this->lineColor; - if (! is_string ($lineColor) || - ($lineColor !== "transparent" && - ! in_array ($lineColor, Color::colorList ()))) - throw new \Exception (dgettext ("domframework", - "Invalid lineColor provided to line style"), 406); - $this->lineColor = $lineColor; - return $this; - } - - /** Set the palette to use if the parameter is provided - * Get the palette if the parameter is not provided - * @param string|null $palette The palette to use - */ - public function palette ($palette = null) - { - if ($palette === null) - return $this->palette; - if (! is_string ($palette)) - throw new \Exception (dgettext ("domframework", - "Invalid palette provided to line style"), 406); - $this->palette = $palette; - return $this; - } - - /** Set the point background color if the parameter is provided. - * Get the point background color if the parameter is not provided - * @param string|null $pointBgcolor The point background color - */ - public function pointBgcolor ($pointBgcolor = null) - { - if ($pointBgcolor === null) - return $this->pointBgcolor; - if (! is_string ($pointBgcolor) || - ($pointBgcolor !== "transparent" && - ! in_array ($pointBgcolor, Color::colorList ()))) - throw new \Exception (dgettext ("domframework", - "Invalid pointBgcolor provided to line style"), 406); - $this->pointBgcolor = $pointBgcolor; - return $this; - } - - /** Set the point border color if the parameter is provided. - * Get the point border color if the parameter is not provided - * @param string|null $pointColor The point border color - */ - public function pointColor ($pointColor = null) - { - if ($pointColor === null) - return $this->pointColor; - if (! is_string ($pointColor) || - ($pointColor !== "transparent" && - ! in_array ($pointColor, Color::colorList ()))) - throw new \Exception (dgettext ("domframework", - "Invalid pointColor provided to line style"), 406); - $this->pointColor = $pointColor; - return $this; - } - - /** Set the point shape if the parameter is provided. - * Get the point shape if the parameter is not provided - * @param string|null $pointShape The point shape - */ - public function pointShape ($pointShape = null) - { - if ($pointShape === null) - return $this->pointShape; - if (! is_string ($pointShape) || - ! in_array ($pointShape, $this->allowedShapes)) - throw new \Exception (dgettext ("domframework", - "Invalid pointShape provided to line style"), 406); - $this->pointShape = $pointShape; - return $this; - } - - /** Set the point width if the parameter is provided. - * Get the point width if the parameter is not provided - * @param string|null $pointWidth The point width - */ - public function pointWidth ($pointWidth = null) - { - if ($pointWidth === null) - return $this->pointWidth; - if (! is_integer ($pointWidth) || $pointWidth < 3 || $pointWidth > 20) - throw new \Exception (dgettext ("domframework", - "Invalid pointWidth provided to line style"), 406); - $this->pointWidth = $pointWidth; - return $this; - } - - /** Select the colors, shapes by the serie number. - * Do not change any property if the property is already defined - * If the parameter is not provided, return the value - * @param integer|null $number The serie number - */ - public function number ($number = null) - { - if ($number === null) - return $this->number; - if (! is_int ($number) || $number < 0) - throw new \Exception (dgettext ("domframework", - "Invalid number provided to line style number"), 406); - $this->number = $number; - if ($this->pointShape === null) - $this->pointShape = $this->allowedShapes[ - ($number%count($this->allowedShapes))]; - $palette = graphPalette::getPalette ($this->palette); - if ($this->pointBgcolor === null) - $this->pointBgcolor = $palette[($number%count ($palette))]["bgcolor"]; - if ($this->pointColor === null) - $this->pointColor = $palette[($number%count ($palette))]["color"]; - if ($this->lineColor === null) - $this->lineColor = $palette[($number%count ($palette))]["color"]; - } - - /** Draw in the $gd resource, in the $free array, the data with the parameter - * of the style - * @param resource $gd The resource to modify - * @param array $free The free space coordinates on the graphic - * @param array $data The data to graph - * @param object $axisX The X axis used to graph - * @param object $axisY The Y axis used to graph - */ - public function draw ($gd, $free, $data, $axisX, $axisY) - { - if ($this->lineColor !== "transparent") - $lineColor = Color::allocateFromText ($gd, $this->lineColor); - $lastX = null; - $lastY = null; - foreach ($data as $key=>$value) - { - $posX = $axisX->position ($key); - $posY = $axisY->position ($value); - if ($posX === null || $posY === null) - { - // NULL position : skip the point - $lastX = null; - $lastY = null; - continue; - } - - // Draw the lines between points (except if the last point was null, or - // if the line color is "transparent") - if ($lastX !== null && $lastY !== null && - $this->lineColor !== "transparent") - { - imageline ($gd, $lastX, $lastY, $posX, $posY, $lineColor); - // Redraw the old point which was scratch by the new created line - $this->drawPoint ($gd, $lastX, $lastY); - } - if ($lastX === null) - $lastX = $posX; - if ($lastY === null) - $lastY = $posY; - - // Draw the point. Will overwrite the lines - if ($this->pointWidth === null) - $this->pointWidth = 6; - $this->drawPoint ($gd, $posX, $posY); - $lastX = $posX; - $lastY = $posY; - } - } - - /** Draw a point defined in the property of the class - * @param resource $gd The resource to modify - * @param integer $posX The X position to draw the point - * @param integer $posY The Y position to draw the point - */ - private function drawPoint ($gd, $posX, $posY) - { - if ($this->pointColor !== "transparent") - $pointColor = Color::allocateFromText ($gd, $this->pointColor); - if ($this->pointBgcolor !== "transparent") - $pointBgcolor = Color::allocateFromText ($gd, $this->pointBgcolor); - $half = intval ($this->pointWidth / 2); - switch ($this->pointShape) - { - case "circle": - if ($this->pointBgcolor !== "transparent") - imagefilledellipse ($gd, $posX, $posY, $this->pointWidth, - $this->pointWidth, $pointBgcolor + 2); - if ($this->pointColor !== "transparent") - imageellipse ($gd, $posX, $posY, $this->pointWidth + 2, - $this->pointWidth + 2, $pointColor); - break; - case "lozenge": - if ($this->pointBgcolor !== "transparent") - imagefilledpolygon ($gd, array ($posX - $half - 2, $posY, - $posX, $posY - $half - 2, - $posX + $half + 2, $posY, - $posX, $posY + $half + 2), - 4, $pointBgcolor); - if ($this->pointColor !== "transparent") - imagepolygon ($gd, array ($posX - $half - 2, $posY, - $posX, $posY - $half - 2, - $posX + $half + 2, $posY, - $posX, $posY + $half + 2), - 4, $pointColor); - break; - case "square": - if ($this->pointBgcolor !== "transparent") - imagefilledrectangle ($gd, $posX - $half - 1, $posY - $half - 1, - $posX + $half + 1, $posY + $half + 1, - $pointBgcolor); - if ($this->pointColor !== "transparent") - imagerectangle ($gd, $posX - $half - 1, $posY - $half - 1, - $posX + $half + 1, $posY + $half + 1, - $pointColor); - break; - case "triangle": - if ($this->pointBgcolor !== "transparent") - imagefilledpolygon ($gd, array ($posX - $half -2, $posY + $half + 2, - $posX, $posY - $half -2, - $posX + $half + 2, $posY + $half + 2), - 3, $pointBgcolor); - if ($this->pointColor !== "transparent") - imagepolygon ($gd, array ($posX - $half - 2, $posY + $half + 2, - $posX, $posY - $half - 2, - $posX + $half + 2, $posY + $half + 2), - 3, $pointColor); - break; - default: - throw new \Exception (dgettext ("domframework", - "Unknown pointShape for serie"), 406); - } - } - - /** Draw a sample of the style for the legend - * @param resource $gd The resource to modify - * @param integer $x The central position of the sample in x - * @param integer $y The central position of the sample in y - */ - public function sample ($gd, $x, $y) - { - if ($this->lineColor !== "transparent") - { - $lineColor = Color::allocateFromText ($gd, $this->lineColor); - imageline ($gd, $x-10, $y, $x+10, $y, $lineColor); - } - if ($this->pointWidth === null) - $this->pointWidth = 6; - $this->drawPoint ($gd, $x, $y); - } -} - -/** The graphStylePoints : draw a graph with points */ -class GraphStylePoints extends GraphStyleLinePoints -{ - /** The line color : transparent - */ - protected $lineColor = "transparent"; - - /** Return the name of the style */ - public function name () - { - return "points"; - } -} - -/** The graphStyleLine : draw a graph with line */ -class GraphStyleLine extends GraphStyleLinePoints -{ - /** The point color background. To hide the points, choose "transparent" - */ - protected $pointBgcolor = "transparent"; - - /** The point color border - */ - protected $pointColor = "transparent"; - - /** Return the name of the style */ - public function name () - { - return "line"; - } -} - -/** The graphPalette class */ -class GraphPalette -{ - /** Get the complete palette - * @param string $name The palette name to get - */ - public static function getPalette ($name) - { - $palette = array ( - "basic" => array ( - array ("bgcolor"=>"indianred", "color"=>"firebrick"), - array ("bgcolor"=>"lightblue", "color"=>"blue"), - array ("bgcolor"=>"peru", "color"=>"maroon"), - array ("bgcolor"=>"mediumaquamarine", "color"=>"teal"), - array ("bgcolor"=>"orange", "color"=>"goldenrod"), - array ("bgcolor"=>"limegreen", "color"=>"green"), - array ("bgcolor"=>"darkgrey", "color"=>"grey"), - array ("bgcolor"=>"darkyellow1", "color"=>"darkyellow2"), - array ("bgcolor"=>"grey", "color"=>"black"), - ), - ); - if (! is_string ($name) || ! array_key_exists ($name, $palette)) - throw new \Exception (dgettext ("domframework", - "Unknown palette name provided"), 406); - return $palette[$name]; - } } diff --git a/src/Http.php b/src/Http.php index 6f4bf33..21a49ca 100644 --- a/src/Http.php +++ b/src/Http.php @@ -1,4 +1,5 @@ @@ -12,127 +13,204 @@ namespace Domframework; */ 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 - * Defined in https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - * @param string $uservar The parameter provided by the user - * @param array|null $available The list of available choices in the soft - * @param string|null $default The choice if nothing match - * @return string The prefered choice - */ - function bestChoice ($uservar, $available=array(), $default=FALSE) - { - $uservar = str_replace (" ", "", $uservar); - $userchoices = explode (",", $uservar); - if (!isset ($userchoices[0])) + /** 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 + * Defined in https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + * @param string $uservar The parameter provided by the user + * @param array|null $available The list of available choices in the soft + * @param string|null $default The choice if nothing match + * @return string The prefered choice + */ + public function bestChoice($uservar, $available = array(), $default = false) { - if ($default === FALSE) - throw new \Exception ("No user choice provided to bestChoice", 500); - return $default; - } + $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; + } - // If the priority is not set, must be used in priority - // If the priority is set, use it if it is valid - $choicesPrio = array (); - foreach ($userchoices as $choice) - { - @list ($choice, $prio) = explode (";q=", $choice); - if (trim ($choice) === "") - continue; - if ($prio === null) - $prio = 1.0; - else - { - $nums = explode (".", $prio); - if (count ($nums) > 2) - $prio = 0.0; - elseif ($nums[0] !== "0") - $prio = 0.0; - elseif ($nums[0] < 0 || $nums[0] > 9) - $prio = 0.0; - } - $choicesPrio[$choice] = $prio; - } - // Sort by priority - arsort ($choicesPrio, SORT_NATURAL); + // If the priority is not set, must be used in priority + // If the priority is set, use it if it is valid + $choicesPrio = array(); + foreach ($userchoices as $choice) { + @list($choice, $prio) = explode(";q=", $choice); + if (trim($choice) === "") { + continue; + } + if ($prio === null) { + $prio = 1.0; + } else { + $nums = explode(".", $prio); + if (count($nums) > 2) { + $prio = 0.0; + } elseif ($nums[0] !== "0") { + $prio = 0.0; + } elseif ($nums[0] < 0 || $nums[0] > 9) { + $prio = 0.0; + } + } + $choicesPrio[$choice] = $prio; + } + // Sort by priority + arsort($choicesPrio, SORT_NATURAL); - if (count ($available) === 0) - return $userchoices[0]; + if (count($available) === 0) { + return $userchoices[0]; + } - // Look at the best existing solution - foreach ($choicesPrio as $choice => $priority) - { - if ($choice === "*/*") + // Look at the best existing solution + foreach ($choicesPrio as $choice => $priority) { + if ($choice === "*/*") { + return $default; + } + 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; + } + } + } + + // No best solution found. Use the default available solution return $default; - 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; - } } - // No best solution found. Use the default available solution - return $default; - } - - /** Return the associated text for a HTTP code - * @param integer $code The HTTP code to translate in text - */ - function codetext ($code) - { - switch ($code) + /** Return the associated text for a HTTP code + * @param integer $code The HTTP code to translate in text + */ + public function codetext($code) { - case 100: $text = 'Continue'; break; - case 101: $text = 'Switching Protocols'; break; - case 200: $text = 'OK'; break; - case 201: $text = 'Created'; break; - case 202: $text = 'Accepted'; break; - case 203: $text = 'Non-Authoritative Information'; break; - case 204: $text = 'No Content'; break; - case 205: $text = 'Reset Content'; break; - case 206: $text = 'Partial Content'; break; - case 300: $text = 'Multiple Choices'; break; - case 301: $text = 'Moved Permanently'; break; - case 302: $text = 'Moved Temporarily'; break; - case 303: $text = 'See Other'; break; - case 304: $text = 'Not Modified'; break; - case 305: $text = 'Use Proxy'; break; - case 400: $text = 'Bad Request'; break; - case 401: $text = 'Unauthorized'; break; - case 402: $text = 'Payment Required'; break; - case 403: $text = 'Forbidden'; break; - case 404: $text = 'Not Found'; break; - case 405: $text = 'Method Not Allowed'; break; - case 406: $text = 'Not Acceptable'; break; - case 407: $text = 'Proxy Authentication Required'; break; - case 408: $text = 'Request Time-out'; break; - case 409: $text = 'Conflict'; break; - case 410: $text = 'Gone'; break; - case 411: $text = 'Length Required'; break; - case 412: $text = 'Precondition Failed'; break; - case 413: $text = 'Request Entity Too Large'; break; - case 414: $text = 'Request-URI Too Large'; break; - case 415: $text = 'Unsupported Media Type'; break; - case 416: $text = 'Range Not Satisfiable'; break; - case 500: $text = 'Internal Server Error'; break; - case 501: $text = 'Not Implemented'; break; - case 502: $text = 'Bad Gateway'; break; - case 503: $text = 'Service Unavailable'; break; - case 504: $text = 'Gateway Time-out'; break; - case 505: $text = 'HTTP Version not supported'; break; - default: - exit('Unknown http status code "'.htmlentities ($code).'"'); + switch ($code) { + case 100: + $text = 'Continue'; + break; + case 101: + $text = 'Switching Protocols'; + break; + case 200: + $text = 'OK'; + break; + case 201: + $text = 'Created'; + break; + case 202: + $text = 'Accepted'; + break; + case 203: + $text = 'Non-Authoritative Information'; + break; + case 204: + $text = 'No Content'; + break; + case 205: + $text = 'Reset Content'; + break; + case 206: + $text = 'Partial Content'; + break; + case 300: + $text = 'Multiple Choices'; + break; + case 301: + $text = 'Moved Permanently'; + break; + case 302: + $text = 'Moved Temporarily'; + break; + case 303: + $text = 'See Other'; + break; + case 304: + $text = 'Not Modified'; + break; + case 305: + $text = 'Use Proxy'; + break; + case 400: + $text = 'Bad Request'; + break; + case 401: + $text = 'Unauthorized'; + break; + case 402: + $text = 'Payment Required'; + break; + case 403: + $text = 'Forbidden'; + break; + case 404: + $text = 'Not Found'; + break; + case 405: + $text = 'Method Not Allowed'; + break; + case 406: + $text = 'Not Acceptable'; + break; + case 407: + $text = 'Proxy Authentication Required'; + break; + case 408: + $text = 'Request Time-out'; + break; + case 409: + $text = 'Conflict'; + break; + case 410: + $text = 'Gone'; + break; + case 411: + $text = 'Length Required'; + break; + case 412: + $text = 'Precondition Failed'; + break; + case 413: + $text = 'Request Entity Too Large'; + break; + case 414: + $text = 'Request-URI Too Large'; + break; + case 415: + $text = 'Unsupported Media Type'; + break; + case 416: + $text = 'Range Not Satisfiable'; + break; + case 500: + $text = 'Internal Server Error'; + break; + case 501: + $text = 'Not Implemented'; + break; + case 502: + $text = 'Bad Gateway'; + break; + case 503: + $text = 'Service Unavailable'; + break; + case 504: + $text = 'Gateway Time-out'; + break; + case 505: + $text = 'HTTP Version not supported'; + break; + default: + exit('Unknown http status code "' . htmlentities($code) . '"'); + } + return $text; } - return $text; - } } diff --git a/src/Httpclient.php b/src/Httpclient.php index 6a76cf1..d2ca070 100644 --- a/src/Httpclient.php +++ b/src/Httpclient.php @@ -1,4 +1,5 @@ @@ -13,1016 +14,1071 @@ namespace Domframework; */ class Httpclient { - ////////////////////////// - //// PROPERTIES //// - ////////////////////////// - /** The debug depth. 0: Nothing is displayed, 1: Only URL are displayed, - * 2: headers only, 3: all the content - */ - private $debug = null; + ////////////////////////// + //// PROPERTIES //// + ////////////////////////// + /** The debug depth. 0: Nothing is displayed, 1: Only URL are displayed, + * 2: headers only, 3: all the content + */ + private $debug = null; - /** The URL to use - */ - private $url = ""; + /** The URL to use + */ + private $url = ""; - /** The cookies - */ - private $cookies = array (); + /** The cookies + */ + private $cookies = array(); - /** Store the session cookies when analyzing the answer of the server - */ - private $cookiesSession = true; + /** Store the session cookies when analyzing the answer of the server + */ + private $cookiesSession = true; - /** The headersReceived - */ - private $headersReceived = array (); + /** The headersReceived + */ + private $headersReceived = array(); - /** The headersSent to the server - */ - private $headersSent = array (); + /** The headersSent to the server + */ + private $headersSent = array(); - /** The Method used to communicate : GET, POST, HEAD, PUT, DELETE - */ - private $method = "GET"; + /** The Method used to communicate : GET, POST, HEAD, PUT, DELETE + */ + private $method = "GET"; - /** The TCP port used for connection - */ - private $port = null; + /** The TCP port used for connection + */ + private $port = null; - /** The TCPClient object - */ - private $tcpclient = null; + /** The TCPClient object + */ + private $tcpclient = null; - /** The SSL Options parameters (if set) - */ - private $ssloptions = array (); + /** The SSL Options parameters (if set) + */ + private $ssloptions = array(); - /** Authentication value - */ - private $authentication = ""; + /** Authentication value + */ + private $authentication = ""; - /** The maximum maxsize allowed - */ - private $maxsize; + /** The maximum maxsize allowed + */ + private $maxsize; - /** The returned HTTP code from the server - */ - private $httpCode = null; + /** The returned HTTP code from the server + */ + private $httpCode = null; - /** The body size staying to read - */ - private $bodySize = null; + /** The body size staying to read + */ + private $bodySize = null; - /** The content method to get the content : chunked or Content-Length - */ - private $contentMethod = false; + /** The content method to get the content : chunked or Content-Length + */ + private $contentMethod = false; - /** Follow X redirects before abort - */ - private $redirectMaxCount = 10; + /** Follow X redirects before abort + */ + private $redirectMaxCount = 10; - /** The actual number of redirect - */ - private $redirectCount = 0; + /** The actual number of redirect + */ + private $redirectCount = 0; - /** The form data to send - * Will be of type array ("field" => "value") - * If value is like "@/tmp/file", use the /tmp/file as content - */ - private $formData = array (); + /** The form data to send + * Will be of type array ("field" => "value") + * If value is like "@/tmp/file", use the /tmp/file as content + */ + private $formData = array(); - /** The raw data to send - */ - private $rawData = ""; + /** The raw data to send + */ + private $rawData = ""; - /** The timeout in second before expiring the connection - */ - private $timeout = 30; + /** The timeout in second before expiring the connection + */ + private $timeout = 30; - /** Store the user agent. If it is empty, it will not be sent to the server - */ - private $useragent = "HTTPClient"; + /** Store the user agent. If it is empty, it will not be sent to the server + */ + private $useragent = "HTTPClient"; - /** The last valid page known. Used as referer - */ - private $referer = ""; + /** The last valid page known. Used as referer + */ + private $referer = ""; - /** The accept type of data wanted by the client - */ - private $accept = "text/html,application/xhtml+xml,application/xml;q=0.9,". + /** The accept type of data wanted by the client + */ + private $accept = "text/html,application/xhtml+xml,application/xml;q=0.9," . "*/*;q=0.8"; - /** The accept language wanted by the client - */ - private $acceptLanguage = "en-us,en;q=0.5"; + /** The accept language wanted by the client + */ + private $acceptLanguage = "en-us,en;q=0.5"; - /** The accept encoding wanted by the client - */ - private $acceptEncoding = "gzip, deflate"; + /** The accept encoding wanted by the client + */ + private $acceptEncoding = "gzip, deflate"; - /** The constructor - */ - public function __construct () - { - $maxsize = str_replace (array ('G', 'M', 'K'), - array ('000000000', '000000', '000'), - ini_get ('memory_limit')); - $maxsize = intval ($maxsize / 2); - // If no maxsize limit, set to 8G - if ($maxsize === 0) - $maxsize = 8000000000; - $this->maxsize = $maxsize; - $this->headersReset (); - } - - ///////////////////////////////// - //// GETTERS / SETTERS //// - ///////////////////////////////// - /** Set / Get the url - * @param string|null $url Set / Get the url - */ - public function url ($url = null) - { - if ($url === null) - return $this->url; - if (! is_string ($url)) - throw new \Exception ("Invalid url to set : not a string", 406); - $this->url = $url; - return $this; - } - - /** Set / Get the cookies stored - * @param array|null $cookies Set / Get the cookies - */ - public function cookies ($cookies = null) - { - if ($cookies === null) - return $this->cookies; - if (! is_array ($cookies)) - throw new \Exception ("Invalid cookies to set : not an array", 406); - $this->cookies = $cookies; - return $this; - } - - /** Set / Get the method - * @param string|null $method Set / Get the method - */ - public function method ($method = null) - { - if ($method === null) - return $this->method; - if (! is_string ($method)) - throw new \Exception ("Invalid method to set : not an string", 406); - $method = strtoupper ($method); - if (! in_array ($method, array ("GET", "POST", "PUT", "DELETE", "HEAD"))) - throw new \Exception ("Invalid method to set : not in list", 406); - $this->method = $method; - return $this; - } - - /** Get the headersReceived after the page was get - */ - public function headersReceived () - { - return $this->headersReceived; - } - - /** Get the headers sent to the server after the page was get - */ - public function headersSent () - { - return $this->headersSent; - } - - /** Set the headers to initial value - */ - public function headersReset () - { - $this->headersSent = array (); - return $this; - } - - /** Add a new header to be sent to the server - * @param string $header The header to add/update - * @param string $value The value to save - */ - public function headerAdd ($header, $value) - { - $this->headersSent[$header] = $value; - return $this; - } - - /** Get the port used for connection - */ - public function port () - { - return $this->port; - } - - /** Set / Get the maximum maxsize allowed - * @param integer|null $maxsize The maxsize in bytes - */ - public function maxsize ($maxsize = null) - { - if ($maxsize === null) - return $this->maxsize; - $this->maxsize = intval ($maxsize); - return $this; - } - - /** Get the HTTP Return code from connection - */ - public function httpCode () - { - return $this->httpCode; - } - - /** Set / Get the debug mode - * 0: Nothing is displayed, 1: Only URL are displayed, - * 2: headers only send and received, 3: all the content, but without sent - * files, 4: all the content - * @param boolean|null $debug The debug value to set or get - */ - public function debug ($debug = null) - { - if ($debug === null) - return $this->debug; - $this->debug = intval ($debug); - return $this; - } - - /** Set / Get the form Data - * Will be of type array ("field" => "value") - * If value is like "@/tmp/file", use the /tmp/file as content - * @param array|null $formData The data to send to the server - */ - public function formData ($formData = null) - { - if ($formData === null) - return $this->formData; - if (! is_array ($formData)) - throw new \Exception ("Invalid form data provided : not an array", 406); - $this->formData = $formData; - $this->rawData = ""; - return $this; - } - - /** Set / Get the content Data - * The data is in raw format and will not be modified. - * Overwrite the eventually previous form data and rawData - * @param string|null $rawData The data to use - */ - public function rawData ($rawData = null) - { - if ($rawData === null) - return $this->rawData; - if (! is_string ($rawData)) - throw new \Exception ("Invalid raw data provided : not a string", 406); - $this->rawData = $rawData; - $this->formData = array (); - return $this; - } - - /** Get / Set the Store of session cookies when analyzing the answer of the - * server - * @param boolean|null $cookiesSession Allow to store the session cookies - */ - public function cookiesSession ($cookiesSession = null) - { - if ($cookiesSession === null) - return $this->cookiesSession; - $this->cookiesSession = !! $cookiesSession; - return $this; - } - - /** Get / Set the maximum number of redirect to follow before aborting - * @param integer|null $redirectMaxCount The maximum number of redirect - * before exception - */ - public function redirectMaxCount ($redirectMaxCount = null) - { - if ($redirectMaxCount === null) - return $this->redirectMaxCount; - $this->redirectMaxCount = intval ($redirectMaxCount); - return $this; - } - - /** Get / Set the actual number of redirect - * @param integer|null $redirectCount The actual number of redirect - */ - public function redirectCount ($redirectCount = null) - { - if ($redirectCount === null) - return $this->redirectCount; - $this->redirectCount = intval ($redirectCount); - return $this; - } - - /** Get / Set the timeout in second before expiring the connection - * 30s by default - * @param integer|null $timeout The timeout value - */ - public function timeout ($timeout = null) - { - if ($timeout === null) - return $this->timeout; - $this->timeout = intval ($timeout); - return $this; - } - - /** Get / Set the useragent sent to the server. If it is empty, it will not be - * sent - * @param string|null $useragent The user agent to use - */ - public function useragent ($useragent = null) - { - if ($useragent === null) - return $this->useragent; - $this->useragent = $useragent; - return $this; - } - - /** Get/Set the referer page - * @param string|null $referer The new referer that will be used on next - * request - */ - public function referer ($referer = null) - { - if ($referer === null) - return $this->referer; - $this->referer = $referer; - return $this; - } - - /** Get/Set the accept type of page wanted by the client - * @param string|null $accept The accept types with weight - */ - public function accept ($accept = null) - { - if ($accept === null) - return $this->accept; - $this->accept = $accept; - return $this; - } - - /** Get/Set the accept Language wanted by the client - * @param string|null $acceptLanguage The languages with weight - */ - public function acceptLanguage ($acceptLanguage = null) - { - if ($acceptLanguage === null) - return $this->acceptLanguage; - $this->acceptLanguage = $acceptLanguage; - return $this; - } - - /** Get/Set the accept Encoding wanted by the client - * @param string|null $acceptEncoding The encoding requested - */ - public function acceptEncoding ($acceptEncoding = null) - { - if ($acceptEncoding === null) - return $this->acceptEncoding; - $this->acceptEncoding = $acceptEncoding; - return $this; - } - - /** Set the authentication in Basic type - * @param string $login The login to use - * @param string $password The password to use - */ - public function authBasic ($login, $password) - { - $this->authentication = "Basic ". base64_encode ("$login:$password"); - return $this; - } - - /** Get/Set authentication - * To remove authentication, pass "" to $auth arg - * @param string|null $auth The authentication string to send - * @return value or $this - */ - public function authentication ($auth = null) - { - if ($auth === null) - return $this->authentication; - $this->authentication = $auth; - return $this; - } - - /** Get/Set the ssl options - * @param array|null $ssloptions The SSL Options to use - * @return $this - */ - public function ssloptions ($ssloptions = null) - { - if ($ssloptions === null) - return $this->ssloptions; - $this->ssloptions = $ssloptions; - return $this; - } - - /** Get meta data, like the timeout state, the crypto protocol and ciphers... - */ - public function getMeta () - { - return $this->tcpclient->getMeta (); - } - - /** Return the TCP infos of the connection - */ - public function getInfo () - { - return $this->tcpclient->getInfo (); - } - - ////////////////////////////////// - //// THE ACTIVE METHODS //// - ////////////////////////////////// - /** Get the page - * Will fill the headersReceived, cookies and port properties. - * This will fill all the RAM if the page is too big. For big files, use - * $httpclient->url ($url) - * ->connect () ; - * while ($content = $httpclient->read ()) {} - * $httpclient->disconnect (); - * If no maxsize limit is set, limit the download to 8G - * @param string $url The URL to get - * @param array|null $ssloptions The SSL options (stream_context_set_option) - * @return the page body - */ - public function getPage ($url, $ssloptions = null) - { - $this->method ("GET"); - $this->url ($url); - $this->connect ($ssloptions); - return $this->getContent (); - } - - /** Init the connection to URL - * Will fill the headersReceived, cookies and port properties. - * @param array|null $ssloptions The SSL options (stream_context_set_option) - * @return $this - */ - public function connect ($ssloptions = null) - { - $this->log (2, "## URL Start $this->method $this->url"); - if ($ssloptions !== null) - $this->ssloptions = $ssloptions; - $this->headersReceived = array (); - $this->bodySize = null; - $this->httpCode = null; - if ($this->url === "") - throw new \Exception ("No URL set to connect", 406); - // Manage the URL (and the parameters in GET method) - $parseURL = parse_url ($this->url); - if (! key_exists ("scheme", $parseURL)) - throw new \Exception ("Scheme must be set to http or https", 406); - if ($parseURL["scheme"] !== "http" && - $parseURL["scheme"] !== "https") - throw new \Exception ("Scheme must be http or https only", 406); - if (key_exists ("port", $parseURL)) - $this->port = $parseURL["port"]; - elseif (key_exists ("scheme", $parseURL)) + /** The constructor + */ + public function __construct() { - if ($parseURL["scheme"] === "http") - $this->port = 80; - elseif ($parseURL["scheme"] === "https") - $this->port = 443; - } - if (! key_exists ("path", $parseURL)) - $path = "/"; - else - $path = $parseURL["path"]; - if (key_exists ("query", $parseURL)) - $path .= "?".$parseURL["query"]; - - if ($this->method === "GET" && ! empty ($this->formData)) - { - // In GET method, the form data are added to the path - if (! key_exists ("query", $parseURL)) - $path .= "?"; - else - $path .= "&"; - $i = 0; - foreach ($this->formData as $key => $val) - { - if ($i > 0) - $path .= "&"; - $path .= rawurlencode ($key)."="; - if (isset ($val[0]) && $val[0] === "@") - { - $file = substr ($val, 1); - if (! file_exists ($file)) - throw new \Exception ("Data file '$file' doesn't exists", 406); - $val = file_get_contents ($file); + $maxsize = str_replace( + array('G', 'M', 'K'), + array('000000000', '000000', '000'), + ini_get('memory_limit') + ); + $maxsize = intval($maxsize / 2); + // If no maxsize limit, set to 8G + if ($maxsize === 0) { + $maxsize = 8000000000; } - $path .= rawurlencode ($val); - $i ++; - } + $this->maxsize = $maxsize; + $this->headersReset(); } - if (key_exists ("fragment", $parseURL)) - $path .= "#".$parseURL["fragment"]; - if (! key_exists ("host", $parseURL)) - throw new \Exception ("No host provided to URL", 406); - - // Prepare the headers to be sent - unset ($this->headersSent[0]); - array_unshift ($this->headersSent, - "$this->method $path HTTP/1.1"); - $this->headersSent["Host"] = $parseURL["host"]; - if ($this->acceptEncoding !== "") - $this->headersSent["Accept-Encoding"] = $this->acceptEncoding; - if ($this->acceptLanguage !== "") - $this->headersSent["Accept-Language"] = $this->acceptLanguage; - if ($this->accept != "") - $this->headersSent["Accept"] = $this->accept; - if ($this->useragent !== "") - $this->headersSent["User-Agent"] = $this->useragent; - if ($this->referer !== "") - $this->headersSent["Referer"] = $this->referer; - if ($this->authentication !== "") - $this->headersSent["Authorization"] = $this->authentication; - $this->headersSent["Connection"] = "keep-alive"; - $cookies = $this->cookieToSend ($this->url); - if (! empty ($cookies)) + ///////////////////////////////// + //// GETTERS / SETTERS //// + ///////////////////////////////// + /** Set / Get the url + * @param string|null $url Set / Get the url + */ + public function url($url = null) { - $this->headersSent["Cookie"] = implode ("; ", $cookies); - } - if ($this->method !== "GET" && ! empty ($this->formData)) - { - if (! key_exists ("Content-Type", $this->headersSent)) - $this->headersSent["Content-Type"] = - "application/x-www-form-urlencoded"; - $len = 0; - foreach ($this->formData as $key => $val) - { - if ($len > 0) - $len++; // Add the & - $len += strlen (rawurlencode ($key)) + 1; - if (isset ($val[0]) && $val[0] === "@") - { - $file = substr ($val, 1); - if (! file_exists ($file)) - throw new \Exception ("Data file '$file' doesn't exists", 406); - // TODO : Do a loop of 1MB for big files instead of loading the mem - $len += strlen (rawurlencode (file_get_contents ($file))); + if ($url === null) { + return $this->url; } - else - $len += strlen (rawurlencode ($val)); - } - $this->headersSent["Content-Length"] = $len; - } - if ($this->method !== "GET" && $this->rawData !== "") - { - if (! key_exists ("Content-Type", $this->headersSent)) - $this->headersSent["Content-Type"] = - "application/x-www-form-urlencoded"; - $this->headersSent["Content-Length"] = strlen ($this->rawData); + if (! is_string($url)) { + throw new \Exception("Invalid url to set : not a string", 406); + } + $this->url = $url; + return $this; } - $this->log (2, "Headers Send :"); - $this->log (2, $this->headersSent); - - // Send the request to the server - if ($this->tcpclient === null) + /** Set / Get the cookies stored + * @param array|null $cookies Set / Get the cookies + */ + public function cookies($cookies = null) { - $this->tcpclient = new Tcpclient ($parseURL["host"], $this->port); - $this->tcpclient->timeout ($this->timeout); - $this->tcpclient->connect (); - if ($parseURL["scheme"] === "https") - $this->tcpclient->cryptoEnable (true, null, $this->ssloptions); - } - $this->tcpclient->readMode ("text"); - $this->tcpclient->send ($this->headersSent[0]."\r\n"); - foreach ($this->headersSent as $header => $value) - { - if ($header === 0) - continue; - $this->tcpclient->send ("$header: $value\r\n"); - } - $this->tcpclient->send ("\r\n"); - - // Send the POST data form if exists - if ($this->method !== "GET" && ! empty ($this->formData)) - { - $i = 0; - $this->log (3, "Body Send : \n"); - foreach ($this->formData as $key => $val) - { - if ($i > 0) - { - $this->tcpclient->send ("&"); - $this->log (3, "&"); + if ($cookies === null) { + return $this->cookies; } - $this->tcpclient->send (rawurlencode ($key)."="); - $this->log (3, rawurlencode ($key)."="); - if (isset ($val[0]) && $val[0] === "@") - { - $file = substr ($val, 1); - if (! file_exists ($file)) - throw new \Exception ("Data file '$file' doesn't exists", 406); - // TODO : Do a loop of 1MB for big files instead of loading the mem - $val = file_get_contents ($file); - $this->tcpclient->send (rawurlencode ($val)); - $this->log (4, rawurlencode ($val)); + if (! is_array($cookies)) { + throw new \Exception("Invalid cookies to set : not an array", 406); } - else - { - $this->tcpclient->send (rawurlencode ($val)); - $this->log (3, rawurlencode ($val)); - } - $i ++; - } - $this->log (3, "\n"); - } - elseif ($this->method !== "GET" && $this->rawData !== "") - { - $this->tcpclient->send ($this->rawData); - $this->log (3, $this->rawData."\n"); + $this->cookies = $cookies; + return $this; } - // Get the result header from the server - $headers = array (); - while (($header = $this->tcpclient->read (4095)) !== "") + /** Set / Get the method + * @param string|null $method Set / Get the method + */ + public function method($method = null) { - @list ($key, $val) = explode (":", $header, 2); - if ($val === null) - $headers[] = $header; - else - { - if (key_exists ($key, $headers)) - { - if (! (is_array ($headers[$key]))) - $headers[$key] = array ($headers[$key]); - $headers[$key][] = trim ($val); + if ($method === null) { + return $this->method; } - else - $headers[$key] = trim ($val); - } + if (! is_string($method)) { + throw new \Exception("Invalid method to set : not an string", 406); + } + $method = strtoupper($method); + if (! in_array($method, array("GET", "POST", "PUT", "DELETE", "HEAD"))) { + throw new \Exception("Invalid method to set : not in list", 406); + } + $this->method = $method; + return $this; } - if (! key_exists (0, $headers)) - throw new \Exception ("No HTTP code available from server", 500); - $this->headersReceived = $headers; - $returnCode = $headers[0]; - preg_match_all ("#^HTTP/(?P\d.\d) (?P\d+) ". + + /** Get the headersReceived after the page was get + */ + public function headersReceived() + { + return $this->headersReceived; + } + + /** Get the headers sent to the server after the page was get + */ + public function headersSent() + { + return $this->headersSent; + } + + /** Set the headers to initial value + */ + public function headersReset() + { + $this->headersSent = array(); + return $this; + } + + /** Add a new header to be sent to the server + * @param string $header The header to add/update + * @param string $value The value to save + */ + public function headerAdd($header, $value) + { + $this->headersSent[$header] = $value; + return $this; + } + + /** Get the port used for connection + */ + public function port() + { + return $this->port; + } + + /** Set / Get the maximum maxsize allowed + * @param integer|null $maxsize The maxsize in bytes + */ + public function maxsize($maxsize = null) + { + if ($maxsize === null) { + return $this->maxsize; + } + $this->maxsize = intval($maxsize); + return $this; + } + + /** Get the HTTP Return code from connection + */ + public function httpCode() + { + return $this->httpCode; + } + + /** Set / Get the debug mode + * 0: Nothing is displayed, 1: Only URL are displayed, + * 2: headers only send and received, 3: all the content, but without sent + * files, 4: all the content + * @param boolean|null $debug The debug value to set or get + */ + public function debug($debug = null) + { + if ($debug === null) { + return $this->debug; + } + $this->debug = intval($debug); + return $this; + } + + /** Set / Get the form Data + * Will be of type array ("field" => "value") + * If value is like "@/tmp/file", use the /tmp/file as content + * @param array|null $formData The data to send to the server + */ + public function formData($formData = null) + { + if ($formData === null) { + return $this->formData; + } + if (! is_array($formData)) { + throw new \Exception("Invalid form data provided : not an array", 406); + } + $this->formData = $formData; + $this->rawData = ""; + return $this; + } + + /** Set / Get the content Data + * The data is in raw format and will not be modified. + * Overwrite the eventually previous form data and rawData + * @param string|null $rawData The data to use + */ + public function rawData($rawData = null) + { + if ($rawData === null) { + return $this->rawData; + } + if (! is_string($rawData)) { + throw new \Exception("Invalid raw data provided : not a string", 406); + } + $this->rawData = $rawData; + $this->formData = array(); + return $this; + } + + /** Get / Set the Store of session cookies when analyzing the answer of the + * server + * @param boolean|null $cookiesSession Allow to store the session cookies + */ + public function cookiesSession($cookiesSession = null) + { + if ($cookiesSession === null) { + return $this->cookiesSession; + } + $this->cookiesSession = !! $cookiesSession; + return $this; + } + + /** Get / Set the maximum number of redirect to follow before aborting + * @param integer|null $redirectMaxCount The maximum number of redirect + * before exception + */ + public function redirectMaxCount($redirectMaxCount = null) + { + if ($redirectMaxCount === null) { + return $this->redirectMaxCount; + } + $this->redirectMaxCount = intval($redirectMaxCount); + return $this; + } + + /** Get / Set the actual number of redirect + * @param integer|null $redirectCount The actual number of redirect + */ + public function redirectCount($redirectCount = null) + { + if ($redirectCount === null) { + return $this->redirectCount; + } + $this->redirectCount = intval($redirectCount); + return $this; + } + + /** Get / Set the timeout in second before expiring the connection + * 30s by default + * @param integer|null $timeout The timeout value + */ + public function timeout($timeout = null) + { + if ($timeout === null) { + return $this->timeout; + } + $this->timeout = intval($timeout); + return $this; + } + + /** Get / Set the useragent sent to the server. If it is empty, it will not be + * sent + * @param string|null $useragent The user agent to use + */ + public function useragent($useragent = null) + { + if ($useragent === null) { + return $this->useragent; + } + $this->useragent = $useragent; + return $this; + } + + /** Get/Set the referer page + * @param string|null $referer The new referer that will be used on next + * request + */ + public function referer($referer = null) + { + if ($referer === null) { + return $this->referer; + } + $this->referer = $referer; + return $this; + } + + /** Get/Set the accept type of page wanted by the client + * @param string|null $accept The accept types with weight + */ + public function accept($accept = null) + { + if ($accept === null) { + return $this->accept; + } + $this->accept = $accept; + return $this; + } + + /** Get/Set the accept Language wanted by the client + * @param string|null $acceptLanguage The languages with weight + */ + public function acceptLanguage($acceptLanguage = null) + { + if ($acceptLanguage === null) { + return $this->acceptLanguage; + } + $this->acceptLanguage = $acceptLanguage; + return $this; + } + + /** Get/Set the accept Encoding wanted by the client + * @param string|null $acceptEncoding The encoding requested + */ + public function acceptEncoding($acceptEncoding = null) + { + if ($acceptEncoding === null) { + return $this->acceptEncoding; + } + $this->acceptEncoding = $acceptEncoding; + return $this; + } + + /** Set the authentication in Basic type + * @param string $login The login to use + * @param string $password The password to use + */ + public function authBasic($login, $password) + { + $this->authentication = "Basic " . base64_encode("$login:$password"); + return $this; + } + + /** Get/Set authentication + * To remove authentication, pass "" to $auth arg + * @param string|null $auth The authentication string to send + * @return value or $this + */ + public function authentication($auth = null) + { + if ($auth === null) { + return $this->authentication; + } + $this->authentication = $auth; + return $this; + } + + /** Get/Set the ssl options + * @param array|null $ssloptions The SSL Options to use + * @return $this + */ + public function ssloptions($ssloptions = null) + { + if ($ssloptions === null) { + return $this->ssloptions; + } + $this->ssloptions = $ssloptions; + return $this; + } + + /** Get meta data, like the timeout state, the crypto protocol and ciphers... + */ + public function getMeta() + { + return $this->tcpclient->getMeta(); + } + + /** Return the TCP infos of the connection + */ + public function getInfo() + { + return $this->tcpclient->getInfo(); + } + + ////////////////////////////////// + //// THE ACTIVE METHODS //// + ////////////////////////////////// + /** Get the page + * Will fill the headersReceived, cookies and port properties. + * This will fill all the RAM if the page is too big. For big files, use + * $httpclient->url ($url) + * ->connect () ; + * while ($content = $httpclient->read ()) {} + * $httpclient->disconnect (); + * If no maxsize limit is set, limit the download to 8G + * @param string $url The URL to get + * @param array|null $ssloptions The SSL options (stream_context_set_option) + * @return the page body + */ + public function getPage($url, $ssloptions = null) + { + $this->method("GET"); + $this->url($url); + $this->connect($ssloptions); + return $this->getContent(); + } + + /** Init the connection to URL + * Will fill the headersReceived, cookies and port properties. + * @param array|null $ssloptions The SSL options (stream_context_set_option) + * @return $this + */ + public function connect($ssloptions = null) + { + $this->log(2, "## URL Start $this->method $this->url"); + if ($ssloptions !== null) { + $this->ssloptions = $ssloptions; + } + $this->headersReceived = array(); + $this->bodySize = null; + $this->httpCode = null; + if ($this->url === "") { + throw new \Exception("No URL set to connect", 406); + } + // Manage the URL (and the parameters in GET method) + $parseURL = parse_url($this->url); + if (! key_exists("scheme", $parseURL)) { + throw new \Exception("Scheme must be set to http or https", 406); + } + if ( + $parseURL["scheme"] !== "http" && + $parseURL["scheme"] !== "https" + ) { + throw new \Exception("Scheme must be http or https only", 406); + } + if (key_exists("port", $parseURL)) { + $this->port = $parseURL["port"]; + } elseif (key_exists("scheme", $parseURL)) { + if ($parseURL["scheme"] === "http") { + $this->port = 80; + } elseif ($parseURL["scheme"] === "https") { + $this->port = 443; + } + } + if (! key_exists("path", $parseURL)) { + $path = "/"; + } else { + $path = $parseURL["path"]; + } + if (key_exists("query", $parseURL)) { + $path .= "?" . $parseURL["query"]; + } + + if ($this->method === "GET" && ! empty($this->formData)) { + // In GET method, the form data are added to the path + if (! key_exists("query", $parseURL)) { + $path .= "?"; + } else { + $path .= "&"; + } + $i = 0; + foreach ($this->formData as $key => $val) { + if ($i > 0) { + $path .= "&"; + } + $path .= rawurlencode($key) . "="; + if (isset($val[0]) && $val[0] === "@") { + $file = substr($val, 1); + if (! file_exists($file)) { + throw new \Exception("Data file '$file' doesn't exists", 406); + } + $val = file_get_contents($file); + } + $path .= rawurlencode($val); + $i++; + } + } + + if (key_exists("fragment", $parseURL)) { + $path .= "#" . $parseURL["fragment"]; + } + if (! key_exists("host", $parseURL)) { + throw new \Exception("No host provided to URL", 406); + } + + // Prepare the headers to be sent + unset($this->headersSent[0]); + array_unshift( + $this->headersSent, + "$this->method $path HTTP/1.1" + ); + $this->headersSent["Host"] = $parseURL["host"]; + if ($this->acceptEncoding !== "") { + $this->headersSent["Accept-Encoding"] = $this->acceptEncoding; + } + if ($this->acceptLanguage !== "") { + $this->headersSent["Accept-Language"] = $this->acceptLanguage; + } + if ($this->accept != "") { + $this->headersSent["Accept"] = $this->accept; + } + if ($this->useragent !== "") { + $this->headersSent["User-Agent"] = $this->useragent; + } + if ($this->referer !== "") { + $this->headersSent["Referer"] = $this->referer; + } + if ($this->authentication !== "") { + $this->headersSent["Authorization"] = $this->authentication; + } + $this->headersSent["Connection"] = "keep-alive"; + $cookies = $this->cookieToSend($this->url); + if (! empty($cookies)) { + $this->headersSent["Cookie"] = implode("; ", $cookies); + } + if ($this->method !== "GET" && ! empty($this->formData)) { + if (! key_exists("Content-Type", $this->headersSent)) { + $this->headersSent["Content-Type"] = + "application/x-www-form-urlencoded"; + } + $len = 0; + foreach ($this->formData as $key => $val) { + if ($len > 0) { + $len++; + } // Add the & + $len += strlen(rawurlencode($key)) + 1; + if (isset($val[0]) && $val[0] === "@") { + $file = substr($val, 1); + if (! file_exists($file)) { + throw new \Exception("Data file '$file' doesn't exists", 406); + } + // TODO : Do a loop of 1MB for big files instead of loading the mem + $len += strlen(rawurlencode(file_get_contents($file))); + } else { + $len += strlen(rawurlencode($val)); + } + } + $this->headersSent["Content-Length"] = $len; + } + if ($this->method !== "GET" && $this->rawData !== "") { + if (! key_exists("Content-Type", $this->headersSent)) { + $this->headersSent["Content-Type"] = + "application/x-www-form-urlencoded"; + } + $this->headersSent["Content-Length"] = strlen($this->rawData); + } + + $this->log(2, "Headers Send :"); + $this->log(2, $this->headersSent); + + // Send the request to the server + if ($this->tcpclient === null) { + $this->tcpclient = new Tcpclient($parseURL["host"], $this->port); + $this->tcpclient->timeout($this->timeout); + $this->tcpclient->connect(); + if ($parseURL["scheme"] === "https") { + $this->tcpclient->cryptoEnable(true, null, $this->ssloptions); + } + } + $this->tcpclient->readMode("text"); + $this->tcpclient->send($this->headersSent[0] . "\r\n"); + foreach ($this->headersSent as $header => $value) { + if ($header === 0) { + continue; + } + $this->tcpclient->send("$header: $value\r\n"); + } + $this->tcpclient->send("\r\n"); + + // Send the POST data form if exists + if ($this->method !== "GET" && ! empty($this->formData)) { + $i = 0; + $this->log(3, "Body Send : \n"); + foreach ($this->formData as $key => $val) { + if ($i > 0) { + $this->tcpclient->send("&"); + $this->log(3, "&"); + } + $this->tcpclient->send(rawurlencode($key) . "="); + $this->log(3, rawurlencode($key) . "="); + if (isset($val[0]) && $val[0] === "@") { + $file = substr($val, 1); + if (! file_exists($file)) { + throw new \Exception("Data file '$file' doesn't exists", 406); + } + // TODO : Do a loop of 1MB for big files instead of loading the mem + $val = file_get_contents($file); + $this->tcpclient->send(rawurlencode($val)); + $this->log(4, rawurlencode($val)); + } else { + $this->tcpclient->send(rawurlencode($val)); + $this->log(3, rawurlencode($val)); + } + $i++; + } + $this->log(3, "\n"); + } elseif ($this->method !== "GET" && $this->rawData !== "") { + $this->tcpclient->send($this->rawData); + $this->log(3, $this->rawData . "\n"); + } + + // Get the result header from the server + $headers = array(); + while (($header = $this->tcpclient->read(4095)) !== "") { + @list($key, $val) = explode(":", $header, 2); + if ($val === null) { + $headers[] = $header; + } else { + if (key_exists($key, $headers)) { + if (! (is_array($headers[$key]))) { + $headers[$key] = array($headers[$key]); + } + $headers[$key][] = trim($val); + } else { + $headers[$key] = trim($val); + } + } + } + if (! key_exists(0, $headers)) { + throw new \Exception("No HTTP code available from server", 500); + } + $this->headersReceived = $headers; + $returnCode = $headers[0]; + preg_match_all("#^HTTP/(?P\d.\d) (?P\d+) " . "(?P.+)$#i", $returnCode, $matches); - if (isset ($matches["HTTPCode"][0])) - $this->httpCode = intval ($matches["HTTPCode"][0]); - - // Add the received cookies to property - if (isset ($headers["Set-Cookie"])) - { - if (! is_array ($headers["Set-Cookie"])) - $cookies = array ($headers["Set-Cookie"]); - else - $cookies = $headers["Set-Cookie"]; - foreach ($cookies as $cookie) - { - // The invalid cookies are silently dropped - $this->cookieAdd ($parseURL["host"], $cookie); - } - } - $this->log (2, "Headers Received :"); - $this->log (2, $this->headersReceived); - - $this->contentMethod = false; - if (key_exists ("Transfer-Encoding", $headers) && - $headers["Transfer-Encoding"] === "chunked") - { - $this->contentMethod = "chunked"; - $this->bodySize = 0; - } - elseif (key_exists ("Content-Length", $headers)) - { - $this->contentMethod = "Content-Length"; - $this->bodySize = $headers["Content-Length"]; - } - elseif (key_exists ("Connection", $headers) && - $headers["Connection"] === "close") - { - // Connection closed by server. Nothing to get - } - elseif ($this->httpCode !== 204 && $this->httpCode !== 301 && - $this->httpCode !== 302) - { - throw new \Exception ("No transfert content provided", 500); - } - if ($this->contentMethod === "chunked") - $this->log (1, "URL $this->method $this->url $this->httpCode Chunked"); - elseif (is_numeric ($this->bodySize)) - $this->log (1, "URL $this->method $this->url $this->httpCode ". - $this->bodySize); - else - $this->log (1, "URL $this->method $this->url $this->httpCode 0"); - return $this; - } - - /** Get the content from the server and put it in memory - */ - public function getContent () - { - $url = $this->url; - $content = ""; - while ($tmp = $this->read (1000000)) - { - $content .= $tmp; - if (strlen ($content) > $this->maxsize) - throw new \Exception ("File to get exceeded maxsize", 500); - } - if (key_exists ("Content-Encoding", $this->headersReceived)) - { - if ($this->headersReceived["Content-Encoding"] === "gzip" && - function_exists ("gzdecode")) - $content = gzdecode ($content); - } - $this->disconnect (); - $this->headersReset (); - $this->formData = ""; - $this->rawData = ""; - if ($this->httpCode === 301 || $this->httpCode === 302 || - key_exists ("Location", $this->headersReceived)) - { - if (! key_exists ("Location", $this->headersReceived)) - throw new \Exception ("Redirect without location provided", 406); - $this->redirectCount++; - if ($this->redirectCount > $this->redirectMaxCount) - throw new \Exception ("Redirect exceed maximum limit", 406); - // echo "REDIRECT TO ".$this->headersReceived["Location"]."\n"; - $location = $this->headersReceived["Location"]; - $parseURLInit = parse_url ($url); - $parseURLLocation = parse_url ($location); - if ($parseURLLocation["path"][0] !== "/" && - key_exists ("path", $parseURLInit)) - $location = dirname ($parseURLInit["path"]).$location; - if (! key_exists ("port", $parseURLLocation) && - key_exists ("port", $parseURLInit)) - $location = ":".$parseURLInit["port"].$location; - if (! key_exists ("host", $parseURLLocation)) - $location = $parseURLInit["host"].$location; - if (! key_exists ("scheme", $parseURLLocation)) - $location = $parseURLInit["scheme"]."://".$location; - $this->log (1, "REDIRECT $this->httpCode to $location"); - $this->log (2, " content=$content\n"); - $content = $this->getPage ($location, $this->ssloptions); - } - $this->referer = $url; - $this->redirectCount = 0; - return $content; - } - - /** Read max MAXSIZE bytes - * Return "" if all the file is received - * 3 methods are supported : Chunked mode, Content-Length defined and all - * until the connection will be closed by the server - * @param integer $maxsize The maxsize to get in this read - */ - public function read ($maxsize = 4096) - { - if ($this->tcpclient === null) - throw new \Exception ("HTTPClient : can not read non connected URL", 406); - $this->tcpclient->timeout ($this->timeout); - $content = ""; - if ($this->contentMethod === "chunked" && $this->bodySize === 0) - { - // Get the body chunk size - $this->tcpclient->readMode ("text"); - $size = trim ($this->tcpclient->read ()); - $this->bodySize = hexdec ($size); - } - if ($this->bodySize === 0) - return ""; - if ($this->bodySize === null) - $toBeRead = $maxsize; - else - $toBeRead = $this->bodySize; - if ($toBeRead > $maxsize) - $toBeRead = $maxsize; - $this->tcpclient->readMode ("binary"); - if ($toBeRead > 0) - $content = $this->tcpclient->read ($toBeRead); - // In close mode, the bodySize is not set and should not be updated - if ($this->bodySize !== null) - $this->bodySize = $this->bodySize - strlen ($content); - if ($this->contentMethod === "chunked" && $this->bodySize === 0) - { - // Get the Carriage return before the next chunk size - $this->tcpclient->readMode ("text"); - $cr = trim ($this->tcpclient->read ()); - } - $this->log (3, $content); - return $content; - } - - /** Disconnect the connection - */ - public function disconnect () - { - $this->tcpclient = null; - } - - /** Display the log message - * @param integer $priority The minimal priority to display the message - * @param mixed $message The message to display - */ - public function log ($priority, $message) - { - if ($this->debug < $priority) - return; - if (is_array ($message)) - print_r ($message); - elseif (is_bool ($message)) - { - if ($message) echo "TRUE\n"; else echo "FALSE\n"; - } - else - { - echo "$message"; - if ($priority < 3) - echo "\n"; - } - } - - /** Return the base URL of the site - * @return the URL - */ - public function baseURL () - { - if ($this->url === "") - throw new \Exception ("Can not get baseURL of empty url", 500); - $parseURL = parse_url ($this->url); - $scheme = isset ($parseURL['scheme']) ? $parseURL['scheme'] . '://' : ''; - $host = isset ($parseURL['host']) ? $parseURL['host'] : ''; - $port = isset ($parseURL['port']) ? ':' . $parseURL['port'] : ''; - $user = isset ($parseURL['user']) ? $parseURL['user'] : ''; - $pass = isset ($parseURL['pass']) ? ':' . $parseURL['pass'] : ''; - $pass = ($user || $pass) ? "$pass@" : ''; - return "$scheme$user$pass$host$port"; - } - - ////////////////////////////////// - //// COOKIES MANAGEMENT //// - ////////////////////////////////// - /** The cookies are stored in Netscape cookies.txt file : - The layout of Netscape's cookies.txt file is such that each line contains - one name-value pair. An example cookies.txt file may have an entry that - looks like this: - - .netscape.com TRUE / FALSE 946684799 NETSCAPE_ID 100103 - - Each line represents a single piece of stored information. A tab is inserted - between each of the fields. - - From left-to-right, here is what each field represents: - domain : The domain that created AND that can read the variable. - flag : A TRUE/FALSE value indicating if all machines within a given - domain can access the variable. This value is set automatically - by the browser, depending on the value you set for domain. - path : The path within the domain that the variable is valid for. - secure : A TRUE/FALSE value indicating if a secure connection with the - domain is needed to access the variable. - expiration : The UNIX time that the variable will expire on. UNIX time is - defined as the number of seconds since Jan 1, 1970 00:00:00 - GMT. - name : The name of the variable. - - value : The value of the variable. - */ - - /** Add a cookie in the store - * If the cookie already exists, the old one is replaced by the new value - * @param string $domain The domain to use - * @param string $cookie The cookie content to store - */ - public function cookieAdd ($domain, $cookie) - { - // echo "COOKIE = $cookie\n"; - $content = explode (";", $cookie); - $flag = "FALSE"; - $path = "/"; - $secure = "FALSE"; - $expiration = 0; - $name = ""; - $value = ""; - foreach ($content as $part) - { - @list ($key, $val) = explode ("=", $part, 2); - $key = trim ($key); - if (strtolower ($key) === "path") $path = $val; - elseif (strtolower ($key) === "domain") - { - // Check if $domain is compatible with $key before storing the cookie - if (substr ($domain, -1 * strlen ($val)) === $val) - { - $domain = $val; - $flag = "TRUE"; + if (isset($matches["HTTPCode"][0])) { + $this->httpCode = intval($matches["HTTPCode"][0]); } - else - { - return "Invalid domain provided"; + + // Add the received cookies to property + if (isset($headers["Set-Cookie"])) { + if (! is_array($headers["Set-Cookie"])) { + $cookies = array($headers["Set-Cookie"]); + } else { + $cookies = $headers["Set-Cookie"]; + } + foreach ($cookies as $cookie) { + // The invalid cookies are silently dropped + $this->cookieAdd($parseURL["host"], $cookie); + } } - } - elseif (strtolower ($key) === "expires") - { - try - { - $date = new \DateTime ($val); - $expiration = $date->getTimestamp(); + $this->log(2, "Headers Received :"); + $this->log(2, $this->headersReceived); + + $this->contentMethod = false; + if ( + key_exists("Transfer-Encoding", $headers) && + $headers["Transfer-Encoding"] === "chunked" + ) { + $this->contentMethod = "chunked"; + $this->bodySize = 0; + } elseif (key_exists("Content-Length", $headers)) { + $this->contentMethod = "Content-Length"; + $this->bodySize = $headers["Content-Length"]; + } elseif ( + key_exists("Connection", $headers) && + $headers["Connection"] === "close" + ) { + // Connection closed by server. Nothing to get + } elseif ( + $this->httpCode !== 204 && $this->httpCode !== 301 && + $this->httpCode !== 302 + ) { + throw new \Exception("No transfert content provided", 500); } - catch (\Exception $e) - { - return "Invalid expires date provided"; + if ($this->contentMethod === "chunked") { + $this->log(1, "URL $this->method $this->url $this->httpCode Chunked"); + } elseif (is_numeric($this->bodySize)) { + $this->log(1, "URL $this->method $this->url $this->httpCode " . + $this->bodySize); + } else { + $this->log(1, "URL $this->method $this->url $this->httpCode 0"); } - } - elseif ($val !== null && $name === "") - { - // Only the first value will be stored as cookie (name, val) pair - // echo "KEY=$key => $val\n"; - $name = $key; - $value = $val; - } - elseif ($val !== null) - { - // echo "Not managed key=>val $key=>$val\n"; - } - else - { - // No value provided : no test - } + return $this; } - $cookieLine = "$domain\t$flag\t$path\t$secure\t$expiration\t$name\t$value"; - if (strlen ($cookieLine) > 4096) - return "Cookie value too long"; - if ($expiration === 0 && $this->cookiesSession === false) + /** Get the content from the server and put it in memory + */ + public function getContent() { - // echo "Do not store Session cookies\n"; - return; + $url = $this->url; + $content = ""; + while ($tmp = $this->read(1000000)) { + $content .= $tmp; + if (strlen($content) > $this->maxsize) { + throw new \Exception("File to get exceeded maxsize", 500); + } + } + if (key_exists("Content-Encoding", $this->headersReceived)) { + if ( + $this->headersReceived["Content-Encoding"] === "gzip" && + function_exists("gzdecode") + ) { + $content = gzdecode($content); + } + } + $this->disconnect(); + $this->headersReset(); + $this->formData = ""; + $this->rawData = ""; + if ( + $this->httpCode === 301 || $this->httpCode === 302 || + key_exists("Location", $this->headersReceived) + ) { + if (! key_exists("Location", $this->headersReceived)) { + throw new \Exception("Redirect without location provided", 406); + } + $this->redirectCount++; + if ($this->redirectCount > $this->redirectMaxCount) { + throw new \Exception("Redirect exceed maximum limit", 406); + } + // echo "REDIRECT TO ".$this->headersReceived["Location"]."\n"; + $location = $this->headersReceived["Location"]; + $parseURLInit = parse_url($url); + $parseURLLocation = parse_url($location); + if ( + $parseURLLocation["path"][0] !== "/" && + key_exists("path", $parseURLInit) + ) { + $location = dirname($parseURLInit["path"]) . $location; + } + if ( + ! key_exists("port", $parseURLLocation) && + key_exists("port", $parseURLInit) + ) { + $location = ":" . $parseURLInit["port"] . $location; + } + if (! key_exists("host", $parseURLLocation)) { + $location = $parseURLInit["host"] . $location; + } + if (! key_exists("scheme", $parseURLLocation)) { + $location = $parseURLInit["scheme"] . "://" . $location; + } + $this->log(1, "REDIRECT $this->httpCode to $location"); + $this->log(2, " content=$content\n"); + $content = $this->getPage($location, $this->ssloptions); + } + $this->referer = $url; + $this->redirectCount = 0; + return $content; } - $found = false; - foreach ($this->cookies as $key => $storedCookie) + /** Read max MAXSIZE bytes + * Return "" if all the file is received + * 3 methods are supported : Chunked mode, Content-Length defined and all + * until the connection will be closed by the server + * @param integer $maxsize The maxsize to get in this read + */ + public function read($maxsize = 4096) { - $storedCookie = explode ("\t", $storedCookie); - if (! key_exists (0, $storedCookie) || - ! key_exists (5, $storedCookie)) - continue; - if ($storedCookie[0] !== $domain || $storedCookie[5] !== $name) - continue; - if ($expiration > 0 && $expiration < time ()) - { - //echo "Remove the already set cookie for $domain $name : expired\n"; - unset ($this->cookies[$key]); - $found = true; - } - else - { - //echo "Update the already set cookie for $domain $name\n"; - $this->cookies[$key] = $cookieLine; - $found = true; - } + if ($this->tcpclient === null) { + throw new \Exception("HTTPClient : can not read non connected URL", 406); + } + $this->tcpclient->timeout($this->timeout); + $content = ""; + if ($this->contentMethod === "chunked" && $this->bodySize === 0) { + // Get the body chunk size + $this->tcpclient->readMode("text"); + $size = trim($this->tcpclient->read()); + $this->bodySize = hexdec($size); + } + if ($this->bodySize === 0) { + return ""; + } + if ($this->bodySize === null) { + $toBeRead = $maxsize; + } else { + $toBeRead = $this->bodySize; + } + if ($toBeRead > $maxsize) { + $toBeRead = $maxsize; + } + $this->tcpclient->readMode("binary"); + if ($toBeRead > 0) { + $content = $this->tcpclient->read($toBeRead); + } + // In close mode, the bodySize is not set and should not be updated + if ($this->bodySize !== null) { + $this->bodySize = $this->bodySize - strlen($content); + } + if ($this->contentMethod === "chunked" && $this->bodySize === 0) { + // Get the Carriage return before the next chunk size + $this->tcpclient->readMode("text"); + $cr = trim($this->tcpclient->read()); + } + $this->log(3, $content); + return $content; } - if ($found === false) - { - //echo "Append the new cookie for $domain $name\n"; - $this->cookies[] = $cookieLine; - } - } - /** Check if some stored cookies must be send to the server, because they are - * in the same domain. - * @param string $url The URL requested - * @return array the cookies to add to the headers send to the server + /** Disconnect the connection + */ + public function disconnect() + { + $this->tcpclient = null; + } + + /** Display the log message + * @param integer $priority The minimal priority to display the message + * @param mixed $message The message to display + */ + public function log($priority, $message) + { + if ($this->debug < $priority) { + return; + } + if (is_array($message)) { + print_r($message); + } elseif (is_bool($message)) { + if ($message) { + echo "TRUE\n"; + } else { + echo "FALSE\n"; + } + } else { + echo "$message"; + if ($priority < 3) { + echo "\n"; + } + } + } + + /** Return the base URL of the site + * @return the URL + */ + public function baseURL() + { + if ($this->url === "") { + throw new \Exception("Can not get baseURL of empty url", 500); + } + $parseURL = parse_url($this->url); + $scheme = isset($parseURL['scheme']) ? $parseURL['scheme'] . '://' : ''; + $host = isset($parseURL['host']) ? $parseURL['host'] : ''; + $port = isset($parseURL['port']) ? ':' . $parseURL['port'] : ''; + $user = isset($parseURL['user']) ? $parseURL['user'] : ''; + $pass = isset($parseURL['pass']) ? ':' . $parseURL['pass'] : ''; + $pass = ($user || $pass) ? "$pass@" : ''; + return "$scheme$user$pass$host$port"; + } + + ////////////////////////////////// + //// COOKIES MANAGEMENT //// + ////////////////////////////////// + /** The cookies are stored in Netscape cookies.txt file : + The layout of Netscape's cookies.txt file is such that each line contains + one name-value pair. An example cookies.txt file may have an entry that + looks like this: + + .netscape.com TRUE / FALSE 946684799 NETSCAPE_ID 100103 + + Each line represents a single piece of stored information. A tab is inserted + between each of the fields. + + From left-to-right, here is what each field represents: + domain : The domain that created AND that can read the variable. + flag : A TRUE/FALSE value indicating if all machines within a given + domain can access the variable. This value is set automatically + by the browser, depending on the value you set for domain. + path : The path within the domain that the variable is valid for. + secure : A TRUE/FALSE value indicating if a secure connection with the + domain is needed to access the variable. + expiration : The UNIX time that the variable will expire on. UNIX time is + defined as the number of seconds since Jan 1, 1970 00:00:00 + GMT. + name : The name of the variable. + + value : The value of the variable. */ - public function cookieToSend ($url) - { - $parseURL = parse_url ($this->url); - if ($parseURL === false) - return array (); - if (! key_exists ("host", $parseURL)) - return array (); - if (! key_exists ("path", $parseURL)) - $parseURL["path"] = "/"; - if ($parseURL["path"][0] !== "/") - $parseURL["path"] = "/".$parseURL["path"]; - $res = array (); - foreach ($this->cookies as $storedCookie) + + /** Add a cookie in the store + * If the cookie already exists, the old one is replaced by the new value + * @param string $domain The domain to use + * @param string $cookie The cookie content to store + */ + public function cookieAdd($domain, $cookie) { - $storedCookie = explode ("\t", $storedCookie); - if (! key_exists (0, $storedCookie) || - ! key_exists (2, $storedCookie) || - ! key_exists (5, $storedCookie) || - ! key_exists (6, $storedCookie)) - continue; - if ($storedCookie[0] !== substr ($parseURL["host"], - -1 * strlen ($storedCookie[0])) || - $storedCookie[2] !== substr ($parseURL["path"], 0, - strlen ($storedCookie[2]))) - continue; - $res[] = $storedCookie[5]."=".$storedCookie[6]; + // echo "COOKIE = $cookie\n"; + $content = explode(";", $cookie); + $flag = "FALSE"; + $path = "/"; + $secure = "FALSE"; + $expiration = 0; + $name = ""; + $value = ""; + foreach ($content as $part) { + @list($key, $val) = explode("=", $part, 2); + $key = trim($key); + if (strtolower($key) === "path") { + $path = $val; + } elseif (strtolower($key) === "domain") { + // Check if $domain is compatible with $key before storing the cookie + if (substr($domain, -1 * strlen($val)) === $val) { + $domain = $val; + $flag = "TRUE"; + } else { + return "Invalid domain provided"; + } + } elseif (strtolower($key) === "expires") { + try { + $date = new \DateTime($val); + $expiration = $date->getTimestamp(); + } catch (\Exception $e) { + return "Invalid expires date provided"; + } + } elseif ($val !== null && $name === "") { + // Only the first value will be stored as cookie (name, val) pair + // echo "KEY=$key => $val\n"; + $name = $key; + $value = $val; + } elseif ($val !== null) { + // echo "Not managed key=>val $key=>$val\n"; + } else { + // No value provided : no test + } + } + + $cookieLine = "$domain\t$flag\t$path\t$secure\t$expiration\t$name\t$value"; + if (strlen($cookieLine) > 4096) { + return "Cookie value too long"; + } + if ($expiration === 0 && $this->cookiesSession === false) { + // echo "Do not store Session cookies\n"; + return; + } + + $found = false; + foreach ($this->cookies as $key => $storedCookie) { + $storedCookie = explode("\t", $storedCookie); + if ( + ! key_exists(0, $storedCookie) || + ! key_exists(5, $storedCookie) + ) { + continue; + } + if ($storedCookie[0] !== $domain || $storedCookie[5] !== $name) { + continue; + } + if ($expiration > 0 && $expiration < time()) { + //echo "Remove the already set cookie for $domain $name : expired\n"; + unset($this->cookies[$key]); + $found = true; + } else { + //echo "Update the already set cookie for $domain $name\n"; + $this->cookies[$key] = $cookieLine; + $found = true; + } + } + if ($found === false) { + //echo "Append the new cookie for $domain $name\n"; + $this->cookies[] = $cookieLine; + } + } + + /** Check if some stored cookies must be send to the server, because they are + * in the same domain. + * @param string $url The URL requested + * @return array the cookies to add to the headers send to the server + */ + public function cookieToSend($url) + { + $parseURL = parse_url($this->url); + if ($parseURL === false) { + return array(); + } + if (! key_exists("host", $parseURL)) { + return array(); + } + if (! key_exists("path", $parseURL)) { + $parseURL["path"] = "/"; + } + if ($parseURL["path"][0] !== "/") { + $parseURL["path"] = "/" . $parseURL["path"]; + } + $res = array(); + foreach ($this->cookies as $storedCookie) { + $storedCookie = explode("\t", $storedCookie); + if ( + ! key_exists(0, $storedCookie) || + ! key_exists(2, $storedCookie) || + ! key_exists(5, $storedCookie) || + ! key_exists(6, $storedCookie) + ) { + continue; + } + if ( + $storedCookie[0] !== substr( + $parseURL["host"], + -1 * strlen($storedCookie[0]) + ) || + $storedCookie[2] !== substr( + $parseURL["path"], + 0, + strlen($storedCookie[2]) + ) + ) { + continue; + } + $res[] = $storedCookie[5] . "=" . $storedCookie[6]; + } + return $res; } - return $res; - } } diff --git a/src/Imap.php b/src/Imap.php index e2e8515..0272d48 100644 --- a/src/Imap.php +++ b/src/Imap.php @@ -1,4 +1,5 @@ @@ -11,841 +12,977 @@ namespace Domframework; In the IMAP terminology, "mailbox" is a folder in the mailbox of the user */ class Imap { - /** The mailbox string */ - private $mailbox = null; - /** The current folder in UTF-8 */ - private $curDir = "INBOX"; - /** The auto expunge feature, after deleting/moving an email */ - public $autoexpunge = true; + /** The mailbox string */ + private $mailbox = null; + /** The current folder in UTF-8 */ + private $curDir = "INBOX"; + /** The auto expunge feature, after deleting/moving an email */ + public $autoexpunge = true; - /** Limit to one instance of the connection to the same database */ - // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ - private static $instance = array (); + /** Limit to one instance of the connection to the same database */ + // Based on an idea of http://tonylandis.com/php/php5-pdo-singleton-class/ + private static $instance = array(); - /** The constructor - * The IMAP standard port is 143, but SSL tunnelled is 993 - * @param string|null $imapserver The IMAP server to connect. Localhost is - * used if not defined - * @param integer|null $imapport The IMAP port to connect. 143 is used if not - * defined - * @param string|null $username The username to connect - * @param string|null $password The password to connect - * @param boolean|null $imapssl Use the SSL connection layer. Not used by - * default - * @param boolean|null $imapcertvalidate Check the certificates if using the - * SSL connection. True by default - */ - public function __construct ($imapserver = "localhost", $imapport = 143, - $username = null, $password = null, - $imapssl = false, $imapcertvalidate = true) - { - $this->connect ($imapserver, $imapport, $username, $password, $imapssl, - $imapcertvalidate); - } + /** The constructor + * The IMAP standard port is 143, but SSL tunnelled is 993 + * @param string|null $imapserver The IMAP server to connect. Localhost is + * used if not defined + * @param integer|null $imapport The IMAP port to connect. 143 is used if not + * defined + * @param string|null $username The username to connect + * @param string|null $password The password to connect + * @param boolean|null $imapssl Use the SSL connection layer. Not used by + * default + * @param boolean|null $imapcertvalidate Check the certificates if using the + * SSL connection. True by default + */ + public function __construct( + $imapserver = "localhost", + $imapport = 143, + $username = null, + $password = null, + $imapssl = false, + $imapcertvalidate = true + ) { + $this->connect( + $imapserver, + $imapport, + $username, + $password, + $imapssl, + $imapcertvalidate + ); + } - /** The connect can be used when extends the imap class. The constructor can - * be override by the child class. - * The IMAP standard port is 143, but SSL tunnelled is 993 - * @param string|null $imapserver The IMAP server to connect. Localhost is - * used if not defined - * @param integer|null $imapport The IMAP port to connect. 143 is used if not - * defined - * @param string|null $username The username to connect - * @param string|null $password The password to connect - * @param boolean|null $imapssl Use the SSL connection layer. Not used by - * default - * @param boolean|null $imapcertvalidate Check the certificates if using the - * SSL connection. True by default - */ - public function connect ($imapserver = "localhost", $imapport = 143, - $username = null, $password = null, - $imapssl = false, $imapcertvalidate = true) - { - if (! function_exists ("imap_open")) - throw new \Exception ("PHP don't support IMAP. Please add it !", 500); - if (! function_exists ("mb_convert_encoding")) - throw new \Exception ("PHP don't support MBString. Please add it !", 500); - if ($username === null) - throw new \Exception ("No username provided for IMAP server", 500); - if ($password === null) - throw new \Exception ("No password provided for IMAP server", 500); - $imapssl = ($imapssl !== false) ? "/ssl" : ""; - $imapcertvalidate = ($imapcertvalidate === false) ? "/novalidate-cert" : ""; - $this->mailbox = "{"."$imapserver:$imapport/imap$imapssl$imapcertvalidate". + /** The connect can be used when extends the imap class. The constructor can + * be override by the child class. + * The IMAP standard port is 143, but SSL tunnelled is 993 + * @param string|null $imapserver The IMAP server to connect. Localhost is + * used if not defined + * @param integer|null $imapport The IMAP port to connect. 143 is used if not + * defined + * @param string|null $username The username to connect + * @param string|null $password The password to connect + * @param boolean|null $imapssl Use the SSL connection layer. Not used by + * default + * @param boolean|null $imapcertvalidate Check the certificates if using the + * SSL connection. True by default + */ + public function connect( + $imapserver = "localhost", + $imapport = 143, + $username = null, + $password = null, + $imapssl = false, + $imapcertvalidate = true + ) { + if (! function_exists("imap_open")) { + throw new \Exception("PHP don't support IMAP. Please add it !", 500); + } + if (! function_exists("mb_convert_encoding")) { + throw new \Exception("PHP don't support MBString. Please add it !", 500); + } + if ($username === null) { + throw new \Exception("No username provided for IMAP server", 500); + } + if ($password === null) { + throw new \Exception("No password provided for IMAP server", 500); + } + $imapssl = ($imapssl !== false) ? "/ssl" : ""; + $imapcertvalidate = ($imapcertvalidate === false) ? "/novalidate-cert" : ""; + $this->mailbox = "{" . "$imapserver:$imapport/imap$imapssl$imapcertvalidate" . "/user=$username}"; - if (! array_key_exists ($this->mailbox, self::$instance)) + if (! array_key_exists($this->mailbox, self::$instance)) { + try { + // Timeout authentication error to 1s (can't be less). By default, IMAP + // wait 10s before returning an auth error + imap_timeout(IMAP_READTIMEOUT, 1); + self::$instance[$this->mailbox] = @imap_open( + $this->mailbox, + $username, + $password + ); + if (self::$instance[$this->mailbox] === false) { + throw new \Exception(imap_last_error()); + } + } catch (\Exception $e) { + // imap_errors() takes the errors and clear the error stack + $errors = imap_errors(); + if ( + substr($e->getMessage(), 0, 35) === + "Can not authenticate to IMAP server" + ) { + throw new \Exception("IMAP error : " . $e->getMessage(), 401); + } + throw new \Exception("IMAP error : " . $e->getMessage(), 500); + } + } + } + + /////////////////// + /// FOLDERS /// + /////////////////// + /** Return an array of the existing folders. The sub-folders are with slash + * separator + * The names of folders are converted in UTF-8 + */ + public function foldersList() { - try - { - // Timeout authentication error to 1s (can't be less). By default, IMAP - // wait 10s before returning an auth error - imap_timeout (IMAP_READTIMEOUT, 1); - self::$instance[$this->mailbox] = @imap_open ($this->mailbox, $username, - $password); - if (self::$instance[$this->mailbox] === FALSE) - throw new \Exception (imap_last_error()); - } - catch (\Exception $e) - { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $list = array_keys($this->foldersListWithAttr()); + sort($list); + return $list; + } + + /** Return an array with folder name in key and attributes in value. The + * attributes allow to see if there is new mails in folders + */ + public function foldersListWithAttr() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $list = imap_getmailboxes( + self::$instance[$this->mailbox], + $this->mailbox, + "*" + ); + $res = array(); + foreach ($list as $val) { + $dir = substr($val->name, strlen($this->mailbox)); + $dir = mb_convert_encoding($dir, "UTF8", "UTF7-IMAP"); + if (isset($val->delimiter)) { + $dir = str_replace($val->delimiter, "/", $dir); + } + $res[$dir] = $val->attributes; + } + return ($res); + } + + /** Change to provided folder + * The folder name must be in UTF-8. The folder must be absolute + * @param string $folder Change to the provided folder + */ + public function changeFolder($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + if (! in_array($folder, $this->foldersList())) { + throw new \Exception("Folder not found", 404); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + $rc = @imap_reopen( + self::$instance[$this->mailbox], + $this->mailbox . $folderUTF7 + ); + if ($rc === true) { + $this->curDir = $folder; + } else { + throw new \Exception("Can't go in provided folder", 500); + } + return $rc; + } + + /** Return the current folder in UTF-8 + */ + public function getFolder() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + return $this->curDir; + } + + /** Create a new folder, provided in UTF-8. The folder must be absolute + * @param string $folder Create the provided folder + */ + public function createFolder($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + if (in_array($folder, $this->foldersList())) { + throw new \Exception("Folder already exists", 406); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + return imap_createmailbox( + self::$instance[$this->mailbox], + $this->mailbox . $folderUTF7 + ); + } + + /** Delete an existing folder provided in UTF-8. The folder must be absolute + * @param string $folder The folder to delete + */ + public function deleteFolder($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + if (! in_array($folder, $this->foldersList())) { + throw new \Exception("Folder not found", 404); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + return imap_deletemailbox( + self::$instance[$this->mailbox], + $this->mailbox . $folderUTF7 + ); + } + + /** Return the list of the folders substcribed by the user. The folders are + * in UTF-8 + */ + public function getSubscribe() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $subs = imap_getsubscribed( + self::$instance[$this->mailbox], + $this->mailbox, + "*" + ); + $res = array(); + foreach ($subs as $sub) { + $res [] = str_replace( + $sub->delimiter, + "/", + substr($sub->name, strlen($this->mailbox)) + ); + } + $res = array_map(function ($folder) { + return mb_convert_encoding($folder, "UTF-8", "UTF7-IMAP"); + }, $res); + sort($res); + return $res; + } + + /** Add a subscription for a folder. The folder must be in UTF-8 + * @param string $folder Add the provided folder to the subscription file of + * the user + */ + public function addSubscribe($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + return imap_subscribe( + self::$instance[$this->mailbox], + $this->mailbox . $folder + ); + } + + /** Remove a subscription for a folder. The folder must be in UTF-8 + * @param string $folder Remove the provided folder to the subscription file + * of the user + */ + public function delSubscribe($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + return imap_unsubscribe( + self::$instance[$this->mailbox], + $this->mailbox . $folder + ); + } + + /** Return the information concerning a folder. It return an object with the + * following properties : + * Date date of last change (current datetime) + * Driver driver + * Mailbox name of the mailbox + * Nmsgs number of messages + * Recent number of recent messages + * Unread number of unread messages + * Deleted number of deleted messages + * Size mailbox size + * @param string $folder The folder to get the informations + */ + public function getFolderInfo($folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $oldFolder = $this->curDir; + $this->changeFolder($folder); + $rc = imap_mailboxmsginfo(self::$instance[$this->mailbox]); + $this->changeFolder($oldFolder); + if ($rc === false) { + throw new \Exception("Can't read information for folder $folder", 500); + } + return $rc; + } + + ////////////////////// + /// LIST MAILS /// + ////////////////////// + /** Return an array of mailHeaders order by $field and by order ASC or DESC + * @param array $mailHeaders The headers to sort + * @param string $field The field to examine + * @param boolean|null $orderAsc The order of sorting. Asc if not defined + */ + public function imapSortMail($mailHeaders, $field, $orderAsc = true) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + $sortList = array(); + $sortInc = array(); + foreach ($mailHeaders as $mail) { + // Permit to have to mails with the same comparator field. Add an + // increment at the end of field + if (!isset($sortInc[$mail->$field])) { + $inc = 1; + } else { + $inc = $sortInc[$mail->$field] + 1; + } + $sortInc[$mail->$field] = $inc; + $sortList[$mail->$field . $inc] = $mail; + } + ksort($sortList, SORT_NATURAL); + return array_values($sortList); + } + + /** Fetch the headers for all messages in the current folder sorted by date + * Return an array of mail object containing information like the subject, + * the date, if the message is already read (recent), answered... + * (see http://www.php.net/manual/en/function.imap-fetch-overview.php) + * If the $from is negative, take the LAST $from mails + * If from is zero, it's value is override to 1 + * For information, takes 0.4s to select 30 mails on 1552 + * @param integer|null $from The selector of the mails. 1 if not defined + * @param integer|null $nbmails The number of mails returned by the method + * 30 if not defined + **/ + public function mailsDate($from = 1, $nbmails = 30) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if ($from === null) { + $from = 1; + } + $MC = imap_check(self::$instance[$this->mailbox]); + if ($MC->Nmsgs === 0) { + return array(); + } + if ($nbmails > $MC->Nmsgs) { + $nbmails = $MC->Nmsgs; + } + if ($from < 0) { + $from = abs($from); + if ($from < 1) { + $from = 1; + } + if ($from > $MC->Nmsgs) { + throw new \Exception( + "Mail start is higher than the number of mails", + 500 + ); + } + $from = $MC->Nmsgs - $from + 1; + $to = $from + $nbmails - 1; + if ($to > $MC->Nmsgs) { + $to = $MC->Nmsgs; + } + } else { + if ($from > $MC->Nmsgs) { + throw new \Exception( + "Mail start is higher than the number of mails", + 500 + ); + } + if ($from < 1) { + $from = 1; + } + $to = $from + $nbmails - 1; + if ($to > $MC->Nmsgs) { + $to = $MC->Nmsgs; + } + } + $headers = array(); + // Adding the FT_UID options cost 1.1s + $result = imap_fetch_overview( + self::$instance[$this->mailbox], + "$from:$to", + 0 + ); // imap_errors() takes the errors and clear the error stack $errors = imap_errors(); - if (substr ($e->getMessage (), 0, 35) === - "Can not authenticate to IMAP server") - throw new \Exception ("IMAP error : ".$e->getMessage(), 401); - throw new \Exception ("IMAP error : ".$e->getMessage(), 500); - } + return $result; } - } - /////////////////// - /// FOLDERS /// - /////////////////// - /** Return an array of the existing folders. The sub-folders are with slash - * separator - * The names of folders are converted in UTF-8 - */ - public function foldersList () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $list = array_keys ($this->foldersListWithAttr ()); - sort ($list); - return $list; - } - - /** Return an array with folder name in key and attributes in value. The - * attributes allow to see if there is new mails in folders - */ - public function foldersListWithAttr () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $list = imap_getmailboxes (self::$instance[$this->mailbox], $this->mailbox, - "*"); - $res = array (); - foreach ($list as $val) + /** Return all the mails numbers order by thread in an array. + * [] => array ("msgno"=>msgno, "depth"=>depth) + */ + public function mailsThread() { - $dir = substr ($val->name, strlen ($this->mailbox)); - $dir = mb_convert_encoding ($dir, "UTF8", "UTF7-IMAP"); - if (isset ($val->delimiter)) - $dir = str_replace ($val->delimiter, "/", $dir); - $res[$dir] = $val->attributes; - } - return ($res); - } - - /** Change to provided folder - * The folder name must be in UTF-8. The folder must be absolute - * @param string $folder Change to the provided folder - */ - public function changeFolder ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - if (! in_array ($folder, $this->foldersList ())) - throw new \Exception ("Folder not found", 404); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - $rc = @imap_reopen (self::$instance[$this->mailbox], - $this->mailbox.$folderUTF7); - if ($rc === true) - $this->curDir = $folder; - else - throw new \Exception ("Can't go in provided folder", 500); - return $rc; - } - - /** Return the current folder in UTF-8 - */ - public function getFolder () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - return $this->curDir; - } - - /** Create a new folder, provided in UTF-8. The folder must be absolute - * @param string $folder Create the provided folder - */ - public function createFolder ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - if ( in_array ($folder, $this->foldersList ())) - throw new \Exception ("Folder already exists", 406); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - return imap_createmailbox (self::$instance[$this->mailbox], - $this->mailbox.$folderUTF7); - } - - /** Delete an existing folder provided in UTF-8. The folder must be absolute - * @param string $folder The folder to delete - */ - public function deleteFolder ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - if (! in_array ($folder, $this->foldersList ())) - throw new \Exception ("Folder not found", 404); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - return imap_deletemailbox (self::$instance[$this->mailbox], - $this->mailbox.$folderUTF7); - } - - /** Return the list of the folders substcribed by the user. The folders are - * in UTF-8 - */ - public function getSubscribe () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $subs = imap_getsubscribed (self::$instance[$this->mailbox], $this->mailbox, - "*"); - $res = array (); - foreach ($subs as $sub) - { - $res [] = str_replace ($sub->delimiter, "/", - substr ($sub->name, strlen ($this->mailbox))); - } - $res = array_map (function ($folder) { - return mb_convert_encoding ($folder, "UTF-8", "UTF7-IMAP"); - }, $res); - sort ($res); - return $res; - } - - /** Add a subscription for a folder. The folder must be in UTF-8 - * @param string $folder Add the provided folder to the subscription file of - * the user - */ - public function addSubscribe ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - return imap_subscribe (self::$instance[$this->mailbox], - $this->mailbox.$folder); - } - - /** Remove a subscription for a folder. The folder must be in UTF-8 - * @param string $folder Remove the provided folder to the subscription file - * of the user - */ - public function delSubscribe ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - return imap_unsubscribe (self::$instance[$this->mailbox], - $this->mailbox.$folder); - } - - /** Return the information concerning a folder. It return an object with the - * following properties : - * Date date of last change (current datetime) - * Driver driver - * Mailbox name of the mailbox - * Nmsgs number of messages - * Recent number of recent messages - * Unread number of unread messages - * Deleted number of deleted messages - * Size mailbox size - * @param string $folder The folder to get the informations - */ - public function getFolderInfo ($folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $oldFolder = $this->curDir; - $this->changeFolder ($folder); - $rc = imap_mailboxmsginfo (self::$instance[$this->mailbox]); - $this->changeFolder ($oldFolder); - if ($rc === false) - throw new \Exception ("Can't read information for folder $folder", 500); - return $rc; - } - - ////////////////////// - /// LIST MAILS /// - ////////////////////// - /** Return an array of mailHeaders order by $field and by order ASC or DESC - * @param array $mailHeaders The headers to sort - * @param string $field The field to examine - * @param boolean|null $orderAsc The order of sorting. Asc if not defined - */ - public function imapSortMail ($mailHeaders, $field, $orderAsc = TRUE) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - $sortList = array (); - $sortInc = array (); - foreach ($mailHeaders as $mail) - { - // Permit to have to mails with the same comparator field. Add an - // increment at the end of field - if (!isset ($sortInc[$mail->$field])) - $inc = 1; - else - $inc = $sortInc[$mail->$field] + 1; - $sortInc[$mail->$field] = $inc; - $sortList[$mail->$field.$inc] = $mail; - } - ksort ($sortList, SORT_NATURAL); - return array_values ($sortList); - } - - /** Fetch the headers for all messages in the current folder sorted by date - * Return an array of mail object containing information like the subject, - * the date, if the message is already read (recent), answered... - * (see http://www.php.net/manual/en/function.imap-fetch-overview.php) - * If the $from is negative, take the LAST $from mails - * If from is zero, it's value is override to 1 - * For information, takes 0.4s to select 30 mails on 1552 - * @param integer|null $from The selector of the mails. 1 if not defined - * @param integer|null $nbmails The number of mails returned by the method - * 30 if not defined - **/ - public function mailsDate ($from = 1, $nbmails = 30) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if ($from === null) - $from = 1; - $MC = imap_check (self::$instance[$this->mailbox]); - if ($MC->Nmsgs === 0) - return array (); - if ($nbmails > $MC->Nmsgs) - $nbmails = $MC->Nmsgs; - if ($from < 0) - { - $from = abs ($from); - if ($from < 1) - $from = 1; - if ($from > $MC->Nmsgs) - throw new \Exception ("Mail start is higher than the number of mails", - 500); - $from = $MC->Nmsgs - $from + 1; - $to = $from + $nbmails - 1; - if ($to > $MC->Nmsgs) - $to = $MC->Nmsgs; - } - else - { - if ($from > $MC->Nmsgs) - throw new \Exception ("Mail start is higher than the number of mails", - 500); - if ($from < 1) - $from = 1; - $to = $from + $nbmails - 1; - if ($to > $MC->Nmsgs) - $to = $MC->Nmsgs; - } - $headers = array (); - // Adding the FT_UID options cost 1.1s - $result = imap_fetch_overview (self::$instance[$this->mailbox], - "$from:$to", 0); - // imap_errors() takes the errors and clear the error stack - $errors = imap_errors(); - return $result; - } - - /** Return all the mails numbers order by thread in an array. - * [] => array ("msgno"=>msgno, "depth"=>depth) - */ - public function mailsThread () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - $threads = @imap_thread (self::$instance[$this->mailbox]); - // imap_errors() takes the errors and clear the error stack - $errors = imap_errors(); - $thread = array (); - $depth = 0; - foreach ($threads as $key => $val) - { - $tree = explode('.', $key); - if ($tree[1] == 'num') - { - // If the mail unknown (the mails starts at 1), skip the thread record - if ($val === 0) - continue; - $thread[] = array ("msgno"=>$val, "depth"=>$depth); - $depth++; - } - elseif ($tree[1] == 'branch' && $depth > 0) - { - $depth--; - } - } - return $thread; - } - - /** Send back the number of mails in the mailbox - */ - public function mailsNumber () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - $MC = imap_check (self::$instance[$this->mailbox]); - return $MC->Nmsgs; - } - - /** Return an array containing the msgno corresponding to the criteria - * @param string $criteria The criteria to use for the IMAP search - */ - public function mailsSearch ($criteria) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - return imap_search (self::$instance[$this->mailbox], $criteria); - } - - /** Move the mail provided in the $folder in UTF-8. - * If $msgno is an array, all the mails with the contain msgno are deleted - * Expunge automatically the current folder to remove the old emails - * @param integer|array $msgno The message number(s) to copy - * @param string $folder The destination folder of the move. Must exists - */ - public function mailMove ($msgno, $folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - $rc = imap_mail_move (self::$instance[$this->mailbox], $msgno, $folderUTF7); - if ($rc !== TRUE) - { - return FALSE; - } - if ($this->autoexpunge) - return imap_expunge (self::$instance[$this->mailbox]); - return true; - } - - /** Copy the mail provided in the $folder in UTF-8. - * If $msgno is an array, all the mails with the contain msgno are copied - * @param integer|array $msgno The message number(s) to copy - * @param string $folder The destination folder of the copy. Must exists - */ - public function mailCopy ($msgno, $folder) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $folderUTF7 = mb_convert_encoding ($folder, "UTF7-IMAP", "UTF-8"); - $rc = imap_mail_copy (self::$instance[$this->mailbox], $msgno, $folderUTF7); - if ($rc !== TRUE) - { - return FALSE; - } - return true; - } - - /** Expunge the mailbox. If the autoexpunge is activated, it is normally not - * needed - */ - public function expunge () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - return imap_expunge (self::$instance[$this->mailbox]); - } - - ///////////////////////////// - /// GET/SET/DEL EMAIL /// - ///////////////////////////// - /** Get an existing email in the current folder in raw format - * @param integer $msgno The message number to examine - */ - public function getEmailRaw ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - // Clear the errors - imap_errors(); - $content = @imap_fetchheader (self::$instance[$this->mailbox], $msgno). - "\r\n". - @imap_body (self::$instance[$this->mailbox], $msgno); - $errors = imap_errors (); - if ($errors !== false || $content === "\n") - throw new \Exception ("Mail not found", 404); - return $content; - } - - /** Get the headers of the email (in raw format) - * @param integer $msgno The message number to examine - */ - public function getEmailHeadersRaw ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - // Clear the errors - imap_errors(); - $content = @imap_fetchheader (self::$instance[$this->mailbox], $msgno); - $errors = imap_errors (); - if ($errors !== false || $content === "") - throw new \Exception ("Mail not found", 404); - return $content; - } - - /** Get all the body (and attached files) of an email in raw format - * @param integer $msgno The message number to examine - */ - public function getEmailBodyRaw ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - // Clear the errors - imap_errors(); - $content = @imap_body (self::$instance[$this->mailbox], $msgno); - $errors = imap_errors (); - if ($errors !== false) - throw new \Exception ("Mail not found", 404); - return $content; - } - - /** Return email structure of the body - * @param integer $msgno The message number to examine - */ - public function getStructure ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - // Clear the errors - imap_errors(); - $structure = @imap_fetchstructure (self::$instance[$this->mailbox], $msgno); - $errors = imap_errors (); - if ($errors !== false) - throw new \Exception ("Mail not found", 404); - return $structure; - } - - /** Return the structure of the mail body with the associated content - * @param integer $msgno The message number to examine - */ - public function getStructureWithContent ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - // Clear the errors - imap_errors(); - $structure = @imap_fetchstructure (self::$instance[$this->mailbox], $msgno); - $errors = imap_errors (); - if ($errors !== false) - throw new \Exception ("Mail not found", 404); - if (! isset ($structure->parts)) - { - // In case of PLAIN text, there is no parts - $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, 1); - if ($structure->encoding === 4) - $content = quoted_printable_decode ($content); - elseif ($structure->encoding === 3) - $content = base64_decode ($content); - foreach ($structure->parameters as $param) - { - if ($param->attribute === "charset") - $content = iconv ($param->value, "utf-8", $content); - } - $structure->content = $content; - return $structure; - } - foreach ($structure->parts as $part1=>$struct1) - { - if (isset ($struct1->parts)) - { - foreach ($struct1->parts as $part2=>$struct2) - { - $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, - ($part1+1).".".($part2+1)); - if ($struct2->encoding === 4) - $content = quoted_printable_decode ($content); - elseif ($struct2->encoding === 3) - $content = base64_decode ($content); - foreach ($struct2->parameters as $param) - { - if ($param->attribute === "charset") - $content = iconv ($param->value, "utf-8", $content); - } - $structure->parts[$part1]->parts[$part2]->content = $content; - // Add the MIME type - if ($struct2->type === 0) - $structure->parts[$part1]->parts[$part2]->mimetype = "text/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 1) - $structure->parts[$part1]->parts[$part2]->mimetype = "multipart/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 2) - $structure->parts[$part1]->parts[$part2]->mimetype = "message/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 3) - $structure->parts[$part1]->parts[$part2]->mimetype = "application/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 4) - $structure->parts[$part1]->parts[$part2]->mimetype = "audio/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 5) - $structure->parts[$part1]->parts[$part2]->mimetype = "image/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 6) - $structure->parts[$part1]->parts[$part2]->mimetype = "video/". - strtolower ($struct2->subtype); - elseif ($struct2->type === 7) - $structure->parts[$part1]->parts[$part2]->mimetype = "other/". - strtolower ($struct2->subtype); - else - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown type in imap_fetchstructure : %s"), - $struct2->type), 500); + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); } - } - else - { - $content = imap_fetchbody (self::$instance[$this->mailbox], $msgno, - $part1+1); - if ($struct1->encoding === 4) - $content = quoted_printable_decode ($content); - elseif ($struct1->encoding === 3) - $content = base64_decode ($content); - foreach ($struct1->parameters as $param) - { - if ($param->attribute === "charset") - $content = iconv ($param->value, "utf-8", $content); + $this->changeFolder($this->curDir); + $threads = @imap_thread(self::$instance[$this->mailbox]); + // imap_errors() takes the errors and clear the error stack + $errors = imap_errors(); + $thread = array(); + $depth = 0; + foreach ($threads as $key => $val) { + $tree = explode('.', $key); + if ($tree[1] == 'num') { + // If the mail unknown (the mails starts at 1), skip the thread record + if ($val === 0) { + continue; + } + $thread[] = array("msgno" => $val, "depth" => $depth); + $depth++; + } elseif ($tree[1] == 'branch' && $depth > 0) { + $depth--; + } } - $structure->parts[$part1]->content = $content; - // Add the MIME type - if ($struct1->type === 0) - $structure->parts[$part1]->mimetype = "text/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 1) - $structure->parts[$part1]->mimetype = "multipart/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 2) - $structure->parts[$part1]->mimetype = "message/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 3) - $structure->parts[$part1]->mimetype = "application/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 4) - $structure->parts[$part1]->mimetype = "audio/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 5) - $structure->parts[$part1]->mimetype = "image/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 6) - $structure->parts[$part1]->mimetype = "video/". - strtolower ($struct1->subtype); - elseif ($struct1->type === 7) - $structure->parts[$part1]->mimetype = "other/". - strtolower ($struct1->subtype); - else - throw new \Exception (sprintf ( - dgettext ("domframework", - "Unknown type in imap_fetchstructure : %s"), - $struct1->type), 500); - } + return $thread; } - return $structure; - } - /** Return the content of a part of the mail body defined in the structure in - * an object, with the associated mimetype, the parameters like the charset - * if they are defined, the number of lines associated to this part in the - * mail and some other info - * @param integer $msgno The message number to examine - * @param integer $part The message part to get - */ - public function getStructureContent ($msgno, $part) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $structure = $this->getStructureWithContent ($msgno); - if (isset ($structure->parts[$part])) - return $structure->parts[$part]; - throw new \Exception ("Part not found in the mail", 404); - } + /** Send back the number of mails in the mailbox + */ + public function mailsNumber() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + $MC = imap_check(self::$instance[$this->mailbox]); + return $MC->Nmsgs; + } - /** Return the part identifiers of the structure of the mail body. To be used - * in getStructureContent - * @param integer $msgno The message number to examine - */ - public function getStructureParts ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $structure = $this->getStructure ($msgno); - if (! isset ($structure->parts)) - return array (); - return array_keys ($structure->parts); - } + /** Return an array containing the msgno corresponding to the criteria + * @param string $criteria The criteria to use for the IMAP search + */ + public function mailsSearch($criteria) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + return imap_search(self::$instance[$this->mailbox], $criteria); + } - /** Delete all the mailIDs (msgno) provided in an array or a single mail if - * $msgno is not an array - * DO NOT MOVE THE MAIL IN TRASH, DESTROY THE MAIL REALLY - * Expunge the mails at the end of the operation - * @param array|integer $msgno The message number(s) to remove - */ - public function mailsDel ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $rc = @imap_delete (self::$instance[$this->mailbox], $msgno); - imap_errors(); - if ($rc === FALSE) - throw new \Exception ("No mailID provided can be found : ABORT"); - if ($this->autoexpunge) - return imap_expunge(self::$instance[$this->mailbox]); - return $rc; - } + /** Move the mail provided in the $folder in UTF-8. + * If $msgno is an array, all the mails with the contain msgno are deleted + * Expunge automatically the current folder to remove the old emails + * @param integer|array $msgno The message number(s) to copy + * @param string $folder The destination folder of the move. Must exists + */ + public function mailMove($msgno, $folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + $rc = imap_mail_move(self::$instance[$this->mailbox], $msgno, $folderUTF7); + if ($rc !== true) { + return false; + } + if ($this->autoexpunge) { + return imap_expunge(self::$instance[$this->mailbox]); + } + return true; + } - /** Add a new mail in the current folder. The content must be a string - * containing all the mail (header and body). If the content is invalid, the - * directory listing can provide erroneous data - * @param string $content the content of the mail to add - */ - public function mailAdd ($content) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $folderUTF7 = mb_convert_encoding ($this->curDir, "UTF7-IMAP", "UTF-8"); - $rc = imap_append (self::$instance[$this->mailbox], - $this->mailbox.$folderUTF7, - $content); - $errors = imap_errors(); - if ($rc === FALSE) - throw new \Exception ("Error when saving the mail in folder : ". - implode (" ", $errors), 500); - return true; - } + /** Copy the mail provided in the $folder in UTF-8. + * If $msgno is an array, all the mails with the contain msgno are copied + * @param integer|array $msgno The message number(s) to copy + * @param string $folder The destination folder of the copy. Must exists + */ + public function mailCopy($msgno, $folder) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $folderUTF7 = mb_convert_encoding($folder, "UTF7-IMAP", "UTF-8"); + $rc = imap_mail_copy(self::$instance[$this->mailbox], $msgno, $folderUTF7); + if ($rc !== true) { + return false; + } + return true; + } - ///////////////// - /// QUOTA /// - ///////////////// - /** Return the quota used by the user in Mo - */ - public function getQuota () - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $quota = @imap_get_quotaroot (self::$instance[$this->mailbox], "INBOX"); - imap_errors(); - if (! isset ($quota["STORAGE"])) - return array (); + /** Expunge the mailbox. If the autoexpunge is activated, it is normally not + * needed + */ + public function expunge() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + return imap_expunge(self::$instance[$this->mailbox]); + } - return array_map (function ($n) {return intval ($n/1000);}, - $quota["STORAGE"]); - } + ///////////////////////////// + /// GET/SET/DEL EMAIL /// + ///////////////////////////// + /** Get an existing email in the current folder in raw format + * @param integer $msgno The message number to examine + */ + public function getEmailRaw($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + // Clear the errors + imap_errors(); + $content = @imap_fetchheader(self::$instance[$this->mailbox], $msgno) . + "\r\n" . + @imap_body(self::$instance[$this->mailbox], $msgno); + $errors = imap_errors(); + if ($errors !== false || $content === "\n") { + throw new \Exception("Mail not found", 404); + } + return $content; + } - ///////////////// - /// FLAGS /// - ///////////////// - /** Set the flags of the msgno. If msgno is an array, the flags will be write - * on the list of mails. The others flags of the email are not modified. - * The flags must be an array containing : - * \Seen Message has been read - * \Answered Message has been answered - * \Flagged Message is "flagged" for urgent/special attention - * \Deleted Message is "deleted" for removal by later EXPUNGE - * \Draft Message has not completed composition (marked as a draft). - * @param integer|array $msgno The messages number(s) to add the flags - * @param array $flags The flags to add - */ - public function setFlag ($msgno, $flags) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $rc = @imap_setflag_full (self::$instance[$this->mailbox], $msgno, - implode (" ", $flags)); - imap_errors(); - if ($rc === FALSE) - throw new \Exception ("Can't define the flags", 500); - return true; - } + /** Get the headers of the email (in raw format) + * @param integer $msgno The message number to examine + */ + public function getEmailHeadersRaw($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + // Clear the errors + imap_errors(); + $content = @imap_fetchheader(self::$instance[$this->mailbox], $msgno); + $errors = imap_errors(); + if ($errors !== false || $content === "") { + throw new \Exception("Mail not found", 404); + } + return $content; + } - /** Unset the flags of the msgno. If msgno is an array, the flags will be - * write on the list of mails. The others flags of the email are not - * modified. - * The flags must be an array containing : - * \Seen Message has been read - * \Answered Message has been answered - * \Flagged Message is "flagged" for urgent/special attention - * \Deleted Message is "deleted" for removal by later EXPUNGE - * \Draft Message has not completed composition (marked as a draft). - * @param integer|array $msgno The messages number(s) to remove the flags - * @param array $flags The flags to remove - */ - public function unsetFlag ($msgno, $flags) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $rc = @imap_clearflag_full (self::$instance[$this->mailbox], $msgno, - implode (" ", $flags)); - imap_errors(); - if ($rc === FALSE) - throw new \Exception ("Can't define the flags", 500); - return true; - } + /** Get all the body (and attached files) of an email in raw format + * @param integer $msgno The message number to examine + */ + public function getEmailBodyRaw($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + // Clear the errors + imap_errors(); + $content = @imap_body(self::$instance[$this->mailbox], $msgno); + $errors = imap_errors(); + if ($errors !== false) { + throw new \Exception("Mail not found", 404); + } + return $content; + } - /** Mark mail(s) as read. - * If msgno is an array, a list of mails will be modified. - * If msgno is an integer, only one mail will be modified - * @param integer|array $msgno The messages number(s) to mark as read - */ - public function markMailAsRead ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $rc = @imap_setflag_full (self::$instance[$this->mailbox], $msgno, - "\\Seen"); - imap_errors(); - if ($rc === FALSE) - throw new \Exception ("Can't mark mail as read", 500); - return true; - } + /** Return email structure of the body + * @param integer $msgno The message number to examine + */ + public function getStructure($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + // Clear the errors + imap_errors(); + $structure = @imap_fetchstructure(self::$instance[$this->mailbox], $msgno); + $errors = imap_errors(); + if ($errors !== false) { + throw new \Exception("Mail not found", 404); + } + return $structure; + } - /** Mark mail(s) as unread. - * If msgno is an array, a list of mails will be modified. - * If msgno is an integer, only one mail will be modified - * @param integer|array $msgno The messages number(s) to mark as unread - */ - public function markMailAsUnread ($msgno) - { - if ($this->mailbox === null) - throw new \Exception ("IMAP server not connected", 500); - $this->changeFolder ($this->curDir); - if (is_array ($msgno)) - $msgno = implode (",", $msgno); - $rc = @imap_clearflag_full (self::$instance[$this->mailbox], $msgno, - "\\Seen"); - imap_errors(); - if ($rc === FALSE) - throw new \Exception ("Can't mark mail as read", 500); - return true; - } + /** Return the structure of the mail body with the associated content + * @param integer $msgno The message number to examine + */ + public function getStructureWithContent($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + // Clear the errors + imap_errors(); + $structure = @imap_fetchstructure(self::$instance[$this->mailbox], $msgno); + $errors = imap_errors(); + if ($errors !== false) { + throw new \Exception("Mail not found", 404); + } + if (! isset($structure->parts)) { + // In case of PLAIN text, there is no parts + $content = imap_fetchbody(self::$instance[$this->mailbox], $msgno, 1); + if ($structure->encoding === 4) { + $content = quoted_printable_decode($content); + } elseif ($structure->encoding === 3) { + $content = base64_decode($content); + } + foreach ($structure->parameters as $param) { + if ($param->attribute === "charset") { + $content = iconv($param->value, "utf-8", $content); + } + } + $structure->content = $content; + return $structure; + } + foreach ($structure->parts as $part1 => $struct1) { + if (isset($struct1->parts)) { + foreach ($struct1->parts as $part2 => $struct2) { + $content = imap_fetchbody( + self::$instance[$this->mailbox], + $msgno, + ($part1 + 1) . "." . ($part2 + 1) + ); + if ($struct2->encoding === 4) { + $content = quoted_printable_decode($content); + } elseif ($struct2->encoding === 3) { + $content = base64_decode($content); + } + foreach ($struct2->parameters as $param) { + if ($param->attribute === "charset") { + $content = iconv($param->value, "utf-8", $content); + } + } + $structure->parts[$part1]->parts[$part2]->content = $content; + // Add the MIME type + if ($struct2->type === 0) { + $structure->parts[$part1]->parts[$part2]->mimetype = "text/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 1) { + $structure->parts[$part1]->parts[$part2]->mimetype = "multipart/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 2) { + $structure->parts[$part1]->parts[$part2]->mimetype = "message/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 3) { + $structure->parts[$part1]->parts[$part2]->mimetype = "application/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 4) { + $structure->parts[$part1]->parts[$part2]->mimetype = "audio/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 5) { + $structure->parts[$part1]->parts[$part2]->mimetype = "image/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 6) { + $structure->parts[$part1]->parts[$part2]->mimetype = "video/" . + strtolower($struct2->subtype); + } elseif ($struct2->type === 7) { + $structure->parts[$part1]->parts[$part2]->mimetype = "other/" . + strtolower($struct2->subtype); + } else { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown type in imap_fetchstructure : %s" + ), + $struct2->type + ), 500); + } + } + } else { + $content = imap_fetchbody( + self::$instance[$this->mailbox], + $msgno, + $part1 + 1 + ); + if ($struct1->encoding === 4) { + $content = quoted_printable_decode($content); + } elseif ($struct1->encoding === 3) { + $content = base64_decode($content); + } + foreach ($struct1->parameters as $param) { + if ($param->attribute === "charset") { + $content = iconv($param->value, "utf-8", $content); + } + } + $structure->parts[$part1]->content = $content; + // Add the MIME type + if ($struct1->type === 0) { + $structure->parts[$part1]->mimetype = "text/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 1) { + $structure->parts[$part1]->mimetype = "multipart/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 2) { + $structure->parts[$part1]->mimetype = "message/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 3) { + $structure->parts[$part1]->mimetype = "application/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 4) { + $structure->parts[$part1]->mimetype = "audio/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 5) { + $structure->parts[$part1]->mimetype = "image/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 6) { + $structure->parts[$part1]->mimetype = "video/" . + strtolower($struct1->subtype); + } elseif ($struct1->type === 7) { + $structure->parts[$part1]->mimetype = "other/" . + strtolower($struct1->subtype); + } else { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Unknown type in imap_fetchstructure : %s" + ), + $struct1->type + ), 500); + } + } + } + return $structure; + } + + /** Return the content of a part of the mail body defined in the structure in + * an object, with the associated mimetype, the parameters like the charset + * if they are defined, the number of lines associated to this part in the + * mail and some other info + * @param integer $msgno The message number to examine + * @param integer $part The message part to get + */ + public function getStructureContent($msgno, $part) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $structure = $this->getStructureWithContent($msgno); + if (isset($structure->parts[$part])) { + return $structure->parts[$part]; + } + throw new \Exception("Part not found in the mail", 404); + } + + /** Return the part identifiers of the structure of the mail body. To be used + * in getStructureContent + * @param integer $msgno The message number to examine + */ + public function getStructureParts($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $structure = $this->getStructure($msgno); + if (! isset($structure->parts)) { + return array(); + } + return array_keys($structure->parts); + } + + /** Delete all the mailIDs (msgno) provided in an array or a single mail if + * $msgno is not an array + * DO NOT MOVE THE MAIL IN TRASH, DESTROY THE MAIL REALLY + * Expunge the mails at the end of the operation + * @param array|integer $msgno The message number(s) to remove + */ + public function mailsDel($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $rc = @imap_delete(self::$instance[$this->mailbox], $msgno); + imap_errors(); + if ($rc === false) { + throw new \Exception("No mailID provided can be found : ABORT"); + } + if ($this->autoexpunge) { + return imap_expunge(self::$instance[$this->mailbox]); + } + return $rc; + } + + /** Add a new mail in the current folder. The content must be a string + * containing all the mail (header and body). If the content is invalid, the + * directory listing can provide erroneous data + * @param string $content the content of the mail to add + */ + public function mailAdd($content) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $folderUTF7 = mb_convert_encoding($this->curDir, "UTF7-IMAP", "UTF-8"); + $rc = imap_append( + self::$instance[$this->mailbox], + $this->mailbox . $folderUTF7, + $content + ); + $errors = imap_errors(); + if ($rc === false) { + throw new \Exception("Error when saving the mail in folder : " . + implode(" ", $errors), 500); + } + return true; + } + + ///////////////// + /// QUOTA /// + ///////////////// + /** Return the quota used by the user in Mo + */ + public function getQuota() + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $quota = @imap_get_quotaroot(self::$instance[$this->mailbox], "INBOX"); + imap_errors(); + if (! isset($quota["STORAGE"])) { + return array(); + } + + return array_map( + function ($n) { + return intval($n / 1000); + }, + $quota["STORAGE"] + ); + } + + ///////////////// + /// FLAGS /// + ///////////////// + /** Set the flags of the msgno. If msgno is an array, the flags will be write + * on the list of mails. The others flags of the email are not modified. + * The flags must be an array containing : + * \Seen Message has been read + * \Answered Message has been answered + * \Flagged Message is "flagged" for urgent/special attention + * \Deleted Message is "deleted" for removal by later EXPUNGE + * \Draft Message has not completed composition (marked as a draft). + * @param integer|array $msgno The messages number(s) to add the flags + * @param array $flags The flags to add + */ + public function setFlag($msgno, $flags) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $rc = @imap_setflag_full( + self::$instance[$this->mailbox], + $msgno, + implode(" ", $flags) + ); + imap_errors(); + if ($rc === false) { + throw new \Exception("Can't define the flags", 500); + } + return true; + } + + /** Unset the flags of the msgno. If msgno is an array, the flags will be + * write on the list of mails. The others flags of the email are not + * modified. + * The flags must be an array containing : + * \Seen Message has been read + * \Answered Message has been answered + * \Flagged Message is "flagged" for urgent/special attention + * \Deleted Message is "deleted" for removal by later EXPUNGE + * \Draft Message has not completed composition (marked as a draft). + * @param integer|array $msgno The messages number(s) to remove the flags + * @param array $flags The flags to remove + */ + public function unsetFlag($msgno, $flags) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $rc = @imap_clearflag_full( + self::$instance[$this->mailbox], + $msgno, + implode(" ", $flags) + ); + imap_errors(); + if ($rc === false) { + throw new \Exception("Can't define the flags", 500); + } + return true; + } + + /** Mark mail(s) as read. + * If msgno is an array, a list of mails will be modified. + * If msgno is an integer, only one mail will be modified + * @param integer|array $msgno The messages number(s) to mark as read + */ + public function markMailAsRead($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $rc = @imap_setflag_full( + self::$instance[$this->mailbox], + $msgno, + "\\Seen" + ); + imap_errors(); + if ($rc === false) { + throw new \Exception("Can't mark mail as read", 500); + } + return true; + } + + /** Mark mail(s) as unread. + * If msgno is an array, a list of mails will be modified. + * If msgno is an integer, only one mail will be modified + * @param integer|array $msgno The messages number(s) to mark as unread + */ + public function markMailAsUnread($msgno) + { + if ($this->mailbox === null) { + throw new \Exception("IMAP server not connected", 500); + } + $this->changeFolder($this->curDir); + if (is_array($msgno)) { + $msgno = implode(",", $msgno); + } + $rc = @imap_clearflag_full( + self::$instance[$this->mailbox], + $msgno, + "\\Seen" + ); + imap_errors(); + if ($rc === false) { + throw new \Exception("Can't mark mail as read", 500); + } + return true; + } } diff --git a/src/Inifile.php b/src/Inifile.php index 3a74f3a..2d7b9d2 100644 --- a/src/Inifile.php +++ b/src/Inifile.php @@ -1,4 +1,5 @@ @@ -11,162 +12,184 @@ namespace Domframework; Support the sections (or not) */ class Inifile { - /** Return an array with the .ini file content - * If the sections are true, the sections are analyzed too - * This function is the same as parse_ini_file PHP internal - * @param string $file The ini file to read - * @param boolean|null $sections Manage the sections if true. False by - * default - */ - public function getFile ($file, $sections=false) - { - if (! file_exists ($file)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' not found"), $file), 404); - if (! is_readable ($file)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' not readable"), $file), 500); - return $this->getString (file_get_contents ($file, $sections)); - } - - /** Return an array with the .ini string content - * If the sections are true, the sections are analyzed too - * This function is the same as parse_ini_string PHP internal - * @param string $string The ini string to read - * @param boolean|null $sections Manage the sections if true. False by - * default - */ - public function getString ($string, $sections=false) - { - $res = parse_ini_string ($string, $sections); - // The DomFramework is PHP 5.3 compatible. I need to overwrite the bools and - // null values. The INI_SCANNER_TYPED is available as PHP 5.6.1 - foreach ($res as $key=>$val) + /** Return an array with the .ini file content + * If the sections are true, the sections are analyzed too + * This function is the same as parse_ini_file PHP internal + * @param string $file The ini file to read + * @param boolean|null $sections Manage the sections if true. False by + * default + */ + public function getFile($file, $sections = false) { - if ($val === "null") - $res[$key] = null; - elseif ($val === "true") - $res[$key] = true; - elseif ($val === "false") - $res[$key] = false; - elseif (is_array ($val)) - { - foreach ($val as $k=>$v) - { - if ($v === "null") - $res[$key][$k] = null; - elseif ($v === "true") - $res[$key][$k] = true; - elseif ($v === "false") - $res[$key][$k] = false; - elseif (is_numeric ($v)) - $res[$key][$k] = $v + 0; + if (! file_exists($file)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "File '%s' not found" + ), $file), 404); } - } - elseif (is_numeric ($val)) - $res[$key] = $val + 0; + if (! is_readable($file)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "File '%s' not readable" + ), $file), 500); + } + return $this->getString(file_get_contents($file, $sections)); } - return $res; - } - /** Return a string containing a .ini content from the provided array. - * If the sections are true, define the first child of the array as sections - * @param array $array The array read from a .ini file - * @param boolean|null $sections Manage the sections if true. False by - * default - */ - public function setString ($array, $sections=false) - { - if (! is_array ($array)) - throw new \Exception ( - dgettext ("domframework", - "inifile::setString : provided data is not an array"), - 500); - $content = ""; - if ($sections !== false) + /** Return an array with the .ini string content + * If the sections are true, the sections are analyzed too + * This function is the same as parse_ini_string PHP internal + * @param string $string The ini string to read + * @param boolean|null $sections Manage the sections if true. False by + * default + */ + public function getString($string, $sections = false) { - foreach ($array as $section=>$sub) - { - if (! is_array ($sub)) - throw new \Exception ( - dgettext ("domframework", - "inifile::setString : provided data is not an array"), - 500); - $content .= "[$section]\n"; - foreach ($sub as $key=>$val) - { - if (is_array ($val)) - { - foreach ($val as $k=>$v) - { - if (!is_scalar ($v) && ! is_null ($v)) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Provided value for '%s' is not scalar"), - $key), 500); - if ($v === null) $v = "null"; - $content .= $key."[$k] = \"$v\"\n"; + $res = parse_ini_string($string, $sections); + // The DomFramework is PHP 5.3 compatible. I need to overwrite the bools and + // null values. The INI_SCANNER_TYPED is available as PHP 5.6.1 + foreach ($res as $key => $val) { + if ($val === "null") { + $res[$key] = null; + } elseif ($val === "true") { + $res[$key] = true; + } elseif ($val === "false") { + $res[$key] = false; + } elseif (is_array($val)) { + foreach ($val as $k => $v) { + if ($v === "null") { + $res[$key][$k] = null; + } elseif ($v === "true") { + $res[$key][$k] = true; + } elseif ($v === "false") { + $res[$key][$k] = false; + } elseif (is_numeric($v)) { + $res[$key][$k] = $v + 0; + } + } + } elseif (is_numeric($val)) { + $res[$key] = $val + 0; } - } - else - { - if ($val === null) $val = "null"; - $content .= "$key = \"$val\"\n"; - } } - $content .= "\n"; - } + return $res; } - else + + /** Return a string containing a .ini content from the provided array. + * If the sections are true, define the first child of the array as sections + * @param array $array The array read from a .ini file + * @param boolean|null $sections Manage the sections if true. False by + * default + */ + public function setString($array, $sections = false) { - foreach ($array as $key=>$val) - { - if (is_array ($val)) - { - foreach ($val as $k=>$v) - { - if (!is_scalar ($v) && ! is_null ($v)) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Provided value for '%s' is not scalar"), - $key), 500); - if ($v === null) $v = "null"; - $content .= $key."[$k] = \"$v\"\n"; - } + if (! is_array($array)) { + throw new \Exception( + dgettext( + "domframework", + "inifile::setString : provided data is not an array" + ), + 500 + ); } - else - { - if ($val === null) $val = "null"; - $content .= "$key = \"$val\"\n"; + $content = ""; + if ($sections !== false) { + foreach ($array as $section => $sub) { + if (! is_array($sub)) { + throw new \Exception( + dgettext( + "domframework", + "inifile::setString : provided data is not an array" + ), + 500 + ); + } + $content .= "[$section]\n"; + foreach ($sub as $key => $val) { + if (is_array($val)) { + foreach ($val as $k => $v) { + if (!is_scalar($v) && ! is_null($v)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Provided value for '%s' is not scalar" + ), + $key + ), 500); + } + if ($v === null) { + $v = "null"; + } + $content .= $key . "[$k] = \"$v\"\n"; + } + } else { + if ($val === null) { + $val = "null"; + } + $content .= "$key = \"$val\"\n"; + } + } + $content .= "\n"; + } + } else { + foreach ($array as $key => $val) { + if (is_array($val)) { + foreach ($val as $k => $v) { + if (!is_scalar($v) && ! is_null($v)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Provided value for '%s' is not scalar" + ), + $key + ), 500); + } + if ($v === null) { + $v = "null"; + } + $content .= $key . "[$k] = \"$v\"\n"; + } + } else { + if ($val === null) { + $val = "null"; + } + $content .= "$key = \"$val\"\n"; + } + } + $content .= "\n"; } - } - $content .= "\n"; - + return $content; } - return $content; - } - /** Save a file containing a .ini content from the provided array. - * Don't create the directory if it doesn't exists - * If the sections are true, define the first child of the array as sections - * @param string $file The .ini file to store - * @param array $array The array to store in file - * @param boolean|null $sections Manage the sections if true. False by - * default - */ - public function setFile ($file, $array, $sections=false) - { - $dir = basename ($file); - if (! file_exists ($dir) || ! is_readable ($dir) || ! is_writeable ($dir)) - throw new \Exception (sprintf ( - dgettext ("domframework", - "Directory '%s' available or not readable or not writeable"), - $dir), 500); - if (file_exists ($file) && ! is_writeable ($file)) - throw new \Exception (sprintf (dgettext ("domframework", - "File '%s' is not writeable"), $file), - 500); - $content = $this->setString ($array, $sections); - return file_put_contents ($file, $content); - } + /** Save a file containing a .ini content from the provided array. + * Don't create the directory if it doesn't exists + * If the sections are true, define the first child of the array as sections + * @param string $file The .ini file to store + * @param array $array The array to store in file + * @param boolean|null $sections Manage the sections if true. False by + * default + */ + public function setFile($file, $array, $sections = false) + { + $dir = basename($file); + if (! file_exists($dir) || ! is_readable($dir) || ! is_writeable($dir)) { + throw new \Exception(sprintf( + dgettext( + "domframework", + "Directory '%s' available or not readable or not writeable" + ), + $dir + ), 500); + } + if (file_exists($file) && ! is_writeable($file)) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "File '%s' is not writeable" + ), $file), + 500 + ); + } + $content = $this->setString($array, $sections); + return file_put_contents($file, $content); + } } diff --git a/src/Ipaddresses.php b/src/Ipaddresses.php index 84fef23..270462f 100644 --- a/src/Ipaddresses.php +++ b/src/Ipaddresses.php @@ -1,4 +1,5 @@ @@ -10,665 +11,714 @@ namespace Domframework; /** Manage the IP addresses conversions */ class Ipaddresses { - /** Return true if the provided IP address is valid (IPv4 or IPv6) - * @param string $ip The IP Address to validate - */ - public function validIPAddress ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - $rc = $this->validIPv4Address ($ip); - if ($rc === TRUE) - return TRUE; - $rc = $this->validIPv6Address ($ip); - return $rc; - } - - /** Return true if the provided IP address is valid and is IPv4 - * @param string $ip The IP Address to validate - */ - public function validIPv4Address ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IPv4 address"), - 500); - $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); - if ($rc ===FALSE) - return FALSE; - return TRUE; - } - - /** Return true if the provided IP address is valid and is IPv6 - * @param string $ip The IP Address to validate - */ - public function validIPv6Address ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IPv6 address"), - 500); - $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); - if ($rc ===FALSE) - return FALSE; - return TRUE; - } - - /** Return true if the provided IP address is valid (IPv4 or IPv6) and the - * provided CIDR is valid too - * @param string $ip The IP Address to validate with a CIDR - */ - public function validIPAddressWithCIDR ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - $rc = $this->validIPv4AddressWithCIDR ($ip); - if ($rc === true) - return true; - $rc = $this->validIPv6AddressWithCIDR ($ip); - return $rc; - } - - /** Return true if the provided IP address is valid and is IPv4 and the - * provided CIDR is valid too - * @param string $ip The IP Address to validate with a CIDR - */ - public function validIPv4AddressWithCIDR ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IPv4 address"), - 500); - @list ($ip, $cidr) = @explode ("/", $ip); - if ($cidr === null) - return false; - $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); - if ($rc === false) - return false; - if ($this->validIPv4CIDR ($cidr) === false) - return false; - return true; - } - - /** Return true if the provided IP address is valid and is IPv6 and the - * provided CIDR is valid too - * @param string $ip The IP Address to validate with a CIDR - */ - public function validIPv6AddressWithCIDR ($ip) - { - if (!is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IPv6 address"), - 500); - @list ($ip, $cidr) = @explode ("/", $ip); - if ($cidr === null) - return false; - $rc = filter_var ($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); - if ($rc === false) - return false; - if ($this->validIPv6CIDR ($cidr) === false) - return false; - return true; - } - - /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4 - * or IPv6 - * @param integer $cidr The CIDR to test - * @return boolean The CIDR is valid - */ - public function validCIDR ($cidr) - { - if (! is_integer ($cidr) && ! is_integer ($cidr)) - throw new \Exception (dgettext ("domframework", "Invalid CIDR provided"), - 500); - if (strspn ($cidr, "0123456879") !== strlen ($cidr)) - return false; - if ($cidr < 0 || $cidr > 128) - return false; - return true; - } - - /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4. - * @param integer $cidr The CIDR to test - * @return boolean The CIDR is valid - */ - public function validIPv4CIDR ($cidr) - { - if (! is_integer ($cidr) && ! is_string ($cidr)) - throw new \Exception (dgettext ("domframework", "Invalid CIDR provided"), - 500); - if (strspn ($cidr, "0123456879") !== strlen ($cidr)) - return false; - if ($cidr < 0 || $cidr > 32) - return false; - return true; - } - - /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv6. - * @param integer $cidr The CIDR to test - * @return boolean The CIDR is valid - */ - public function validIPv6CIDR ($cidr) - { - if (! is_integer ($cidr) && ! is_string ($cidr)) - throw new \Exception (dgettext ("domframework", "Invalid CIDR provided"), - 500); - if (strspn ($cidr, "0123456879") !== strlen ($cidr)) - return false; - if ($cidr < 0 || $cidr > 128) - return false; - return true; - } - - /** Return the IPv6 to compressed (or compact) form. - * Remove the 0 when they are placed on the begin of the nibble. - * Remove all the blocks only zero to convert them to :: (but only one time) - * Example: 2001:0660:530d:0201:0000:0000:0000:0124 => 2001:660:530d:201::124 - * If an IPv4 is provided, return it without modification - * @param string $ip The IP to compress - */ - public function compressIP ($ip) - { - if (strpos ($ip, ":") === false) - return $ip; - $ip = $this->uncompressIPv6 ($ip); - $ipArr = explode (":", $ip); - if (count ($ipArr) !== 8) - return $ip; - // Remove the 0 if they are at the beginning of the nibble - foreach ($ipArr as &$ip) + /** Return true if the provided IP address is valid (IPv4 or IPv6) + * @param string $ip The IP Address to validate + */ + public function validIPAddress($ip) { - $ip = sprintf ("%x", hexdec ($ip)); - } - // Remove the 0 nibble if there is an other 0 nibble after - $cleanLoop = false; - $ipCompArr = array (); - foreach ($ipArr as $key=>$val) - { - // echo "VAL=".var_export ($val, true). - // ", cleanLoop=".var_export ($cleanLoop, true); - if ($val !== "0") - { - // echo " => In NOT zero\n"; - if ($cleanLoop) - $cleanLoop = false; - } - elseif($cleanLoop) - { - // echo " => In CleanLoop\n"; - unset ($ipArr[$key]); - } - else - { - // echo " => In ZERO\n"; - if (key_exists ($key+1, $ipArr) && $ipArr[$key+1] === "0") - { - // echo " ===> NEXT ZERO : CleanLoop Start\n"; - $cleanLoop = true; - $ipArr[$key] = ""; + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); } - } - } - $ipArr = array_values ($ipArr); - if (end ($ipArr) === "") - { - array_pop ($ipArr); - $ipArr[] = ":"; - } - if (reset ($ipArr) === "") - $ipArr[0] = ":"; - if (count ($ipArr) === 1) - $ipArr[] = ""; - $ipHex = implode (":", $ipArr); - return $ipHex; - } - - /** Return the IPv6 uncompressed (all the fields exists). They are not filled - * by zeros - * If the provided IP is IPv4, there is no change applied - * Return False if the parameter is invalid - * Based on http://www.weberdev.com/get_example.php3?ExampleID=3921 - * @param string $ip The IP address to uncompress - * Example : $ip="::" => return "0:0:0:0:0:0:0:0" - * Example : $ip = "::ffff:127.0.0.1", - * return "0:0:0:0:0:0:ffff:7f00:1" - */ - public function uncompressIPv6 ($ip) - { - if (! is_string ($ip) || $ip === "" || - $this->validIPAddress ($ip) === false) - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - if (strstr ($ip, "::")) - { - $e = explode (":", $ip); - // Case where :: is in start - if ($e[0] === "") - $e[0] = "0"; - // Case where :: is in end - if ($e[count ($e)-1] === "") - $e[count ($e)-1] = "0"; - $s = 8 - count ($e); - foreach ($e as $key=>$val) - { - if ($val === "") - { - for ($i=0 ; $i<=$s ; $i++) - $newipv6[] = 0; + $rc = $this->validIPv4Address($ip); + if ($rc === true) { + return true; } - else - { - $newipv6[] = $val; + $rc = $this->validIPv6Address($ip); + return $rc; + } + + /** Return true if the provided IP address is valid and is IPv4 + * @param string $ip The IP Address to validate + */ + public function validIPv4Address($ip) + { + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IPv4 address"), + 500 + ); } - } - $ip = implode (":", $newipv6); - if (substr_count ($ip, ":") !== 7) - throw new \Exception ("uncompressIPv6: Invalid IP provided", 500); - } - if (substr ($ip, 0, 17) === "0:0:0:0:0:0:ffff:") - { - // Manage the IPv4 blocks in IPv6 : ::ffff:192.168.1.2 - // If the IP is already in valid IPv6 (without dots), skip this part - $ipv4Block = substr ($ip, 17); - if (strpos ($ipv4Block, ".") !== false) - { - @list ($ip1, $ip2, $ip3, $ip4) = @explode (".", $ipv4Block); - // remove the first 0: as there is 2 nibbles for the IPv4 address - $ip = substr ($ip, 2, 15); - $ip .= sprintf ("%x:%x", $ip1 * 256 + $ip2, $ip3 * 256 + $ip4); - } - } - return $ip; - } - - /** Get an IPv6 address with the format - * x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x - * and return it with format - * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx - * Return false if the IP provided is not complete - * @param string $ipv6 The IPv6 to group - */ - public function groupIPv6 ($ipv6) - { - if (! is_string ($ipv6) || $ipv6 === "") - throw new \Exception (dgettext ("domframework", "Invalid IPv6 address"), - 500); - if (substr_count ($ipv6, ".") !== 31) - throw new \Exception (dgettext ("domframework", "Invalid IPv6 address"), - 500); - $ipv6 = str_replace (".", "", $ipv6); - $new = ""; - for ($i = 0 ; $i < 32 ; $i++) - { - if ($i % 4 === 0 && $i !== 0) - { - $new .= ":"; - } - $new .= $ipv6[$i]; - } - return $new; - } - - /** Return the IP adddress with filling the fields with the missing zeros. - * Valid only on IPv6 (but don't change anything if the provided address is - * IPv4) - * @param string $ip The IP to complete - * @return string The address in nibbles - * Example : $ip = "::", return "0000:0000:0000:0000:0000:0000:0000:0000" - * Example : $ip = "::ffff:127.0.0.1", - * return "0000:0000:0000:0000:0000:0000:ffff:7f00:0001" - */ - public function completeAddressWithZero ($ip) - { - if (! is_string ($ip) || $ip === "") - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - $ip = $this->uncompressIPv6 ($ip); - if (substr_count ($ip, ":") === 7) - { - // IPv6 - $ips = explode (":", $ip); - $ipnew = array(); - foreach ($ips as $iptmp) - { - $ipnew[] = sprintf ("%04x", hexdec ($iptmp)); - } - return implode (":", $ipnew); - } - elseif (substr_count ($ip, ".") === 31) - { - // Full IPv6 with dots - return $ip; - } - elseif (substr_count ($ip, ".") === 3) - { - // IPv4 - return $ip; - } - throw new \Exception (dgettext ("domframework", "Invalid IP address"), 500); - } - - /** Return the provided CIDR in binary. Length must be in bytes. - * Return FALSE if the parameters are invalid - * @param integer $cidr The CIDR to convert - * @param integer $length The length to use - */ - public function cidrToBin ($cidr, $length) - { - if (! is_numeric ($cidr) || $cidr < 0 || $cidr > 128) - throw new \Exception (dgettext ("domframework", "Invalid CIDR"), 500); - if (! is_numeric ($length) || $length < 1 || $length > 16) - throw new \Exception (dgettext ("domframework", "Invalid length"), 500); - $val=""; - for ( $i=0 ; $i<$length*8 ; $i++ ) - { - if ($i < $cidr) $val.="1"; - else $val.="0"; - } - return pack ('H*', $this->str_base_convert ($val, 2, 16)); - } - - /** Base conversion with 128 bits support for IPv6 - * Based on http://fr2.php.net/manual/en/function.base-convert.php#109660 - * @param string $str The string to convert - * @param integer|null $frombase The base of the provided string (10 by - * default) - * @param integer|null $tobase The base of the returned string (36 by - * default) - */ - public function str_base_convert($str, $frombase=10, $tobase=36) - { - $str = trim ($str); - if (intval ($frombase) != 10) - { - $len = strlen ($str); - $q = 0; - for ($i=0; $i<$len; $i++) - { - $r = base_convert ($str[$i], $frombase, 10); - $q = bcadd (bcmul ($q, $frombase), $r); - } - } - else - { - $q = $str; + $rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + if ($rc === false) { + return false; + } + return true; } - if (intval ($tobase) != 10) + /** Return true if the provided IP address is valid and is IPv6 + * @param string $ip The IP Address to validate + */ + public function validIPv6Address($ip) { - $s = ''; - while (bccomp ($q, '0', 0) > 0) - { - $r = intval (bcmod($q, $tobase)); - $s = base_convert ($r, 10, $tobase) . $s; - $q = bcdiv ($q, $tobase, 0); - } - } - else - { - $s = $q; + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IPv6 address"), + 500 + ); + } + $rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + if ($rc === false) { + return false; + } + return true; } - return $s; - } + /** Return true if the provided IP address is valid (IPv4 or IPv6) and the + * provided CIDR is valid too + * @param string $ip The IP Address to validate with a CIDR + */ + public function validIPAddressWithCIDR($ip) + { + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + $rc = $this->validIPv4AddressWithCIDR($ip); + if ($rc === true) { + return true; + } + $rc = $this->validIPv6AddressWithCIDR($ip); + return $rc; + } - /** Reverse the provided IP address - * The IPv6 are returned in format : - * x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x - * @param string $ipReverse The IPv6 to reverse - */ - function reverseIPAddress ($ipReverse) - { - if (!is_string ($ipReverse) || $ipReverse === "") - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - $ipReverse = $this->completeAddressWithZero ($ipReverse); - if (substr_count ($ipReverse, ":") === 7 && strlen ($ipReverse) == 39) + /** Return true if the provided IP address is valid and is IPv4 and the + * provided CIDR is valid too + * @param string $ip The IP Address to validate with a CIDR + */ + public function validIPv4AddressWithCIDR($ip) { - // Complete IPv6 with quadruplets and colon - $ip = str_replace (":", "", $ipReverse); - $tmp2 = array_reverse (str_split ($ip)); - return implode (".", $tmp2); + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IPv4 address"), + 500 + ); + } + @list($ip, $cidr) = @explode("/", $ip); + if ($cidr === null) { + return false; + } + $rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + if ($rc === false) { + return false; + } + if ($this->validIPv4CIDR($cidr) === false) { + return false; + } + return true; } - elseif (substr_count ($ipReverse, ".") === 31) - { - // IPv6 with dots - $tmp2 = explode (".", $ipReverse); - $tmp2 = array_reverse ($tmp2); - $ipnew = implode (".", $tmp2); - return $ipnew; - } - elseif (substr_count ($ipReverse, ".") === 3) - { - // IPv4 - $tmp2 = explode (".", $ipReverse); - $tmp2 = array_reverse ($tmp2); - $ipnew = implode (".", $tmp2); - return $ipnew; - } - throw new \Exception (dgettext ("domframework", "Invalid IP address"), 500); - } - /** This function return the CIDR associated to the provided netmask - * Ex. Return 24 for a mask 255.255.255.0 in direct - * Ex. Return 24 for a mask 0.0.0.255 in wildcard - * Work only in IPv4 - * Return FALSE if the provided mask is invalid (155.0.0.0 by example) - * Throw an exception if the provided IP is invalid - * @param string $netmask The mask to convert in CIDR - * @param boolean|null $maskdirect If true check a direct mask, if false - * check a wildcard mask - */ - public function netmask2cidr ($netmask, $maskdirect = true) - { - $maskdirect = "". ($maskdirect + 0); - $maskrevert = ($maskdirect === "0") ? "1" : "0"; - $netmask = ip2long ($netmask); - if ($netmask === FALSE) - throw new \Exception (dgettext ("domframework", "Invalid netmask"), 500); - $netmask = decbin ($netmask); - $netmask = sprintf ("%032s", $netmask); - $res = -1; - for ($i = 0 ; $i < 32 ; $i++) + /** Return true if the provided IP address is valid and is IPv6 and the + * provided CIDR is valid too + * @param string $ip The IP Address to validate with a CIDR + */ + public function validIPv6AddressWithCIDR($ip) { - if ($res === -1 && $netmask[$i] === $maskdirect) - { - } - elseif ($res === -1 && $netmask[$i] === $maskrevert) - { - $res = $i; - } - elseif ($res !== -1 && $netmask[$i] === $maskdirect) - { - return false; - } - else - { - } + if (!is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IPv6 address"), + 500 + ); + } + @list($ip, $cidr) = @explode("/", $ip); + if ($cidr === null) { + return false; + } + $rc = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + if ($rc === false) { + return false; + } + if ($this->validIPv6CIDR($cidr) === false) { + return false; + } + return true; } - if ($res === -1 && $i === 32) - return 32; - if ($res === -1 && $i === 1) - return 32; - return $res; - } - /** This function return the netmask associated to a CIDR. - * Work only on IPv4 addresses (CIDR between 0 and 32) - * @param string $cidr The CIDR to convert in netmask - * @param boolean|null $maskdirect If true return a direct mask, if false - * return a wildcard mask - * @return the mask - * @return false if the CIDR is not between 0 and 32 - */ - public function cidr2netmask ($cidr, $maskdirect = true) - { - if ($cidr < 0 || $cidr > 32) - return false; - $maskdirect = "". ($maskdirect + 0); - $maskrevert = ($maskdirect === "0") ? "1" : "0"; - $bin = ""; - for ($i = 0 ; $i < 32 ; $i++) + /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4 + * or IPv6 + * @param integer $cidr The CIDR to test + * @return boolean The CIDR is valid + */ + public function validCIDR($cidr) { - if ($i < $cidr) - $bin .= $maskdirect; - else - $bin .= $maskrevert; + if (! is_integer($cidr) && ! is_integer($cidr)) { + throw new \Exception( + dgettext("domframework", "Invalid CIDR provided"), + 500 + ); + } + if (strspn($cidr, "0123456879") !== strlen($cidr)) { + return false; + } + if ($cidr < 0 || $cidr > 128) { + return false; + } + return true; } - $res = ""; - for ($i = 0 ; $i < 32 ; $i = $i + 8) - { - $block = substr ($bin, $i, 8); - if ($i > 0) - $res .= "."; - $res .= bindec ($block); - } - return $res; - } - /** This function return true if the provided address is in the provided - * network with the associated cidr - * @param string $ip The IPv4 or IPv6 to test - * @param string $network The IPv4 or IPv6 network base - * @param string $cidr The CIDR to apply - * @return boolean True if $ip is in $network/$cidr - */ - public function ipInNetwork ($ip, $network, $cidr) - { - if ($this->validIPAddress ($ip) === false) - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - if ($this->validIPAddress ($network) === false) - throw new \Exception (dgettext ("domframework", - "Invalid Network address"), 500); - $ipv4 = $this->validIPv4Address ($ip); - $networkv4 = $this->validIPv4Address ($network); - if ($ipv4 !== $networkv4) - throw new \Exception (dgettext ("domframework", - "Network and IP address are not compatible"), 500); - if ($ipv4 === true) + /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv4. + * @param integer $cidr The CIDR to test + * @return boolean The CIDR is valid + */ + public function validIPv4CIDR($cidr) { - if ($this->validIPv4CIDR ($cidr) === false) - throw new \Exception (dgettext ("domframework", - "CIDR is not IPv4 compatible"), 500); + if (! is_integer($cidr) && ! is_string($cidr)) { + throw new \Exception( + dgettext("domframework", "Invalid CIDR provided"), + 500 + ); + } + if (strspn($cidr, "0123456879") !== strlen($cidr)) { + return false; + } + if ($cidr < 0 || $cidr > 32) { + return false; + } + return true; } - else - { - if ($this->validIPv6CIDR ($cidr) === false) - throw new \Exception (dgettext ("domframework", - "CIDR is not IPv6 compatible"), 500); - } - return ($this->networkFirstIP ($ip, $cidr) === - $this->networkFirstIP ($network, $cidr)); - } - /** Get the first IP of a network. - * IPv4 and IPv6 compatible - * @param string $ip The IPv4 or IPv6 in the network - * @param string $cidr The CIDR to apply - * @return string the network base - * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0" - */ - public function networkFirstIP ($ip, $cidr) - { - return $this->networkFirstLastIP ($ip, $cidr, "0"); - } + /** Return true if the provided CIDR is valid. The CIDR can be valid in IPv6. + * @param integer $cidr The CIDR to test + * @return boolean The CIDR is valid + */ + public function validIPv6CIDR($cidr) + { + if (! is_integer($cidr) && ! is_string($cidr)) { + throw new \Exception( + dgettext("domframework", "Invalid CIDR provided"), + 500 + ); + } + if (strspn($cidr, "0123456879") !== strlen($cidr)) { + return false; + } + if ($cidr < 0 || $cidr > 128) { + return false; + } + return true; + } - /** Get the last IP of a network. - * IPv4 and IPv6 compatible - * @param string $ip The IPv4 or IPv6 in the network - * @param string $cidr The CIDR to apply - * @return string the network base - * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.255" - */ - public function networkLastIP ($ip, $cidr) - { - return $this->networkFirstLastIP ($ip, $cidr, "1"); - } + /** Return the IPv6 to compressed (or compact) form. + * Remove the 0 when they are placed on the begin of the nibble. + * Remove all the blocks only zero to convert them to :: (but only one time) + * Example: 2001:0660:530d:0201:0000:0000:0000:0124 => 2001:660:530d:201::124 + * If an IPv4 is provided, return it without modification + * @param string $ip The IP to compress + */ + public function compressIP($ip) + { + if (strpos($ip, ":") === false) { + return $ip; + } + $ip = $this->uncompressIPv6($ip); + $ipArr = explode(":", $ip); + if (count($ipArr) !== 8) { + return $ip; + } + // Remove the 0 if they are at the beginning of the nibble + foreach ($ipArr as &$ip) { + $ip = sprintf("%x", hexdec($ip)); + } + // Remove the 0 nibble if there is an other 0 nibble after + $cleanLoop = false; + $ipCompArr = array(); + foreach ($ipArr as $key => $val) { + // echo "VAL=".var_export ($val, true). + // ", cleanLoop=".var_export ($cleanLoop, true); + if ($val !== "0") { + // echo " => In NOT zero\n"; + if ($cleanLoop) { + $cleanLoop = false; + } + } elseif ($cleanLoop) { + // echo " => In CleanLoop\n"; + unset($ipArr[$key]); + } else { + // echo " => In ZERO\n"; + if (key_exists($key + 1, $ipArr) && $ipArr[$key + 1] === "0") { + // echo " ===> NEXT ZERO : CleanLoop Start\n"; + $cleanLoop = true; + $ipArr[$key] = ""; + } + } + } + $ipArr = array_values($ipArr); + if (end($ipArr) === "") { + array_pop($ipArr); + $ipArr[] = ":"; + } + if (reset($ipArr) === "") { + $ipArr[0] = ":"; + } + if (count($ipArr) === 1) { + $ipArr[] = ""; + } + $ipHex = implode(":", $ipArr); + return $ipHex; + } - /** Get the network first IP. - * IPv4 and IPv6 compatible - * @param string $ip The IPv4 or IPv6 in the network - * @param string $cidr The CIDR to apply - * @param string $map if "0", get the first address of the network, - * if "1" get the last address of the network - * @return string the network base - * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0" - */ - private function networkFirstLastIP ($ip, $cidr, $map) - { - if ($this->validIPAddress ($ip) === false) - throw new \Exception (dgettext ("domframework", "Invalid IP address"), - 500); - $ipv4 = $this->validIPv4Address ($ip); - if ($ipv4 === true) + /** Return the IPv6 uncompressed (all the fields exists). They are not filled + * by zeros + * If the provided IP is IPv4, there is no change applied + * Return False if the parameter is invalid + * Based on http://www.weberdev.com/get_example.php3?ExampleID=3921 + * @param string $ip The IP address to uncompress + * Example : $ip="::" => return "0:0:0:0:0:0:0:0" + * Example : $ip = "::ffff:127.0.0.1", + * return "0:0:0:0:0:0:ffff:7f00:1" + */ + public function uncompressIPv6($ip) { - if ($this->validIPv4CIDR ($cidr) === false) - throw new \Exception (dgettext ("domframework", - "CIDR is not IPv4 compatible"), 500); + if ( + ! is_string($ip) || $ip === "" || + $this->validIPAddress($ip) === false + ) { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + if (strstr($ip, "::")) { + $e = explode(":", $ip); + // Case where :: is in start + if ($e[0] === "") { + $e[0] = "0"; + } + // Case where :: is in end + if ($e[count($e) - 1] === "") { + $e[count($e) - 1] = "0"; + } + $s = 8 - count($e); + foreach ($e as $key => $val) { + if ($val === "") { + for ($i = 0; $i <= $s; $i++) { + $newipv6[] = 0; + } + } else { + $newipv6[] = $val; + } + } + $ip = implode(":", $newipv6); + if (substr_count($ip, ":") !== 7) { + throw new \Exception("uncompressIPv6: Invalid IP provided", 500); + } + } + if (substr($ip, 0, 17) === "0:0:0:0:0:0:ffff:") { + // Manage the IPv4 blocks in IPv6 : ::ffff:192.168.1.2 + // If the IP is already in valid IPv6 (without dots), skip this part + $ipv4Block = substr($ip, 17); + if (strpos($ipv4Block, ".") !== false) { + @list($ip1, $ip2, $ip3, $ip4) = @explode(".", $ipv4Block); + // remove the first 0: as there is 2 nibbles for the IPv4 address + $ip = substr($ip, 2, 15); + $ip .= sprintf("%x:%x", $ip1 * 256 + $ip2, $ip3 * 256 + $ip4); + } + } + return $ip; } - else + + /** Get an IPv6 address with the format + * x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x + * and return it with format + * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx + * Return false if the IP provided is not complete + * @param string $ipv6 The IPv6 to group + */ + public function groupIPv6($ipv6) { - if ($this->validIPv6CIDR ($cidr) === false) - throw new \Exception (dgettext ("domframework", - "CIDR is not IPv6 compatible"), 500); + if (! is_string($ipv6) || $ipv6 === "") { + throw new \Exception( + dgettext("domframework", "Invalid IPv6 address"), + 500 + ); + } + if (substr_count($ipv6, ".") !== 31) { + throw new \Exception( + dgettext("domframework", "Invalid IPv6 address"), + 500 + ); + } + $ipv6 = str_replace(".", "", $ipv6); + $new = ""; + for ($i = 0; $i < 32; $i++) { + if ($i % 4 === 0 && $i !== 0) { + $new .= ":"; + } + $new .= $ipv6[$i]; + } + return $new; } - // Convert the IP and CIDR to binary string - if ($ipv4) + + /** Return the IP adddress with filling the fields with the missing zeros. + * Valid only on IPv6 (but don't change anything if the provided address is + * IPv4) + * @param string $ip The IP to complete + * @return string The address in nibbles + * Example : $ip = "::", return "0000:0000:0000:0000:0000:0000:0000:0000" + * Example : $ip = "::ffff:127.0.0.1", + * return "0000:0000:0000:0000:0000:0000:ffff:7f00:0001" + */ + public function completeAddressWithZero($ip) { - list ($ip1, $ip2, $ip3, $ip4) = explode (".", $ip); - $ipBin = sprintf ("%08b%08b%08b%08b", $ip1, $ip2, $ip3, $ip4); - $cidrBin = ""; - for ($i = 0 ; $i < $cidr ; $i++) - $cidrBin .= "1"; - for ($i = $cidr ; $i < 32 ; $i++) - $cidrBin .= "0"; + if (! is_string($ip) || $ip === "") { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + $ip = $this->uncompressIPv6($ip); + if (substr_count($ip, ":") === 7) { + // IPv6 + $ips = explode(":", $ip); + $ipnew = array(); + foreach ($ips as $iptmp) { + $ipnew[] = sprintf("%04x", hexdec($iptmp)); + } + return implode(":", $ipnew); + } elseif (substr_count($ip, ".") === 31) { + // Full IPv6 with dots + return $ip; + } elseif (substr_count($ip, ".") === 3) { + // IPv4 + return $ip; + } + throw new \Exception(dgettext("domframework", "Invalid IP address"), 500); } - else + + /** Return the provided CIDR in binary. Length must be in bytes. + * Return FALSE if the parameters are invalid + * @param integer $cidr The CIDR to convert + * @param integer $length The length to use + */ + public function cidrToBin($cidr, $length) { - $ip = $this->completeAddressWithZero ($ip); - $ip = str_replace (":", "", $ip); - $ipArr = str_split ($ip, 2); - $ipBin = ""; - foreach ($ipArr as $ip) - $ipBin .= sprintf ("%08b", hexdec ($ip)); - $cidrBin = ""; - for ($i = 0 ; $i < $cidr ; $i++) - $cidrBin .= "1"; - for ($i = $cidr ; $i < 128 ; $i++) - $cidrBin .= "0"; + if (! is_numeric($cidr) || $cidr < 0 || $cidr > 128) { + throw new \Exception(dgettext("domframework", "Invalid CIDR"), 500); + } + if (! is_numeric($length) || $length < 1 || $length > 16) { + throw new \Exception(dgettext("domframework", "Invalid length"), 500); + } + $val = ""; + for ($i = 0; $i < $length * 8; $i++) { + if ($i < $cidr) { + $val .= "1"; + } else { + $val .= "0"; + } + } + return pack('H*', $this->str_base_convert($val, 2, 16)); } - // Get the binary value of IP if the mask is 1 or put $map if the mask is 0 - $ipBaseBin = ""; - for ($i = 0 ; $i < strlen ($ipBin) ; $i++) + + /** Base conversion with 128 bits support for IPv6 + * Based on http://fr2.php.net/manual/en/function.base-convert.php#109660 + * @param string $str The string to convert + * @param integer|null $frombase The base of the provided string (10 by + * default) + * @param integer|null $tobase The base of the returned string (36 by + * default) + */ + public function str_base_convert($str, $frombase = 10, $tobase = 36) { - if ($cidrBin[$i] === "1") - $ipBaseBin .= $ipBin[$i]; - else - $ipBaseBin .= "$map"; + $str = trim($str); + if (intval($frombase) != 10) { + $len = strlen($str); + $q = 0; + for ($i = 0; $i < $len; $i++) { + $r = base_convert($str[$i], $frombase, 10); + $q = bcadd(bcmul($q, $frombase), $r); + } + } else { + $q = $str; + } + + if (intval($tobase) != 10) { + $s = ''; + while (bccomp($q, '0', 0) > 0) { + $r = intval(bcmod($q, $tobase)); + $s = base_convert($r, 10, $tobase) . $s; + $q = bcdiv($q, $tobase, 0); + } + } else { + $s = $q; + } + + return $s; } - // Convert ipBaseBin from binary to decimal if IPv4 and to hexa for IPv6 - if ($ipv4) + + /** Reverse the provided IP address + * The IPv6 are returned in format : + * x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x + * @param string $ipReverse The IPv6 to reverse + */ + public function reverseIPAddress($ipReverse) { - $ipBase = ""; - for ($i = 0 ; $i < 32 ; $i = $i + 8) - { - $block = substr ($ipBaseBin, $i, 8); - if ($i > 0) - $ipBase .= "."; - $ipBase .= bindec ($block); - } + if (!is_string($ipReverse) || $ipReverse === "") { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + $ipReverse = $this->completeAddressWithZero($ipReverse); + if (substr_count($ipReverse, ":") === 7 && strlen($ipReverse) == 39) { + // Complete IPv6 with quadruplets and colon + $ip = str_replace(":", "", $ipReverse); + $tmp2 = array_reverse(str_split($ip)); + return implode(".", $tmp2); + } elseif (substr_count($ipReverse, ".") === 31) { + // IPv6 with dots + $tmp2 = explode(".", $ipReverse); + $tmp2 = array_reverse($tmp2); + $ipnew = implode(".", $tmp2); + return $ipnew; + } elseif (substr_count($ipReverse, ".") === 3) { + // IPv4 + $tmp2 = explode(".", $ipReverse); + $tmp2 = array_reverse($tmp2); + $ipnew = implode(".", $tmp2); + return $ipnew; + } + throw new \Exception(dgettext("domframework", "Invalid IP address"), 500); } - else + + /** This function return the CIDR associated to the provided netmask + * Ex. Return 24 for a mask 255.255.255.0 in direct + * Ex. Return 24 for a mask 0.0.0.255 in wildcard + * Work only in IPv4 + * Return FALSE if the provided mask is invalid (155.0.0.0 by example) + * Throw an exception if the provided IP is invalid + * @param string $netmask The mask to convert in CIDR + * @param boolean|null $maskdirect If true check a direct mask, if false + * check a wildcard mask + */ + public function netmask2cidr($netmask, $maskdirect = true) { - $ipBase = ""; - for ($i = 0 ; $i < 128 ; $i = $i + 8) - { - $block = substr ($ipBaseBin, $i, 8); - if ($i > 0 && $i % 16 == 0) - $ipBase .= ":"; - $ipBase .= sprintf ("%02x", bindec ($block)); - } - $ipBase = $this->compressIP ($ipBase); + $maskdirect = "" . ($maskdirect + 0); + $maskrevert = ($maskdirect === "0") ? "1" : "0"; + $netmask = ip2long($netmask); + if ($netmask === false) { + throw new \Exception(dgettext("domframework", "Invalid netmask"), 500); + } + $netmask = decbin($netmask); + $netmask = sprintf("%032s", $netmask); + $res = -1; + for ($i = 0; $i < 32; $i++) { + if ($res === -1 && $netmask[$i] === $maskdirect) { + } elseif ($res === -1 && $netmask[$i] === $maskrevert) { + $res = $i; + } elseif ($res !== -1 && $netmask[$i] === $maskdirect) { + return false; + } else { + } + } + if ($res === -1 && $i === 32) { + return 32; + } + if ($res === -1 && $i === 1) { + return 32; + } + return $res; + } + + /** This function return the netmask associated to a CIDR. + * Work only on IPv4 addresses (CIDR between 0 and 32) + * @param string $cidr The CIDR to convert in netmask + * @param boolean|null $maskdirect If true return a direct mask, if false + * return a wildcard mask + * @return the mask + * @return false if the CIDR is not between 0 and 32 + */ + public function cidr2netmask($cidr, $maskdirect = true) + { + if ($cidr < 0 || $cidr > 32) { + return false; + } + $maskdirect = "" . ($maskdirect + 0); + $maskrevert = ($maskdirect === "0") ? "1" : "0"; + $bin = ""; + for ($i = 0; $i < 32; $i++) { + if ($i < $cidr) { + $bin .= $maskdirect; + } else { + $bin .= $maskrevert; + } + } + $res = ""; + for ($i = 0; $i < 32; $i = $i + 8) { + $block = substr($bin, $i, 8); + if ($i > 0) { + $res .= "."; + } + $res .= bindec($block); + } + return $res; + } + + /** This function return true if the provided address is in the provided + * network with the associated cidr + * @param string $ip The IPv4 or IPv6 to test + * @param string $network The IPv4 or IPv6 network base + * @param string $cidr The CIDR to apply + * @return boolean True if $ip is in $network/$cidr + */ + public function ipInNetwork($ip, $network, $cidr) + { + if ($this->validIPAddress($ip) === false) { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + if ($this->validIPAddress($network) === false) { + throw new \Exception(dgettext( + "domframework", + "Invalid Network address" + ), 500); + } + $ipv4 = $this->validIPv4Address($ip); + $networkv4 = $this->validIPv4Address($network); + if ($ipv4 !== $networkv4) { + throw new \Exception(dgettext( + "domframework", + "Network and IP address are not compatible" + ), 500); + } + if ($ipv4 === true) { + if ($this->validIPv4CIDR($cidr) === false) { + throw new \Exception(dgettext( + "domframework", + "CIDR is not IPv4 compatible" + ), 500); + } + } else { + if ($this->validIPv6CIDR($cidr) === false) { + throw new \Exception(dgettext( + "domframework", + "CIDR is not IPv6 compatible" + ), 500); + } + } + return ($this->networkFirstIP($ip, $cidr) === + $this->networkFirstIP($network, $cidr)); + } + + /** Get the first IP of a network. + * IPv4 and IPv6 compatible + * @param string $ip The IPv4 or IPv6 in the network + * @param string $cidr The CIDR to apply + * @return string the network base + * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0" + */ + public function networkFirstIP($ip, $cidr) + { + return $this->networkFirstLastIP($ip, $cidr, "0"); + } + + /** Get the last IP of a network. + * IPv4 and IPv6 compatible + * @param string $ip The IPv4 or IPv6 in the network + * @param string $cidr The CIDR to apply + * @return string the network base + * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.255" + */ + public function networkLastIP($ip, $cidr) + { + return $this->networkFirstLastIP($ip, $cidr, "1"); + } + + /** Get the network first IP. + * IPv4 and IPv6 compatible + * @param string $ip The IPv4 or IPv6 in the network + * @param string $cidr The CIDR to apply + * @param string $map if "0", get the first address of the network, + * if "1" get the last address of the network + * @return string the network base + * Example : $ip="192.168.1.2", $cidr=24 => return "192.168.1.0" + */ + private function networkFirstLastIP($ip, $cidr, $map) + { + if ($this->validIPAddress($ip) === false) { + throw new \Exception( + dgettext("domframework", "Invalid IP address"), + 500 + ); + } + $ipv4 = $this->validIPv4Address($ip); + if ($ipv4 === true) { + if ($this->validIPv4CIDR($cidr) === false) { + throw new \Exception(dgettext( + "domframework", + "CIDR is not IPv4 compatible" + ), 500); + } + } else { + if ($this->validIPv6CIDR($cidr) === false) { + throw new \Exception(dgettext( + "domframework", + "CIDR is not IPv6 compatible" + ), 500); + } + } + // Convert the IP and CIDR to binary string + if ($ipv4) { + list($ip1, $ip2, $ip3, $ip4) = explode(".", $ip); + $ipBin = sprintf("%08b%08b%08b%08b", $ip1, $ip2, $ip3, $ip4); + $cidrBin = ""; + for ($i = 0; $i < $cidr; $i++) { + $cidrBin .= "1"; + } + for ($i = $cidr; $i < 32; $i++) { + $cidrBin .= "0"; + } + } else { + $ip = $this->completeAddressWithZero($ip); + $ip = str_replace(":", "", $ip); + $ipArr = str_split($ip, 2); + $ipBin = ""; + foreach ($ipArr as $ip) { + $ipBin .= sprintf("%08b", hexdec($ip)); + } + $cidrBin = ""; + for ($i = 0; $i < $cidr; $i++) { + $cidrBin .= "1"; + } + for ($i = $cidr; $i < 128; $i++) { + $cidrBin .= "0"; + } + } + // Get the binary value of IP if the mask is 1 or put $map if the mask is 0 + $ipBaseBin = ""; + for ($i = 0; $i < strlen($ipBin); $i++) { + if ($cidrBin[$i] === "1") { + $ipBaseBin .= $ipBin[$i]; + } else { + $ipBaseBin .= "$map"; + } + } + // Convert ipBaseBin from binary to decimal if IPv4 and to hexa for IPv6 + if ($ipv4) { + $ipBase = ""; + for ($i = 0; $i < 32; $i = $i + 8) { + $block = substr($ipBaseBin, $i, 8); + if ($i > 0) { + $ipBase .= "."; + } + $ipBase .= bindec($block); + } + } else { + $ipBase = ""; + for ($i = 0; $i < 128; $i = $i + 8) { + $block = substr($ipBaseBin, $i, 8); + if ($i > 0 && $i % 16 == 0) { + $ipBase .= ":"; + } + $ipBase .= sprintf("%02x", bindec($block)); + } + $ipBase = $this->compressIP($ipBase); + } + return $ipBase; } - return $ipBase; - } } diff --git a/src/Jwt.php b/src/Jwt.php index 9252a56..3ae1a19 100644 --- a/src/Jwt.php +++ b/src/Jwt.php @@ -1,4 +1,5 @@ @@ -15,216 +16,278 @@ namespace Domframework; */ class Jwt { - // PROPERTIES - /** List the allowed algorithms to sign the token - */ - private $supportedAlgs = array ( + // PROPERTIES + /** List the allowed algorithms to sign the token + */ + private $supportedAlgs = array( 'HS256' => array('hash_hmac', 'SHA256'), 'HS512' => array('hash_hmac', 'SHA512'), 'HS384' => array('hash_hmac', 'SHA384'), - ); + ); - /** Create the token based on payload, sign it with key, and optionally - * encrypt it with ckey - * Do not put confidential data in payload without encrypt it, as the result - * is only a Base64 format of JSON... - * @param array $payload The payload to store - * @param string $key The key to be used to sign the token - * @param string|null $alg The algorithm to use to sign the token (default - * is HS256) - * Allowed algorithms : HS256, HS512, HS384 - * @param string|null $ckey The cipher key to encrypt the payload - * @param string|null $cipherMethod The method to cipher the payload - * des-ede3-cbc by default - * @return string The Token - */ - public function encode ($payload, $key, $alg = "HS256", $ckey = null, - $cipherMethod = "des-ede3-cbc") - { - if (! key_exists ($alg, $this->supportedAlgs)) - throw new \Exception (dgettext ("domframework", - "Invalid encode algorithm requested : not allowed"), 500); - $header = array ("typ" => "JWT", "alg" => $alg); - $segments = array (); - $segments[] = $this->urlsafeB64Encode ($this->jsonEncode ($header)); - $payload = $this->jsonEncode ($payload); - if ($ckey) - { - $encrypt = new Encrypt (); - $payload = $encrypt->encrypt ($payload, $ckey, $cipherMethod); + /** Create the token based on payload, sign it with key, and optionally + * encrypt it with ckey + * Do not put confidential data in payload without encrypt it, as the result + * is only a Base64 format of JSON... + * @param array $payload The payload to store + * @param string $key The key to be used to sign the token + * @param string|null $alg The algorithm to use to sign the token (default + * is HS256) + * Allowed algorithms : HS256, HS512, HS384 + * @param string|null $ckey The cipher key to encrypt the payload + * @param string|null $cipherMethod The method to cipher the payload + * des-ede3-cbc by default + * @return string The Token + */ + public function encode( + $payload, + $key, + $alg = "HS256", + $ckey = null, + $cipherMethod = "des-ede3-cbc" + ) { + if (! key_exists($alg, $this->supportedAlgs)) { + throw new \Exception(dgettext( + "domframework", + "Invalid encode algorithm requested : not allowed" + ), 500); + } + $header = array("typ" => "JWT", "alg" => $alg); + $segments = array(); + $segments[] = $this->urlsafeB64Encode($this->jsonEncode($header)); + $payload = $this->jsonEncode($payload); + if ($ckey) { + $encrypt = new Encrypt(); + $payload = $encrypt->encrypt($payload, $ckey, $cipherMethod); + } + $segments[] = $this->urlsafeB64Encode($payload); + $toBeSigned = implode('.', $segments); + $signature = $this->sign($toBeSigned, $key, $alg); + $segments[] = $this->urlsafeB64Encode($signature); + return implode('.', $segments); } - $segments[] = $this->urlsafeB64Encode ($payload); - $toBeSigned = implode ('.', $segments); - $signature = $this->sign ($toBeSigned, $key, $alg); - $segments[] = $this->urlsafeB64Encode ($signature); - return implode ('.', $segments); - } - /** Decode the provide JWT and return an array of the payload - * @param string $jwt The token to examine - * @param string $key The key used to sign the message - * @param array|null $allowedAlg List of allowed algorithms. If null, all the - * algorithms defined in $this->supportedAlgs are allowed - * @param string|null $ckey The cipher key to decrypt the payload - * @param string|null $cipherMethod The method to cipher the payload - * des-ede3-cbc by default - * @return array the decoded payload - * @throw Exception if the key is not able to verify the token with the - * provided password - */ - public function decode ($jwt, $key, $allowedAlg = null, $ckey = null, - $cipherMethod = "des-ede3-cbc") - { - if ($allowedAlg === null) - $allowedAlg = array_keys ($this->supportedAlgs); - if (empty ($key)) - throw new \Exception (dgettext ("domframework", "Key may not be empty"), - 500); - $tks = explode(".", $jwt); - if (count ($tks) != 3) - throw new \Exception (dgettext ("domframework", "Malformed JWT Token"), - 403); - list ($headerb64, $payloadb64, $signb64) = $tks; - $header = (object)$this->jsonDecode ($this->urlsafeB64Decode ($headerb64)); - $payload = $this->urlsafeB64Decode ($payloadb64); - if ($ckey) - { - $encrypt = new Encrypt (); - $payload = $encrypt->decrypt ($payload, $ckey); + /** Decode the provide JWT and return an array of the payload + * @param string $jwt The token to examine + * @param string $key The key used to sign the message + * @param array|null $allowedAlg List of allowed algorithms. If null, all the + * algorithms defined in $this->supportedAlgs are allowed + * @param string|null $ckey The cipher key to decrypt the payload + * @param string|null $cipherMethod The method to cipher the payload + * des-ede3-cbc by default + * @return array the decoded payload + * @throw Exception if the key is not able to verify the token with the + * provided password + */ + public function decode( + $jwt, + $key, + $allowedAlg = null, + $ckey = null, + $cipherMethod = "des-ede3-cbc" + ) { + if ($allowedAlg === null) { + $allowedAlg = array_keys($this->supportedAlgs); + } + if (empty($key)) { + throw new \Exception( + dgettext("domframework", "Key may not be empty"), + 500 + ); + } + $tks = explode(".", $jwt); + if (count($tks) != 3) { + throw new \Exception( + dgettext("domframework", "Malformed JWT Token"), + 403 + ); + } + list($headerb64, $payloadb64, $signb64) = $tks; + $header = (object)$this->jsonDecode($this->urlsafeB64Decode($headerb64)); + $payload = $this->urlsafeB64Decode($payloadb64); + if ($ckey) { + $encrypt = new Encrypt(); + $payload = $encrypt->decrypt($payload, $ckey); + } + $payload = $this->jsonDecode($payload); + $signature = $this->urlsafeB64Decode($signb64); + if ($header === null) { + throw new \Exception(dgettext( + "domframework", + "JWT Header not readable" + ), 403); + } + if ($payload === null) { + throw new \Exception(dgettext( + "domframework", + "JWT Payload not readable" + ), 403); + } + if ($signature === false) { + throw new \Exception(dgettext( + "domframework", + "JWT Signature not readable" + ), 403); + } + if (empty($header->alg)) { + throw new \Exception(dgettext( + "domframework", + "JWT with Empty algorithm" + ), 403); + } + if (! in_array($header->alg, $allowedAlg)) { + throw new \Exception(dgettext( + "domframework", + "JWT with Invalid algorithm" + ), 403); + } + if (empty($header->typ)) { + throw new \Exception(dgettext( + "domframework", + "JWT with Empty type set" + ), 403); + } + if ($header->typ !== "JWT") { + throw new \Exception(dgettext( + "domframework", + "JWT with Invalid type" + ), 403); + } + if ( + ! $this->verify( + "$headerb64.$payloadb64", + $signature, + $key, + $header->alg + ) + ) { + throw new \Exception(dgettext( + "domframework", + "JWT Signature verification failed" + ), 403); + } + return $payload; } - $payload = $this->jsonDecode ($payload); - $signature = $this->urlsafeB64Decode ($signb64); - if ($header === null) - throw new \Exception (dgettext ("domframework", - "JWT Header not readable"), 403); - if ($payload === null) - throw new \Exception (dgettext ("domframework", - "JWT Payload not readable"), 403); - if ($signature === false) - throw new \Exception (dgettext ("domframework", - "JWT Signature not readable"), 403); - if (empty ($header->alg)) - throw new \Exception (dgettext ("domframework", - "JWT with Empty algorithm"), 403); - if (! in_array ($header->alg, $allowedAlg)) - throw new \Exception (dgettext ("domframework", - "JWT with Invalid algorithm"), 403); - if (empty ($header->typ)) - throw new \Exception (dgettext ("domframework", - "JWT with Empty type set"), 403); - if ($header->typ !== "JWT") - throw new \Exception (dgettext ("domframework", - "JWT with Invalid type"), 403); - if (! $this->verify("$headerb64.$payloadb64", $signature, $key, - $header->alg)) - throw new \Exception (dgettext ("domframework", - "JWT Signature verification failed"), 403); - return $payload; - } - /** Verify the provided token with the key and generate an return true if it - * can be verify - * @param string $input The text in Base64 to check - * @param string $sign The user provided signature in binary - * @param string $key The key to use to sign the input - * @param string $alg The algorithm to use to sign the input - * @return boolean Return true if the input signed is valid - */ - private function verify ($input, $sign, $key, $alg) - { - $signature = $this->sign ($input, $key, $alg); - if (function_exists ("hash_equals") && - (! key_exists ("hash_equals", $GLOBALS) || - $GLOBALS["hash_equals"] === true)) - return hash_equals ($signature, $sign); - if (strlen ($signature) !== strlen ($sign)) - return false; - $status = 0; - for ($i = 0; $i < strlen ($signature); $i++) - $status |= ord ($signature[$i]) ^ ord ($sign[$i]); - return $status === 0; - } - - /** Create a signing key - * @return string the signing key proposed - */ - public function createKey () - { - return sha1 (microtime (true)); - } - - /** Sign the requested string with the provided key and based on the algorithm - * @param string $input The string to sign - * @param string $key The key to use - * @param string $alg The algorithm to use to sign - * @return string The signed string in binary - */ - private function sign ($input, $key, $alg) - { - if (! key_exists ($alg, $this->supportedAlgs)) - throw new \Exception (dgettext ("domframework", - "Invalid encode algorithm requested : not allowed"), 500); - list ($method, $algorithm) = $this->supportedAlgs[$alg]; - switch($method) + /** Verify the provided token with the key and generate an return true if it + * can be verify + * @param string $input The text in Base64 to check + * @param string $sign The user provided signature in binary + * @param string $key The key to use to sign the input + * @param string $alg The algorithm to use to sign the input + * @return boolean Return true if the input signed is valid + */ + private function verify($input, $sign, $key, $alg) { - case 'hash_hmac': - return hash_hmac ($algorithm, $input, $key, true); - default: - throw new \Exception (dgettext ("domframework", - "Invalid method to sign the JWT"), 500); + $signature = $this->sign($input, $key, $alg); + if ( + function_exists("hash_equals") && + (! key_exists("hash_equals", $GLOBALS) || + $GLOBALS["hash_equals"] === true) + ) { + return hash_equals($signature, $sign); + } + if (strlen($signature) !== strlen($sign)) { + return false; + } + $status = 0; + for ($i = 0; $i < strlen($signature); $i++) { + $status |= ord($signature[$i]) ^ ord($sign[$i]); + } + return $status === 0; } - } - /** Return the provided string in base64 without equal at the end - * To be URL compliant, the slash and plus are converted to underscore and - * dash - * @param string $str The string the convert in base64 - * @return string The string converted in base64 - */ - private function urlsafeB64Encode ($str) - { - return rtrim (strtr (base64_encode ($str), '+/', '-_'), "="); - } - - /** Return the provided base64 to string - * @param string $str The string the convert from base64 - * @return string The string converted from base64 - */ - private function urlsafeB64Decode ($str) - { - $str = strtr ($str, '-_', '+/'); - $remainder = strlen ($str) % 4; - switch (strlen ($str) % 4) + /** Create a signing key + * @return string the signing key proposed + */ + public function createKey() { - case 0: break; - case 2: $str .= "=="; break; - case 3: $str .= "="; break; - default: - return false; + return sha1(microtime(true)); } - return base64_decode ($str); - } - /** Return the provided array to JSON string - * @param object $input The object to convert in JSON - * @return string The JSON string - */ - private function jsonEncode ($input) - { - $json = json_encode ($input); - if ($json === "null" && $input !== null) - throw new \Exception (dgettext ("domframework", - "JSON Encode : Null result with non-null input"), 500); - return $json; - } + /** Sign the requested string with the provided key and based on the algorithm + * @param string $input The string to sign + * @param string $key The key to use + * @param string $alg The algorithm to use to sign + * @return string The signed string in binary + */ + private function sign($input, $key, $alg) + { + if (! key_exists($alg, $this->supportedAlgs)) { + throw new \Exception(dgettext( + "domframework", + "Invalid encode algorithm requested : not allowed" + ), 500); + } + list($method, $algorithm) = $this->supportedAlgs[$alg]; + switch ($method) { + case 'hash_hmac': + return hash_hmac($algorithm, $input, $key, true); + default: + throw new \Exception(dgettext( + "domframework", + "Invalid method to sign the JWT" + ), 500); + } + } - /** Decode the provided JSON string and return the result - * If null, there is a decode problem - * @param string $input The string to decode - * @return mixed The decoded string in object - */ - private function jsonDecode ($input) - { - return json_decode ($input, false, 512, JSON_BIGINT_AS_STRING); - } + /** Return the provided string in base64 without equal at the end + * To be URL compliant, the slash and plus are converted to underscore and + * dash + * @param string $str The string the convert in base64 + * @return string The string converted in base64 + */ + private function urlsafeB64Encode($str) + { + return rtrim(strtr(base64_encode($str), '+/', '-_'), "="); + } + + /** Return the provided base64 to string + * @param string $str The string the convert from base64 + * @return string The string converted from base64 + */ + private function urlsafeB64Decode($str) + { + $str = strtr($str, '-_', '+/'); + $remainder = strlen($str) % 4; + switch (strlen($str) % 4) { + case 0: + break; + case 2: + $str .= "=="; + break; + case 3: + $str .= "="; + break; + default: + return false; + } + return base64_decode($str); + } + + /** Return the provided array to JSON string + * @param object $input The object to convert in JSON + * @return string The JSON string + */ + private function jsonEncode($input) + { + $json = json_encode($input); + if ($json === "null" && $input !== null) { + throw new \Exception(dgettext( + "domframework", + "JSON Encode : Null result with non-null input" + ), 500); + } + return $json; + } + + /** Decode the provided JSON string and return the result + * If null, there is a decode problem + * @param string $input The string to decode + * @return mixed The decoded string in object + */ + private function jsonDecode($input) + { + return json_decode($input, false, 512, JSON_BIGINT_AS_STRING); + } } diff --git a/src/Language.php b/src/Language.php index cfdf44a..0b68f77 100644 --- a/src/Language.php +++ b/src/Language.php @@ -1,4 +1,5 @@ @@ -11,369 +12,385 @@ namespace Domframework; */ class Language { - // Language.php + // Language.php - // Use Gettext, so the locales must be available in the system - // Check the output of the command 'locale -a' : - // en_GB.utf8 - // en_US.utf8 - // [...] - // fr_FR.utf8 - // The directories must be of this format but with a UTF8 in capital ! - // Example : ./locale/en_US.UTF8/LC_MESSAGES/programme.mo - // The only available codeset is UTF8 - // The languages are always in the format fr_FR (without the codeset) + // Use Gettext, so the locales must be available in the system + // Check the output of the command 'locale -a' : + // en_GB.utf8 + // en_US.utf8 + // [...] + // fr_FR.utf8 + // The directories must be of this format but with a UTF8 in capital ! + // Example : ./locale/en_US.UTF8/LC_MESSAGES/programme.mo + // The only available codeset is UTF8 + // The languages are always in the format fr_FR (without the codeset) - /** Language cache directory */ - public $cacheDir = "data/locale"; + /** Language cache directory */ + public $cacheDir = "data/locale"; - /** Choose the best language in the browser list and which is available in - * locale path - * @param string|null $repLocale Directory where are stored the translations - * @param string|null $languageCode The coding langugage of the soft - * @return string The choosed locale whithout charset (like fr_FR) - */ - function languageSelection ($repLocale = "./locale", $languageCode = "fr_FR") - { - $arrAccept = array (); - if (isset ($_SERVER["HTTP_ACCEPT_LANGUAGE"])) + /** Choose the best language in the browser list and which is available in + * locale path + * @param string|null $repLocale Directory where are stored the translations + * @param string|null $languageCode The coding langugage of the soft + * @return string The choosed locale whithout charset (like fr_FR) + */ + public function languageSelection($repLocale = "./locale", $languageCode = "fr_FR") { - // Analyse de HTTP_ACCEPT_LANGUAGE - // HTTP_ACCEPT_LANGUAGE est de la forme : fr,en;q=0.7,en-us;q=0.3 - // Recuperation de la liste des languages souhaitees - $arrAccept = explode(",", strtolower ($_SERVER["HTTP_ACCEPT_LANGUAGE"])); - // Pre-traitement des choix de l'utilisateur - foreach ($arrAccept as $key=>$value) - { - // Suppression des poids (l'ordre est donne dans la pile) - if ( ($pos = strpos ($value, ";")) !== FALSE) - { - $arrAccept[$key] = substr ($value, 0, $pos); + $arrAccept = array(); + if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) { + // Analyse de HTTP_ACCEPT_LANGUAGE + // HTTP_ACCEPT_LANGUAGE est de la forme : fr,en;q=0.7,en-us;q=0.3 + // Recuperation de la liste des languages souhaitees + $arrAccept = explode(",", strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"])); + // Pre-traitement des choix de l'utilisateur + foreach ($arrAccept as $key => $value) { + // Suppression des poids (l'ordre est donne dans la pile) + if (($pos = strpos($value, ";")) !== false) { + $arrAccept[$key] = substr($value, 0, $pos); + } + + // Si la language proposee est du style en-us, convertit en en-US + if (($pos = strpos($value, "-")) !== false) { + $arrAccept[$key] = substr($arrAccept[$key], 0, $pos) . + strtoupper(substr($arrAccept[$key], $pos)); + } + + // Remplacement des tirets par des soulignes + $arrAccept[$key] = str_replace("-", "_", $arrAccept[$key]); + } + } + if (isset($_SERVER["LC_MESSAGES"])) { + // La ligne ci-dessous permet de récupérer la language sans le codeset si + // il est fourni en_US.UTF8 -> en_US + @list($languageCodetmp, $codeset) = explode( + ".", + $_SERVER["LC_MESSAGES"] + ); + $arrAccept[] = $languageCodetmp; + } + if (isset($_SERVER["LANG"])) { + // La ligne ci-dessous permet de récupérer la language sans le codeset si + // il est fourni en_US.UTF8 -> en_US + @list($languageCodetmp, $codeset) = explode(".", $_SERVER["LANG"]); + $arrAccept[] = $languageCodetmp; } - // Si la language proposee est du style en-us, convertit en en-US - if ( ($pos = strpos ($value, "-")) !== FALSE) - { - $arrAccept[$key] = substr ($arrAccept[$key], 0, $pos). - strtoupper (substr ($arrAccept[$key], $pos)); + // Si l'utilisateur n'a defini aucune language, on met la language par + // defaut + if (empty($arrAccept)) { + $arrAccept[] = $languageCode; + } + // Le tableau $arrAccept est trié par priorité de language souhaité par + // l'utilisateur (0=>le plus important) + + // Recherche des languages disponibles dans le repertoire $repLocale + $arrLanguageAvailable = $this->languageTraductionsList($repLocale); + $arrLanguageAvailable[] = $languageCode; + + $languageCode = ""; + // Analyse pour donner la meilleure language possible + foreach ($arrAccept as $value) { + // Regarde si un repertoire existe avec la language proposee. + // Recherche insensible à la casse, retourne le nom du fichier avec la + // casse + $val2 = strtolower($value); + foreach ($arrLanguageAvailable as $val) { + $val3 = strtolower($val); + if ($val2 === $val3) { + $languageCode = $val; + break; + } + } + + // Regarde si un repertoire existe avec language en tant que base + // (l'utilisateur demande fr et on a fr_FR.utf-8) + foreach ($arrLanguageAvailable as $languageCodeAvailable) { + if ($value === substr($languageCodeAvailable, 0, strlen($value))) { + $languageCode = $languageCodeAvailable; + break; + } + } + + // On a trouvé : on arrête de chercher + if ($languageCode !== "") { + break; + } } - // Remplacement des tirets par des soulignes - $arrAccept[$key] = str_replace ("-", "_", $arrAccept[$key]); - } - } - if (isset ($_SERVER["LC_MESSAGES"])) - { - // La ligne ci-dessous permet de récupérer la language sans le codeset si - // il est fourni en_US.UTF8 -> en_US - @list ($languageCodetmp, $codeset) = explode (".", - $_SERVER["LC_MESSAGES"]); - $arrAccept[] = $languageCodetmp; - } - if (isset ($_SERVER["LANG"])) - { - // La ligne ci-dessous permet de récupérer la language sans le codeset si - // il est fourni en_US.UTF8 -> en_US - @list ($languageCodetmp, $codeset) = explode (".", $_SERVER["LANG"]); - $arrAccept[] = $languageCodetmp; - } - - // Si l'utilisateur n'a defini aucune language, on met la language par - // defaut - if (empty ($arrAccept)) - $arrAccept[] = $languageCode; - // Le tableau $arrAccept est trié par priorité de language souhaité par - // l'utilisateur (0=>le plus important) - - // Recherche des languages disponibles dans le repertoire $repLocale - $arrLanguageAvailable = $this->languageTraductionsList ($repLocale); - $arrLanguageAvailable[] = $languageCode; - - $languageCode = ""; - // Analyse pour donner la meilleure language possible - foreach ($arrAccept as $value) - { - // Regarde si un repertoire existe avec la language proposee. - // Recherche insensible à la casse, retourne le nom du fichier avec la - // casse - $val2 = strtolower ($value); - foreach ($arrLanguageAvailable as $val) - { - $val3 = strtolower ($val); - if ($val2 === $val3) - { - $languageCode = $val; - break; + // Si on n'a toujours pas trouve de language, c'est que la language par + // defaut proposee en tete de fichier est inconnue : on met la language "C" + // et le code s'affiche selon la programmation + if ($languageCode === "") { + $languageCode = "C"; } - } - // Regarde si un repertoire existe avec language en tant que base - // (l'utilisateur demande fr et on a fr_FR.utf-8) - foreach ($arrLanguageAvailable as $languageCodeAvailable) - { - if ($value === substr ($languageCodeAvailable, 0, strlen ($value))) - { - $languageCode = $languageCodeAvailable; - break; + return ($languageCode); + } + + /** Return the language recorded in the Cookie. Check if this language is + * @param string $cookieName The cookie name + * @param string|null $repLocale The directory use to store the locale files + * allowed + * @return string The language allowed or FALSE + */ + public function languageCookie($cookieName, $repLocale = "./locale") + { + if (!isset($_COOKIE[$cookieName])) { + return false; } - } - - // On a trouvé : on arrête de chercher - if ($languageCode !== "") - break; - } - - // Si on n'a toujours pas trouve de language, c'est que la language par - // defaut proposee en tete de fichier est inconnue : on met la language "C" - // et le code s'affiche selon la programmation - if ($languageCode === "") - $languageCode = "C"; - - return ($languageCode); - } - - /** Return the language recorded in the Cookie. Check if this language is - * @param string $cookieName The cookie name - * @param string|null $repLocale The directory use to store the locale files - * allowed - * @return string The language allowed or FALSE - */ - function languageCookie ($cookieName, $repLocale = "./locale") - { - if (!isset ($_COOKIE[$cookieName])) - return FALSE; - $listeTranslations = $this->languageTraductionsList ($repLocale); - if ($listeTranslations === FALSE) - return FALSE; - if (in_array ($_COOKIE[$cookieName], $listeTranslations)) - return $_COOKIE[$cookieName]; - return FALSE; - } - - /** Set the cookie with a TTL of one month - * @param string $cookieName The name of the cookie - * @param string $languageCode Language to store - * @param string $sitepath The site path - */ - function languageCookieSet ($cookieName, $languageCode, $sitepath) - { - @setcookie ($cookieName, $languageCode, time()+60*60*24*30, $sitepath); - } - - /** Return an array with all the languages available in the $repLocale dir - * The languages are in the format 'en_US' without the codeset. - * @param string|null $repLocale The directory use to store the locale files - * Return FALSE if there is an error - */ - function languageTraductionsList ($repLocale = "./locale") - { - if (! is_dir ($repLocale) || ! is_readable ($repLocale)) - return FALSE; - $list = glob ("$repLocale/*"); - foreach ($list as $key=>$val) - { - $val = basename ($val); - $pos = strpos ($val, "."); - if ($pos === FALSE) - $list[$key] = $val; - else - $list[$key] = substr ($val, 0, $pos); - } - sort ($list); - return $list; - } - - /** Return the full text of the category - * Return false if it doesn't exists - * @param string $category The category to analyze - */ - private function languageCategoryText ($category) - { - $categories[LC_ALL] = "LC_ALL"; - $categories[LC_COLLATE] = "LC_COLLATE"; - $categories[LC_CTYPE] = "LC_CTYPE"; - $categories[LC_MONETARY] = "LC_MONETARY"; - $categories[LC_NUMERIC] = "LC_NUMERIC"; - $categories[LC_TIME] = "LC_TIME"; - $categories[LC_MESSAGES] = "LC_MESSAGES"; - if (! isset ($categories[$category])) - return FALSE; - return $categories[$category]; - } - - /** This function manage the cache of $package.mo files as Apache cache them - * It return the directory to use - * @param string $languageCode Language with format "fr_FR" - * @param string|null $package The package name of the soft ($package.mo - * file). "messages" by default - * @param string|null $category The folder name LC_MESSAGES by default - * @param string|null $repLocale The folder where all the locales are stored - */ - function languageCache ($languageCode, $package="messages", - $category=LC_MESSAGES, $repLocale = "./locale") - { - // Apache cache le fichier messages.mo jusqu'au prochain redémarrage. L'idée - // est de créer un fichier temporaire basé sur le fichier normal. Du coup, - // si on change le fichier temporaire, Apache recharge le cache et donne les - // dernières traductions. - // Cette fonction gère le cache et renvoie le nom du fichier temporaire - - // La ligne ci-dessous permet de récupérer la language sans le codeset si - // il est fourni en_US.UTF8 -> en_US - if (($pos = strpos ($languageCode, ".")) !== FALSE) - list ($languageCode, $codeset) = explode (".", $languageCode); - $codeset = "UTF8"; // SANS TIRET ET EN MAJSUCULES!!! - // -> Le répertoire de données doit être fr_FR.UTF8 - $category = $this->languageCategoryText ($category); - $temporaries = glob ("$repLocale/$languageCode.$codeset/$category/*-*.mo"); - $moFile = "$repLocale/$languageCode.$codeset/$category/$package.mo"; - if (! file_exists ($moFile)) - return ""; - $linkBase = $this->cacheDir."/".filemtime($moFile)."/"; - $linkEnd = "$languageCode.$codeset/$category/$package.mo"; - $link = $linkBase.$linkEnd; - clearstatcache (false, $moFile); - // Manage the cache directory - if (! file_exists (dirname ($link))) - { - // Try to create the cache dir. If there is an error, return the official - // moFile. Apache will need to be restarted - @mkdir (dirname ($link), 0777, true); - } - if (is_dir (dirname ($link)) && is_writeable (dirname ($link)) && - is_readable (dirname ($link))) - { - // Manage the cache file - if (! file_exists ($link) || ! is_readable ($link) || - filemtime ($moFile) > filemtime ($link)) - { - // Do not remove immediately the old files : they can be used by Apache - $files = glob ($this->cacheDir."/*/".$linkEnd); - foreach ($files as $file) - { - unlink ($file); - // Remove the empty dirs. If not empty, do not display an error - @rmdir (dirname ($file)); - @rmdir (dirname (dirname ($file))); - @rmdir (dirname (dirname (dirname ($file)))); + $listeTranslations = $this->languageTraductionsList($repLocale); + if ($listeTranslations === false) { + return false; } - copy ($moFile, $link); - chmod ($link, 0666); - } - if (filemtime ($moFile) <= filemtime ($link)) - { - return $link; - } + if (in_array($_COOKIE[$cookieName], $listeTranslations)) { + return $_COOKIE[$cookieName]; + } + return false; } - return $moFile; - } - /** Start the Gettext support with the cached file .mo provided as parameter - * @param string $moFile The .mo file - * @param string $languageCode The language code to use - * @param integer $category the LC_ type to use - * @param string|null $repLocale The locale directory. Use "./locale" if not - * provided - */ - function languageActivation ($moFile, $languageCode, $category = LC_MESSAGES, - $repLocale = "./locale") - { - // Active le support Gettext pour le fichier de language .mo caché fourni en - // paramètre. - // fichierMo : fichier messages-1354015006.mo - // On ne vérifie pas la language fournie, elle doit correspondre à un - // fichier de language (qui peut être récupéré par languageSelection ou - // languageTraductionsList - // Language doit être fourni sans codeset (fr_FR et PAS fr_FR.UTF8) - if ($languageCode !== "C" && $moFile !== "") + /** Set the cookie with a TTL of one month + * @param string $cookieName The name of the cookie + * @param string $languageCode Language to store + * @param string $sitepath The site path + */ + public function languageCookieSet($cookieName, $languageCode, $sitepath) { - $package = substr (basename ($moFile) , 0, -3); - // La ligne ci-dessous permet de récupérer la language sans le codeset si - // il est fourni en_US.UTF8 -> en_US - if (($pos = strpos ($languageCode, ".")) !== FALSE) - list ($languageCode, $codeset) = explode (".", $languageCode); - $codeset = "UTF8"; // SANS TIRET ET EN MAJSUCULES!!! - // -> Le répertoire de données doit être fr_FR.UTF8 - putenv ('LANG='.$languageCode.'.'.$codeset); - putenv ('LANGUAGE='.$languageCode.'.'.$codeset); - $GLOBALS["domframework"]["lang"] = $languageCode; - bind_textdomain_codeset ($package, "utf-8"); - bindtextdomain ($package, $repLocale); - textdomain ($package); - - $rc = setlocale (LC_MESSAGES, $languageCode.'.'.$codeset); - if ($rc === FALSE) - { - // Language non disponible sur le système - // La liste des languages est affichée par 'locale -a' - return FALSE; - } - $rc = setlocale (LC_TIME, $languageCode.'.'.$codeset); - - return TRUE; + @setcookie($cookieName, $languageCode, time() + 60 * 60 * 24 * 30, $sitepath); } - return FALSE; - } - /** The complete stack of language selection - @param string $package The package name (package.(po|mo) files) - @param string $languageCookie The name of the cookie saved in the browser - @param string $forcedLanguage The name of a forced language - @return string The language with format fr_FR to be used */ - public function activeLanguage ($package, $languageCookie, - $forcedLanguage = null) - { - // Prefered language in the browser - $langNav = $this->languageSelection ("./locale", "fr_FR"); - // Language defined in the cookie - $langCookie = $this->languageCookie ($languageCookie); - if ($forcedLanguage !== null) - $languageCode = $forcedLanguage; - elseif ($langCookie !== FALSE) + /** Return an array with all the languages available in the $repLocale dir + * The languages are in the format 'en_US' without the codeset. + * @param string|null $repLocale The directory use to store the locale files + * Return FALSE if there is an error + */ + public function languageTraductionsList($repLocale = "./locale") { - $languageCode = $langCookie; - // Update the already set cookie - $this->languageCookieSet ($languageCookie, $languageCode, "/"); + if (! is_dir($repLocale) || ! is_readable($repLocale)) { + return false; + } + $list = glob("$repLocale/*"); + foreach ($list as $key => $val) { + $val = basename($val); + $pos = strpos($val, "."); + if ($pos === false) { + $list[$key] = $val; + } else { + $list[$key] = substr($val, 0, $pos); + } + } + sort($list); + return $list; } - else - $languageCode = $langNav; - // Cache the domframework's .mo file too - $dfFile = $this->languageCache ($languageCode, "domframework", LC_MESSAGES, - dirname (__FILE__)."/locale"); - $dfDir = dirname (dirname (dirname ($dfFile))); - $this->languageActivation ($dfFile, $languageCode, LC_MESSAGES, $dfDir); - $languageCodeFichier = $this->languageCache ($languageCode, $package); - $languageCodeDir = dirname (dirname (dirname ($languageCodeFichier))); - $this->languageActivation ($languageCodeFichier, $languageCode, LC_MESSAGES, - $languageCodeDir); - return $languageCode; - } - - /** Return the language name from the language - Ex. : $languageCode=fr_FR, return France - @param string $languageCode Language with format "fr_FR" - @return string Then language name */ - public function languageName ($languageCode) - { - switch ($languageCode) + /** Return the full text of the category + * Return false if it doesn't exists + * @param string $category The category to analyze + */ + private function languageCategoryText($category) { - case "fr_FR": return dgettext ("domframework", "French"); - case "en_US": return dgettext ("domframework", "English (US)"); - case "en_GB": return dgettext ("domframework", "English (GB)"); - default: - throw new \Exception ("No language available for '$languageCode'", 500); + $categories[LC_ALL] = "LC_ALL"; + $categories[LC_COLLATE] = "LC_COLLATE"; + $categories[LC_CTYPE] = "LC_CTYPE"; + $categories[LC_MONETARY] = "LC_MONETARY"; + $categories[LC_NUMERIC] = "LC_NUMERIC"; + $categories[LC_TIME] = "LC_TIME"; + $categories[LC_MESSAGES] = "LC_MESSAGES"; + if (! isset($categories[$category])) { + return false; + } + return $categories[$category]; } - } - /** Return the language subtag for the language - * http://www.iana.org/assignments/language-subtag-registry/ - * language-subtag-registry - * @param string $languageCode The language code to convert - */ - public function languageSubTag ($languageCode) - { - return str_replace ("_", "-", $languageCode); - } + /** This function manage the cache of $package.mo files as Apache cache them + * It return the directory to use + * @param string $languageCode Language with format "fr_FR" + * @param string|null $package The package name of the soft ($package.mo + * file). "messages" by default + * @param string|null $category The folder name LC_MESSAGES by default + * @param string|null $repLocale The folder where all the locales are stored + */ + public function languageCache( + $languageCode, + $package = "messages", + $category = LC_MESSAGES, + $repLocale = "./locale" + ) { + // Apache cache le fichier messages.mo jusqu'au prochain redémarrage. L'idée + // est de créer un fichier temporaire basé sur le fichier normal. Du coup, + // si on change le fichier temporaire, Apache recharge le cache et donne les + // dernières traductions. + // Cette fonction gère le cache et renvoie le nom du fichier temporaire + + // La ligne ci-dessous permet de récupérer la language sans le codeset si + // il est fourni en_US.UTF8 -> en_US + if (($pos = strpos($languageCode, ".")) !== false) { + list($languageCode, $codeset) = explode(".", $languageCode); + } + $codeset = "UTF8"; // SANS TIRET ET EN MAJSUCULES!!! + // -> Le répertoire de données doit être fr_FR.UTF8 + $category = $this->languageCategoryText($category); + $temporaries = glob("$repLocale/$languageCode.$codeset/$category/*-*.mo"); + $moFile = "$repLocale/$languageCode.$codeset/$category/$package.mo"; + if (! file_exists($moFile)) { + return ""; + } + $linkBase = $this->cacheDir . "/" . filemtime($moFile) . "/"; + $linkEnd = "$languageCode.$codeset/$category/$package.mo"; + $link = $linkBase . $linkEnd; + clearstatcache(false, $moFile); + // Manage the cache directory + if (! file_exists(dirname($link))) { + // Try to create the cache dir. If there is an error, return the official + // moFile. Apache will need to be restarted + @mkdir(dirname($link), 0777, true); + } + if ( + is_dir(dirname($link)) && is_writeable(dirname($link)) && + is_readable(dirname($link)) + ) { + // Manage the cache file + if ( + ! file_exists($link) || ! is_readable($link) || + filemtime($moFile) > filemtime($link) + ) { + // Do not remove immediately the old files : they can be used by Apache + $files = glob($this->cacheDir . "/*/" . $linkEnd); + foreach ($files as $file) { + unlink($file); + // Remove the empty dirs. If not empty, do not display an error + @rmdir(dirname($file)); + @rmdir(dirname(dirname($file))); + @rmdir(dirname(dirname(dirname($file)))); + } + copy($moFile, $link); + chmod($link, 0666); + } + if (filemtime($moFile) <= filemtime($link)) { + return $link; + } + } + return $moFile; + } + + /** Start the Gettext support with the cached file .mo provided as parameter + * @param string $moFile The .mo file + * @param string $languageCode The language code to use + * @param integer $category the LC_ type to use + * @param string|null $repLocale The locale directory. Use "./locale" if not + * provided + */ + public function languageActivation( + $moFile, + $languageCode, + $category = LC_MESSAGES, + $repLocale = "./locale" + ) { + // Active le support Gettext pour le fichier de language .mo caché fourni en + // paramètre. + // fichierMo : fichier messages-1354015006.mo + // On ne vérifie pas la language fournie, elle doit correspondre à un + // fichier de language (qui peut être récupéré par languageSelection ou + // languageTraductionsList + // Language doit être fourni sans codeset (fr_FR et PAS fr_FR.UTF8) + if ($languageCode !== "C" && $moFile !== "") { + $package = substr(basename($moFile), 0, -3); + // La ligne ci-dessous permet de récupérer la language sans le codeset si + // il est fourni en_US.UTF8 -> en_US + if (($pos = strpos($languageCode, ".")) !== false) { + list($languageCode, $codeset) = explode(".", $languageCode); + } + $codeset = "UTF8"; // SANS TIRET ET EN MAJSUCULES!!! + // -> Le répertoire de données doit être fr_FR.UTF8 + putenv('LANG=' . $languageCode . '.' . $codeset); + putenv('LANGUAGE=' . $languageCode . '.' . $codeset); + $GLOBALS["domframework"]["lang"] = $languageCode; + bind_textdomain_codeset($package, "utf-8"); + bindtextdomain($package, $repLocale); + textdomain($package); + + $rc = setlocale(LC_MESSAGES, $languageCode . '.' . $codeset); + if ($rc === false) { + // Language non disponible sur le système + // La liste des languages est affichée par 'locale -a' + return false; + } + $rc = setlocale(LC_TIME, $languageCode . '.' . $codeset); + + return true; + } + return false; + } + + /** The complete stack of language selection + @param string $package The package name (package.(po|mo) files) + @param string $languageCookie The name of the cookie saved in the browser + @param string $forcedLanguage The name of a forced language + @return string The language with format fr_FR to be used */ + public function activeLanguage( + $package, + $languageCookie, + $forcedLanguage = null + ) { + // Prefered language in the browser + $langNav = $this->languageSelection("./locale", "fr_FR"); + // Language defined in the cookie + $langCookie = $this->languageCookie($languageCookie); + if ($forcedLanguage !== null) { + $languageCode = $forcedLanguage; + } elseif ($langCookie !== false) { + $languageCode = $langCookie; + // Update the already set cookie + $this->languageCookieSet($languageCookie, $languageCode, "/"); + } else { + $languageCode = $langNav; + } + // Cache the domframework's .mo file too + $dfFile = $this->languageCache( + $languageCode, + "domframework", + LC_MESSAGES, + dirname(__FILE__) . "/locale" + ); + $dfDir = dirname(dirname(dirname($dfFile))); + $this->languageActivation($dfFile, $languageCode, LC_MESSAGES, $dfDir); + $languageCodeFichier = $this->languageCache($languageCode, $package); + $languageCodeDir = dirname(dirname(dirname($languageCodeFichier))); + $this->languageActivation( + $languageCodeFichier, + $languageCode, + LC_MESSAGES, + $languageCodeDir + ); + + return $languageCode; + } + + /** Return the language name from the language + Ex. : $languageCode=fr_FR, return France + @param string $languageCode Language with format "fr_FR" + @return string Then language name */ + public function languageName($languageCode) + { + switch ($languageCode) { + case "fr_FR": + return dgettext("domframework", "French"); + case "en_US": + return dgettext("domframework", "English (US)"); + case "en_GB": + return dgettext("domframework", "English (GB)"); + default: + throw new \Exception("No language available for '$languageCode'", 500); + } + } + + /** Return the language subtag for the language + * http://www.iana.org/assignments/language-subtag-registry/ + * language-subtag-registry + * @param string $languageCode The language code to convert + */ + public function languageSubTag($languageCode) + { + return str_replace("_", "-", $languageCode); + } } diff --git a/src/Lockfile.php b/src/Lockfile.php index 00a96c2..8d0252f 100644 --- a/src/Lockfile.php +++ b/src/Lockfile.php @@ -1,4 +1,5 @@ @@ -11,107 +12,123 @@ namespace Domframework; */ class Lockfile { - /** The Exclusive lock file */ - public $storagelock = "./data/lockfile.lock"; - /** The Read-Only lock file */ - private $storagelockRO = FALSE; + /** The Exclusive lock file */ + public $storagelock = "./data/lockfile.lock"; + /** The Read-Only lock file */ + private $storagelockRO = false; - /** This function lock the storage file until all is written. - If an other processus want to lock, it hang until the lock is released */ - public function lockRW () - { - if (!is_dir (dirname ($this->storagelock))) - @mkdir (dirname ($this->storagelock)); - if (!is_dir (dirname ($this->storagelock))) - throw new \Exception ("Can't create '".dirname ($this->storagelock). + /** This function lock the storage file until all is written. + If an other processus want to lock, it hang until the lock is released */ + public function lockRW() + { + if (!is_dir(dirname($this->storagelock))) { + @mkdir(dirname($this->storagelock)); + } + if (!is_dir(dirname($this->storagelock))) { + throw new \Exception( + "Can't create '" . dirname($this->storagelock) . "' directory for lockfile", - 500); - $lockid = uniqid() . '_' . md5 (mt_rand()); - $startTime = microtime (TRUE); - // Stale lock : 60s old min - if (file_exists ($this->storagelock) && - filemtime ($this->storagelock) < time() - 60) - { - // TODO : Log the Stale lock removing - unlink ($this->storagelock); + 500 + ); + } + $lockid = uniqid() . '_' . md5(mt_rand()); + $startTime = microtime(true); + // Stale lock : 60s old min + if ( + file_exists($this->storagelock) && + filemtime($this->storagelock) < time() - 60 + ) { + // TODO : Log the Stale lock removing + unlink($this->storagelock); + } + + // Wait RW Lock + while (1) { + while (file_exists($this->storagelock)) { + usleep(100000); + clearstatcache(true, $this->storagelock); + if (microtime(true) > $startTime + 10) { + throw new \Exception( + "Can't have the authorization lock RW in 10s", + 500 + ); + } + } + + file_put_contents($this->storagelock, $lockid, FILE_APPEND); + clearstatcache(true, $this->storagelock); + $cnt = file_get_contents($this->storagelock); + if (substr($cnt, 0, strlen($lockid)) === $lockid) { + break; + } + } + + // Wait all the RO lock to go away + $startTime = microtime(true); + while (count(glob($this->storagelock . "-*")) > 0) { + usleep(100000); + if (microtime(true) > $startTime + 10) { + throw new \Exception( + "Can't have the authorization lock RO in 10s", + 500 + ); + } + } + + // I have the lock and no RO lock ! + return true; } - // Wait RW Lock - while (1) + /** This function lock the storage in share mode (to read the file without + modification at the same time) */ + public function lockRO() { - while (file_exists ($this->storagelock)) - { - usleep (100000); - clearstatcache (TRUE, $this->storagelock); - if (microtime (TRUE) > $startTime + 10) - throw new \Exception ("Can't have the authorization lock RW in 10s", - 500); - } + if (!is_dir(dirname($this->storagelock))) { + @mkdir(dirname($this->storagelock)); + } + if (!is_dir(dirname($this->storagelock))) { + throw new \Exception( + "Can't create '" . dirname($this->storagelock) . "'", + 500 + ); + } + $lockid = uniqid() . '_' . md5(mt_rand()); + // Stale lock : 60s old min + if ( + file_exists($this->storagelock) && + filemtime($this->storagelock) < time() - 60 + ) { + // TODO : Log the Stale lock removing + unlink($this->storagelock); + } - file_put_contents ($this->storagelock, $lockid, FILE_APPEND); - clearstatcache (TRUE, $this->storagelock); - $cnt = file_get_contents ($this->storagelock); - if (substr ($cnt, 0, strlen ($lockid)) === $lockid) - break; + // wait the removing of lockRW + $startTime = microtime(true); + while (file_exists($this->storagelock)) { + usleep(100000); + clearstatcache(true, $this->storagelock); + if (microtime(true) > $startTime + 10) { + throw new \Exception("Can't have the authorization lock in 10s", 500); + } + } + + touch($this->storagelock . "-" . $lockid); + $this->storagelockRO = $this->storagelock . "-" . $lockid; } - // Wait all the RO lock to go away - $startTime = microtime (TRUE); - while (count (glob ($this->storagelock."-*")) > 0) + /** This function unlock RW the storage file */ + public function unlockRW() { - usleep (100000); - if (microtime (TRUE) > $startTime + 10) - throw new \Exception ("Can't have the authorization lock RO in 10s", - 500); + if (file_exists($this->storagelock)) { + unlink($this->storagelock); + } } - // I have the lock and no RO lock ! - return TRUE; - } - - /** This function lock the storage in share mode (to read the file without - modification at the same time) */ - public function lockRO () - { - if (!is_dir (dirname ($this->storagelock))) - @mkdir (dirname ($this->storagelock)); - if (!is_dir (dirname ($this->storagelock))) - throw new \Exception ("Can't create '".dirname ($this->storagelock)."'", - 500); - $lockid = uniqid() . '_' . md5 (mt_rand()); - // Stale lock : 60s old min - if (file_exists ($this->storagelock) && - filemtime ($this->storagelock) < time() - 60) + /** This function unlock RO the storage file */ + public function unlockRO() { - // TODO : Log the Stale lock removing - unlink ($this->storagelock); + if ($this->storagelockRO !== false && file_exists($this->storagelockRO)) { + unlink($this->storagelockRO); + } } - - // wait the removing of lockRW - $startTime = microtime (TRUE); - while (file_exists ($this->storagelock)) - { - usleep (100000); - clearstatcache (TRUE, $this->storagelock); - if (microtime (TRUE) > $startTime + 10) - throw new \Exception ("Can't have the authorization lock in 10s", 500); - } - - touch ($this->storagelock."-".$lockid); - $this->storagelockRO = $this->storagelock."-".$lockid; - } - - /** This function unlock RW the storage file */ - public function unlockRW () - { - if (file_exists ($this->storagelock)) - unlink ($this->storagelock); - } - - /** This function unlock RO the storage file */ - public function unlockRO () - { - if ($this->storagelockRO !== FALSE && file_exists ($this->storagelockRO)) - unlink ($this->storagelockRO); - } } diff --git a/src/Logger.php b/src/Logger.php index 02741f7..ad8c83c 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -1,4 +1,5 @@ @@ -12,46 +13,46 @@ namespace Domframework; */ class Logger { - /* The logger class can be used with : - $d=new logger; - $d->timezone = "Europe/Paris"; - $d->logtype="display|file"; - $d->logfile="/tmp/toto.log"; - $d->logwrite ("Super log default"); - $d->logwrite ("Super log DEBUG", $d::DEBUG); - $d->logwrite ("Super log NOTICE", $d::NOTICE); */ - // TODO : Add SQL support - /** The method to log. - Can be display, file, syslog, stderr, session - Can be merged with a pipe : "display|syslog|file" or put in array */ - public $logtype = "stderr"; - /** For logtype=file, the filename to use */ - public $logfile = FALSE; - /** Timezone use to save the logs */ - public $timezone = "UTC"; - /** Minimum log level in the logs */ - public $loglevelmin = LOG_NOTICE; - /** In Syslog mode, the facility to use - See http://fr2.php.net/manual/en/function.openlog.php for $syslogFacility */ - public $syslogFacility = LOG_USER; - /** In Syslog, prefix the log by the text */ - public $syslogPrefix = FALSE; - /** Remove X entries of backtrace to see the right file generating the error - */ - public $backTraceSkip = 1; - /** Display the backtrace in all the messages */ - public $backtraceDisplay = false; + /* The logger class can be used with : + $d=new logger; + $d->timezone = "Europe/Paris"; + $d->logtype="display|file"; + $d->logfile="/tmp/toto.log"; + $d->logwrite ("Super log default"); + $d->logwrite ("Super log DEBUG", $d::DEBUG); + $d->logwrite ("Super log NOTICE", $d::NOTICE); */ + // TODO : Add SQL support + /** The method to log. + Can be display, file, syslog, stderr, session + Can be merged with a pipe : "display|syslog|file" or put in array */ + public $logtype = "stderr"; + /** For logtype=file, the filename to use */ + public $logfile = false; + /** Timezone use to save the logs */ + public $timezone = "UTC"; + /** Minimum log level in the logs */ + public $loglevelmin = LOG_NOTICE; + /** In Syslog mode, the facility to use + See http://fr2.php.net/manual/en/function.openlog.php for $syslogFacility */ + public $syslogFacility = LOG_USER; + /** In Syslog, prefix the log by the text */ + public $syslogPrefix = false; + /** Remove X entries of backtrace to see the right file generating the error + */ + public $backTraceSkip = 1; + /** Display the backtrace in all the messages */ + public $backtraceDisplay = false; - /** The priorities which can be used in the priorities - LOG_EMERG system is unusable - LOG_ALERT action must be taken immediately - LOG_CRIT critical conditions - LOG_ERR error conditions - LOG_WARNING warning conditions - LOG_NOTICE normal, but significant, condition - LOG_INFO informational message - LOG_DEBUG debug-level message */ - private $priorities = array (LOG_EMERG => "EMERG", + /** The priorities which can be used in the priorities + LOG_EMERG system is unusable + LOG_ALERT action must be taken immediately + LOG_CRIT critical conditions + LOG_ERR error conditions + LOG_WARNING warning conditions + LOG_NOTICE normal, but significant, condition + LOG_INFO informational message + LOG_DEBUG debug-level message */ + private $priorities = array(LOG_EMERG => "EMERG", LOG_ALERT => "ALERT", LOG_CRIT => "CRITICAL", LOG_ERR => "ERROR", @@ -60,263 +61,361 @@ class Logger LOG_INFO => "INFO", LOG_DEBUG => "DEBUG"); - /** Catch all the messages raised by the PHP, in trigger_error - Use the properties of the logger to save the logs */ - public function catchAll () - { - set_error_handler (array (&$this, "errorHandler")); - } + /** Catch all the messages raised by the PHP, in trigger_error + Use the properties of the logger to save the logs */ + public function catchAll() + { + set_error_handler(array(&$this, "errorHandler")); + } - /** The error handler to log - * @param integer $errno The error number to use - * @param string $errstr The error message to save - * @param string $errfile The file which generate the error - * @param integer $errline The line where the error is generated - */ - public function errorHandler ($errno, $errstr, $errfile, $errline) - { - if (!(error_reporting() & $errno)) + /** The error handler to log + * @param integer $errno The error number to use + * @param string $errstr The error message to save + * @param string $errfile The file which generate the error + * @param integer $errline The line where the error is generated + */ + public function errorHandler($errno, $errstr, $errfile, $errline) { - // This error code is not included in error_reporting - return; - } - switch($errno) - { - case E_ERROR: $priority = LOG_ERR; break; - case E_WARNING: $priority = LOG_WARNING; break; - case E_PARSE: $priority = LOG_PARSE; break; - case E_NOTICE: $priority = LOG_NOTICE; break; - case E_CORE_ERROR: $priority = LOG_ERR; break; - case E_CORE_WARNING: $priority = LOG_WARNING; break; - case E_COMPILE_ERROR: $priority = LOG_ERR; break; - case E_COMPILE_WARNING: $priority = LOG_WARNING; break; - case E_USER_ERROR: $priority = LOG_ERR; break; - case E_USER_WARNING: $priority = LOG_WARNING; break; - case E_USER_NOTICE: $priority = LOG_NOTICE; break; - case E_STRICT: $priority = LOG_WARNING; break; - case E_RECOVERABLE_ERROR: $priority = LOG_ERR; break; - case E_DEPRECATED: $priority = LOG_WARNING; break; - case E_USER_DEPRECATED: $priority = LOG_WARNING; break; - } - $this->log ($priority, $errstr); - } - - /** Store a new message log in the log manager defined by $logtype - The message can be multiple types. An array will be stored in textual form - but it will accept only one depth. - The $message is not fixed, you can pass the number of parameters you want - @param integer|null $priority Priority to use - @param mixed ...$message Message to log */ - public function log ($priority=LOG_NOTICE, $message) - { - if (! is_int ($priority)) - { - switch ($priority) - { - case "LOG_EMERG": $priority = LOG_EMERG; break; - case "LOG_ALERT": $priority = LOG_ALERT; break; - case "LOG_CRIT": $priority = LOG_CRIT; break; - case "LOG_ERR": $priority = LOG_ERR; break; - case "LOG_WARNING": $priority = LOG_WARNING; break; - case "LOG_NOTICE": $priority = LOG_NOTICE; break; - case "LOG_INFO": $priority = LOG_INFO; break; - case "LOG_DEBUG": $priority = LOG_DEBUG; break; - } - } - if (! is_int ($this->loglevelmin)) - { - switch ($this->loglevelmin) - { - case "LOG_EMERG": $this->loglevelmin = LOG_EMERG; break; - case "LOG_ALERT": $this->loglevelmin = LOG_ALERT; break; - case "LOG_CRIT": $this->loglevelmin = LOG_CRIT; break; - case "LOG_ERR": $this->loglevelmin = LOG_ERR; break; - case "LOG_WARNING": $this->loglevelmin = LOG_WARNING; break; - case "LOG_NOTICE": $this->loglevelmin = LOG_NOTICE; break; - case "LOG_INFO": $this->loglevelmin = LOG_INFO; break; - case "LOG_DEBUG": $this->loglevelmin = LOG_DEBUG; break; - } - } - if ($this->loglevelmin < $priority) - return; - $backtrace = debug_backtrace(); - for ($i = 0 ; $i <= $this->backTraceSkip ; $i++) - $back = array_shift ($backtrace); - while (! array_key_exists ("file", $back) && count ($backtrace) > 0) - $back = array_shift ($backtrace); - $msg = ""; - if (isset ($_SERVER["HTTP_X_FORWARDED_FOR"])) - $msg .= "[".$_SERVER["HTTP_X_FORWARDED_FOR"]."] "; - elseif (isset ($_SERVER["REMOTE_ADDR"])) - $msg .= "[".$_SERVER["REMOTE_ADDR"]."] "; - - // The messages are all the parameters of the function except the first, - // which is the priority - $messages = func_get_args (); - array_shift ($messages); - // Convert each part of message to text - foreach ($messages as $m) - { - if (is_array ($m)) - { - $msg .= "["; - foreach ($m as $key=>$val) - { - if (is_array ($val)) - { - foreach ($val as $key2=>$val2) - { - $msg .= "$key2=>$val2,"; - } - } - else - { - $msg .= "$key=>$val,"; - } + if (!(error_reporting() & $errno)) { + // This error code is not included in error_reporting + return; } - $msg .= "]"; - } - else - { - $msg .= $m; - } + switch ($errno) { + case E_ERROR: + $priority = LOG_ERR; + break; + case E_WARNING: + $priority = LOG_WARNING; + break; + case E_PARSE: + $priority = LOG_PARSE; + break; + case E_NOTICE: + $priority = LOG_NOTICE; + break; + case E_CORE_ERROR: + $priority = LOG_ERR; + break; + case E_CORE_WARNING: + $priority = LOG_WARNING; + break; + case E_COMPILE_ERROR: + $priority = LOG_ERR; + break; + case E_COMPILE_WARNING: + $priority = LOG_WARNING; + break; + case E_USER_ERROR: + $priority = LOG_ERR; + break; + case E_USER_WARNING: + $priority = LOG_WARNING; + break; + case E_USER_NOTICE: + $priority = LOG_NOTICE; + break; + case E_STRICT: + $priority = LOG_WARNING; + break; + case E_RECOVERABLE_ERROR: + $priority = LOG_ERR; + break; + case E_DEPRECATED: + $priority = LOG_WARNING; + break; + case E_USER_DEPRECATED: + $priority = LOG_WARNING; + break; + } + $this->log($priority, $errstr); } - // Add the filename which generate the error - $msg .= " [".basename ($back["file"]).":".$back["line"]."]"; - - // Display the backtrace if it is needed - if ($this->backtraceDisplay) + /** Store a new message log in the log manager defined by $logtype + The message can be multiple types. An array will be stored in textual form + but it will accept only one depth. + The $message is not fixed, you can pass the number of parameters you want + @param integer|null $priority Priority to use + @param mixed ...$message Message to log */ + public function log($priority, $message) { - $e = new Exception(); - $msg .= "\n".($e->getTraceAsString()); + if ($priority === null) { + $priority = LOG_NOTICE; + } + if (! is_int($priority)) { + switch ($priority) { + case "LOG_EMERG": + $priority = LOG_EMERG; + break; + case "LOG_ALERT": + $priority = LOG_ALERT; + break; + case "LOG_CRIT": + $priority = LOG_CRIT; + break; + case "LOG_ERR": + $priority = LOG_ERR; + break; + case "LOG_WARNING": + $priority = LOG_WARNING; + break; + case "LOG_NOTICE": + $priority = LOG_NOTICE; + break; + case "LOG_INFO": + $priority = LOG_INFO; + break; + case "LOG_DEBUG": + $priority = LOG_DEBUG; + break; + } + } + if (! is_int($this->loglevelmin)) { + switch ($this->loglevelmin) { + case "LOG_EMERG": + $this->loglevelmin = LOG_EMERG; + break; + case "LOG_ALERT": + $this->loglevelmin = LOG_ALERT; + break; + case "LOG_CRIT": + $this->loglevelmin = LOG_CRIT; + break; + case "LOG_ERR": + $this->loglevelmin = LOG_ERR; + break; + case "LOG_WARNING": + $this->loglevelmin = LOG_WARNING; + break; + case "LOG_NOTICE": + $this->loglevelmin = LOG_NOTICE; + break; + case "LOG_INFO": + $this->loglevelmin = LOG_INFO; + break; + case "LOG_DEBUG": + $this->loglevelmin = LOG_DEBUG; + break; + } + } + if ($this->loglevelmin < $priority) { + return; + } + $backtrace = debug_backtrace(); + for ($i = 0; $i <= $this->backTraceSkip; $i++) { + $back = array_shift($backtrace); + } + while (! array_key_exists("file", $back) && count($backtrace) > 0) { + $back = array_shift($backtrace); + } + $msg = ""; + if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) { + $msg .= "[" . $_SERVER["HTTP_X_FORWARDED_FOR"] . "] "; + } elseif (isset($_SERVER["REMOTE_ADDR"])) { + $msg .= "[" . $_SERVER["REMOTE_ADDR"] . "] "; + } + + // The messages are all the parameters of the function except the first, + // which is the priority + $messages = func_get_args(); + array_shift($messages); + // Convert each part of message to text + foreach ($messages as $m) { + if (is_array($m)) { + $msg .= "["; + foreach ($m as $key => $val) { + if (is_array($val)) { + foreach ($val as $key2 => $val2) { + $msg .= "$key2=>$val2,"; + } + } else { + $msg .= "$key=>$val,"; + } + } + $msg .= "]"; + } else { + $msg .= $m; + } + } + + // Add the filename which generate the error + $msg .= " [" . basename($back["file"]) . ":" . $back["line"] . "]"; + + // Display the backtrace if it is needed + if ($this->backtraceDisplay) { + $e = new Exception(); + $msg .= "\n" . ($e->getTraceAsString()); + } + + if (is_string($this->logtype)) { + $logsType = explode("|", $this->logtype); + } elseif (is_array($this->logtype)) { + $logsType = $this->logtype; + } + if (in_array("display", $logsType)) { + $this->logdisplay($msg, $priority); + } + if (in_array("stderr", $logsType)) { + $this->logstderr($msg, $priority); + } + if (in_array("file", $logsType)) { + $this->logfile($msg, $priority); + } + if (in_array("syslog", $logsType)) { + $this->logsyslog($msg, $priority); + } + if (in_array("session", $logsType)) { + $this->logsession($msg, $priority); + } } - if (is_string ($this->logtype)) - $logsType = explode ("|", $this->logtype); - elseif (is_array ($this->logtype)) - $logsType = $this->logtype; - if (in_array ("display", $logsType)) - $this->logdisplay ($msg, $priority); - if (in_array ("stderr", $logsType)) - $this->logstderr ($msg, $priority); - if (in_array ("file", $logsType)) - $this->logfile ($msg, $priority); - if (in_array ("syslog", $logsType)) - $this->logsyslog ($msg, $priority); - if (in_array ("session", $logsType)) - $this->logsession ($msg, $priority); - } - - /** Log $message on file - @param string $message Message to log - @param integer|null $priority Priority to use */ - private function logfile ($message, $priority) - { - if ($this->logfile === FALSE) - throw new \Exception ("Undefined file where logging"); - if (!file_exists ($this->logfile)) + /** Log $message on file + @param string $message Message to log + @param integer|null $priority Priority to use */ + private function logfile($message, $priority) { - if (! is_dir (dirname ($this->logfile))) - throw new \Exception ("You must create the ".dirname ($this->logfile). + if ($this->logfile === false) { + throw new \Exception("Undefined file where logging"); + } + if (!file_exists($this->logfile)) { + if (! is_dir(dirname($this->logfile))) { + throw new \Exception("You must create the " . dirname($this->logfile) . "directory"); - if (! is_writable (dirname ($this->logfile))) - throw new \Exception ("The directory ".dirname ($this->logfile)." must" - ." be writable to create log file"); - } - elseif (!is_writable ($this->logfile)) - { - if (function_exists ("posix_geteuid")) - $user = posix_geteuid (); - elseif (getenv('USERNAME') !== FALSE) - $user = getenv('USERNAME'); - else - $user = ""; - throw new \Exception ("Logfile $this->logfile is not writable for user ". + } + if (! is_writable(dirname($this->logfile))) { + throw new \Exception("The directory " . dirname($this->logfile) . " must" + . " be writable to create log file"); + } + } elseif (!is_writable($this->logfile)) { + if (function_exists("posix_geteuid")) { + $user = posix_geteuid(); + } elseif (getenv('USERNAME') !== false) { + $user = getenv('USERNAME'); + } else { + $user = ""; + } + throw new \Exception("Logfile $this->logfile is not writable for user " . $user); + } + + ini_set("date.timezone", $this->timezone); + $message = date("Y/m/d H:i:s") . " [" . $this->priorities[$priority] . "] " . + $message . "\n"; + file_put_contents($this->logfile, $message, FILE_APPEND | LOCK_EX); } - ini_set ("date.timezone", $this->timezone); - $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". - $message."\n"; - file_put_contents ($this->logfile, $message, FILE_APPEND|LOCK_EX); - } - - /** Log $message on screen with adding date. Add the HTML flags if not in CLI. - @param string $message Message to log - @param integer|null $priority Priority to use */ - private function logdisplay ($message, $priority) - { - if (php_sapi_name () !== "cli") - echo ""; - ini_set ("date.timezone", $this->timezone); - $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". - $message; - if (php_sapi_name () !== "cli") - $message = nl2br ($message); - echo "$message"; - if (php_sapi_name () !== "cli") - echo "
                "; - echo "\n"; - } - - /** Log $message on stderr with adding date. Add the HTML flags if not in CLI. - @param string $message Message to log - @param integer|null $priority Priority to use */ - private function logstderr ($message, $priority) - { - ini_set ("date.timezone", $this->timezone); - $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". - $message; - file_put_contents("php://stderr", "$message"); - file_put_contents("php://stderr", "\n"); - } - - /** Log $message on syslog - @param string $message Message to log - @param integer|null $priority Priority to use */ - private function logsyslog ($message, $priority) - { - if (is_string ($this->syslogFacility)) + /** Log $message on screen with adding date. Add the HTML flags if not in CLI. + @param string $message Message to log + @param integer|null $priority Priority to use */ + private function logdisplay($message, $priority) { - switch ($this->syslogFacility) - { - case "LOG_AUTH": $this->syslogFacility=LOG_AUTH; break; - case "LOG_AUTHPRIV": $this->syslogFacility=LOG_AUTHPRIV; break; - case "LOG_DAEMON": $this->syslogFacility=LOG_DAEMON; break; - case "LOG_KERN": $this->syslogFacility=LOG_KERN; break; - case "LOG_LOCAL0": $this->syslogFacility=LOG_LOCAL0; break; - case "LOG_LOCAL1": $this->syslogFacility=LOG_LOCAL1; break; - case "LOG_LOCAL2": $this->syslogFacility=LOG_LOCAL2; break; - case "LOG_LOCAL3": $this->syslogFacility=LOG_LOCAL3; break; - case "LOG_LOCAL4": $this->syslogFacility=LOG_LOCAL4; break; - case "LOG_LOCAL5": $this->syslogFacility=LOG_LOCAL5; break; - case "LOG_LOCAL6": $this->syslogFacility=LOG_LOCAL6; break; - case "LOG_LOCAL7": $this->syslogFacility=LOG_LOCAL7; break; - case "LOG_LPR": $this->syslogFacility=LOG_LPR; break; - case "LOG_MAIL": $this->syslogFacility=LOG_MAIL; break; - case "LOG_NEWS": $this->syslogFacility=LOG_NEWS; break; - case "LOG_SYSLOG": $this->syslogFacility=LOG_SYSLOG; break; - case "LOG_USER": $this->syslogFacility=LOG_USER; break; - case "LOG_UUCP": $this->syslogFacility=LOG_UUCP; break; - } - } - openlog ($this->syslogPrefix, NULL, $this->syslogFacility); - // Syslog display a #012 when there is a \n : remove it - $message = str_replace ("\n", "", $message); - syslog ($priority, $message); - } - - /** Log $message on session (for debug) - @param string $message Message to log - @param integer|null $priority Priority to use */ - private function logsession ($message, $priority) - { - if (! isset ($_SESSION)) - throw new \Exception ("No session available to store the log", 500); - ini_set ("date.timezone", $this->timezone); - $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". + if (php_sapi_name() !== "cli") { + echo ""; + } + ini_set("date.timezone", $this->timezone); + $message = date("Y/m/d H:i:s") . " [" . $this->priorities[$priority] . "] " . $message; - $_SESSION["domframework"]["logger"][] = $message; - } + if (php_sapi_name() !== "cli") { + $message = nl2br($message); + } + echo "$message"; + if (php_sapi_name() !== "cli") { + echo "
                "; + } + echo "\n"; + } + + /** Log $message on stderr with adding date. Add the HTML flags if not in CLI. + @param string $message Message to log + @param integer|null $priority Priority to use */ + private function logstderr($message, $priority) + { + ini_set("date.timezone", $this->timezone); + $message = date("Y/m/d H:i:s") . " [" . $this->priorities[$priority] . "] " . + $message; + file_put_contents("php://stderr", "$message"); + file_put_contents("php://stderr", "\n"); + } + + /** Log $message on syslog + @param string $message Message to log + @param integer|null $priority Priority to use */ + private function logsyslog($message, $priority) + { + if (is_string($this->syslogFacility)) { + switch ($this->syslogFacility) { + case "LOG_AUTH": + $this->syslogFacility = LOG_AUTH; + break; + case "LOG_AUTHPRIV": + $this->syslogFacility = LOG_AUTHPRIV; + break; + case "LOG_DAEMON": + $this->syslogFacility = LOG_DAEMON; + break; + case "LOG_KERN": + $this->syslogFacility = LOG_KERN; + break; + case "LOG_LOCAL0": + $this->syslogFacility = LOG_LOCAL0; + break; + case "LOG_LOCAL1": + $this->syslogFacility = LOG_LOCAL1; + break; + case "LOG_LOCAL2": + $this->syslogFacility = LOG_LOCAL2; + break; + case "LOG_LOCAL3": + $this->syslogFacility = LOG_LOCAL3; + break; + case "LOG_LOCAL4": + $this->syslogFacility = LOG_LOCAL4; + break; + case "LOG_LOCAL5": + $this->syslogFacility = LOG_LOCAL5; + break; + case "LOG_LOCAL6": + $this->syslogFacility = LOG_LOCAL6; + break; + case "LOG_LOCAL7": + $this->syslogFacility = LOG_LOCAL7; + break; + case "LOG_LPR": + $this->syslogFacility = LOG_LPR; + break; + case "LOG_MAIL": + $this->syslogFacility = LOG_MAIL; + break; + case "LOG_NEWS": + $this->syslogFacility = LOG_NEWS; + break; + case "LOG_SYSLOG": + $this->syslogFacility = LOG_SYSLOG; + break; + case "LOG_USER": + $this->syslogFacility = LOG_USER; + break; + case "LOG_UUCP": + $this->syslogFacility = LOG_UUCP; + break; + } + } + openlog($this->syslogPrefix, null, $this->syslogFacility); + // Syslog display a #012 when there is a \n : remove it + $message = str_replace("\n", "", $message); + syslog($priority, $message); + } + + /** Log $message on session (for debug) + @param string $message Message to log + @param integer|null $priority Priority to use */ + private function logsession($message, $priority) + { + if (! isset($_SESSION)) { + throw new \Exception("No session available to store the log", 500); + } + ini_set("date.timezone", $this->timezone); + $message = date("Y/m/d H:i:s") . " [" . $this->priorities[$priority] . "] " . + $message; + $_SESSION["domframework"]["logger"][] = $message; + } } diff --git a/src/Macaddresses.php b/src/Macaddresses.php index 9284e7d..edd7027 100644 --- a/src/Macaddresses.php +++ b/src/Macaddresses.php @@ -1,4 +1,5 @@ @@ -18,50 +19,55 @@ namespace Domframework; */ class Macaddresses { - /** This method return true if the provided MAC address is valid - * return false if the mac is not valid - * The MAC format can be : - * - de:ad:be:af:aa:bb - * - de-ad-be-af-aa-bb - * - 0005.313B.9080 - * - 0005313B9080 - * @param string $mac The mac to check - * @return bool - */ - public static function isMACAddress ($mac) - { - if (! is_string ($mac)) - return false; - return ( - preg_match ("/^([a-fA-F0-9]{2}[-:]){5}[0-9A-Fa-f]{2}$/", $mac) === 1 || - preg_match ("/^([a-fA-F0-9]{4}[.]){2}[a-fA-F0-9]{4}$/", $mac) === 1 || - preg_match ("/^[a-fA-F0-9]{12}$/", $mac) === 1); - } + /** This method return true if the provided MAC address is valid + * return false if the mac is not valid + * The MAC format can be : + * - de:ad:be:af:aa:bb + * - de-ad-be-af-aa-bb + * - 0005.313B.9080 + * - 0005313B9080 + * @param string $mac The mac to check + * @return bool + */ + public static function isMACAddress($mac) + { + if (! is_string($mac)) { + return false; + } + return ( + preg_match("/^([a-fA-F0-9]{2}[-:]){5}[0-9A-Fa-f]{2}$/", $mac) === 1 || + preg_match("/^([a-fA-F0-9]{4}[.]){2}[a-fA-F0-9]{4}$/", $mac) === 1 || + preg_match("/^[a-fA-F0-9]{12}$/", $mac) === 1); + } - /** Reform the mac address with the separator. - * The provided mac MUST be without separator (can be removed by - * removeSeparator method) - * @param string $mac The mac address to update, without separator - * @param string|null $separator The separator to use (: by default) - * @param integer|null $nbdigit The number of digit to use - * @return string The updated mac address with separators - */ - public static function addSeparator ($mac, $separator = ':', $nbdigit = 2) - { - if (strspn ($mac, "0132465789ABCDEFabcdef") !== strlen ($mac)) - throw new \Exception (dgettext ("domframework", - "Invalid mac address provided to addSeparator : bad chars"), 406); - return join ($separator, str_split ($mac, $nbdigit)); - } + /** Reform the mac address with the separator. + * The provided mac MUST be without separator (can be removed by + * removeSeparator method) + * @param string $mac The mac address to update, without separator + * @param string|null $separator The separator to use (: by default) + * @param integer|null $nbdigit The number of digit to use + * @return string The updated mac address with separators + */ + public static function addSeparator($mac, $separator = ':', $nbdigit = 2) + { + if (strspn($mac, "0132465789ABCDEFabcdef") !== strlen($mac)) { + throw new \Exception(dgettext( + "domframework", + "Invalid mac address provided to addSeparator : bad chars" + ), 406); + } + return join($separator, str_split($mac, $nbdigit)); + } - /** Remove all the separators from the provided MAC address - * @param string $mac the mac address to update - * @param array|null $separators The separators to remove - * @return string the updated mac address without separators - */ - public static function removeSeparator ($mac, - $separators = array (":", "-", ".")) - { - return str_replace ($separators, '', $mac); - } + /** Remove all the separators from the provided MAC address + * @param string $mac the mac address to update + * @param array|null $separators The separators to remove + * @return string the updated mac address without separators + */ + public static function removeSeparator( + $mac, + $separators = array(":", "-", ".") + ) { + return str_replace($separators, '', $mac); + } } diff --git a/src/Mail.php b/src/Mail.php index e07dcf9..2f36dfd 100644 --- a/src/Mail.php +++ b/src/Mail.php @@ -1,4 +1,5 @@ @@ -11,1564 +12,1760 @@ namespace Domframework; */ class Mail { - /** The complete of the mail */ - private $completeEmailEML = ""; + private $completeEmailEML = ""; - /** Private the separator between the headers and the mail. Should be - * \r\n on a line, but special crafted mails may use something else - */ - private $headerBodySeparator = "\r\n"; + /** Private the separator between the headers and the mail. Should be + * \r\n on a line, but special crafted mails may use something else + */ + private $headerBodySeparator = "\r\n"; - /** Sections definitions - * Will store the mails sections with the parameters : - * _parent string|null The parent identifier - * _boundary string|null The Boundary identifier - * _contentType string The simplified Content Type - * Content-Type string The complete Content-Type used in previous headers - * _partsIDchild array the parts ID linked to this section - */ - private $sections = array (); + /** Sections definitions + * Will store the mails sections with the parameters : + * _parent string|null The parent identifier + * _boundary string|null The Boundary identifier + * _contentType string The simplified Content Type + * Content-Type string The complete Content-Type used in previous headers + * _partsIDchild array the parts ID linked to this section + */ + private $sections = array(); - /** Counter for the recursion */ - private $recurse; + /** Counter for the recursion */ + private $recurse; - /** Display the existing sections lighter than print_r, without the Carriage - * returns - */ - private function printSections () - { - foreach ($this->sections as $sectionID=>$vals) + /** Display the existing sections lighter than print_r, without the Carriage + * returns + */ + private function printSections() { - echo "[$sectionID] => Array (\n"; - foreach ($vals as $key=>$val) - { - if (is_array ($val)) - { - echo " [$key] => Array (\n"; - foreach ($val as $k2=>$v2) - { - if (is_array ($v2)) - { - echo " [$k2] => Array (\n"; - foreach ($v2 as $k3=>$v3) - echo " [$k3] => ".rtrim ($v3, "\r\n")."\n"; - echo " )\n"; + foreach ($this->sections as $sectionID => $vals) { + echo "[$sectionID] => Array (\n"; + foreach ($vals as $key => $val) { + if (is_array($val)) { + echo " [$key] => Array (\n"; + foreach ($val as $k2 => $v2) { + if (is_array($v2)) { + echo " [$k2] => Array (\n"; + foreach ($v2 as $k3 => $v3) { + echo " [$k3] => " . rtrim($v3, "\r\n") . "\n"; + } + echo " )\n"; + } else { + echo " [$k2] => " . rtrim($v2, "\r\n") . "\n"; + } + } + echo " )\n"; + } else { + echo " [$key] => " . rtrim($val, "\r\n") . "\n"; + } } - else - { - echo " [$k2] => ".rtrim ($v2, "\r\n")."\n"; - } - } - echo " )\n"; + echo ")\n\n"; } - else - { - echo " [$key] => ".rtrim ($val, "\r\n")."\n"; - } - } - echo ")\n\n"; } - } - /** Add a new section - * @param array $param The parameters to store - * @return the sectionID - */ - private function sectionAdd ($param) - { - $sectionID = md5 (microtime(true).rand()); - $this->sections[$sectionID] = $param; - return $sectionID; - } - - /** Add a new section with the default parameters - * @return array The sectionID stored with the default parameters - */ - private function sectionAddDefault () - { - return $this->sectionAdd ( - array ("_headerBodySeparator"=>$this->headerBodySeparator, - "_headerCR"=>"\r\n", - "_headersEML"=>"", - "_headersArray"=>array (), - "_contentEML"=>"", - "_contentUTF"=>"")); - } - - /** Del an existing section - * If there is one child, and the section was multiple, remove it and - * associate the child to a new section - * @param string $sectionID The section to delete - */ - private function sectionDel ($sectionID) - { - // TODO ! - } - - /** Add a newChild to an existing section at the end of the list - * @param string $sectionIDParent The parent modified by adding a child - * @param string $sectionIDchild The sectionID of the child to add - */ - private function sectionAddChild ($sectionIDParent, $sectionIDchild) - { - if (! array_key_exists ($sectionIDParent, $this->sections)) - throw new \Exception (dgettext ("domframework", - "Section parent not found"), 404); - $this->sections[$sectionIDParent]["_partsIDchild"][] = $sectionIDchild; - $this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent; - } - - /** Add a newChild to an existing section at the beginning of the list - * @param string $sectionIDParent The parent modified by adding a child - * @param string $sectionIDchild The sectionID of the child to add - */ - private function sectionAddChildFirst ($sectionIDParent, $sectionIDchild) - { - if (! array_key_exists ($sectionIDParent, $this->sections)) - throw new \Exception (dgettext ("domframework", - "Section parent not found"), 404); - array_unshift ($this->sections[$sectionIDParent]["_partsIDchild"], - $sectionIDchild); - $this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent; - } - - /** Remove all the defined Childs in the section. Do not remove really the - * childs ! - * @param string $sectionID the section to clean - */ - private function sectionDelChilds ($sectionID) - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception (dgettext ("domframework", - "Section not found"), 404); - unset ($this->sections[$sectionID]["_partsIDchild"]); - } - - /** Update the content of an existing section - * @param string $sectionID The section to modify - * @param array $param The parameters to update - */ - private function sectionUpdate ($sectionID, $param) - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception (dgettext ("domframework", "Section not found"), - 404); - if (! is_array ($param)) - throw new \Exception (dgettext ("domframework", - "Param provided to sectionUpdate is not array"), 406); - foreach ($param as $key=>$val) + /** Add a new section + * @param array $param The parameters to store + * @return the sectionID + */ + private function sectionAdd($param) { - $this->sections[$sectionID][$key] = $val; - } - } - - /** Get the list of sections ID - * @return array the defined sectionsID - */ - private function sectionList () - { - return array_keys ($this->sections); - } - - /** Get the section ID List with parents ID - * @return array the defined sectionsID with the parent ID as value - */ - private function sectionListParent () - { - $res = array (); - foreach ($this->sections as $sectionID=>$content) - { - if (! array_key_exists ("_parentID", $content)) - $res[$sectionID] = ""; - else - $res[$sectionID] = $content["_parentID"]; - } - return $res; - } - - /** Return the content array of the section - * @param string $sectionID The section ID to get - * @return array The content of the section - */ - private function sectionGet ($sectionID) - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception (dgettext ("domframework", - "Section not found"), 404); - return $this->sections[$sectionID]; - } - - /** Get the section ID of the main part - * @return bool|string the section ID of the main part or FALSE if not found - */ - public function sectionMainID () - { - foreach ($this->sectionListParent () as $sectionID=>$parentID) - { - if ($parentID === "") + $sectionID = md5(microtime(true) . rand()); + $this->sections[$sectionID] = $param; return $sectionID; } - return false; - } - /** Refresh the _headersEML from the _headersArray - * @param string $sectionID the section to refresh - */ - private function sectionRefreshHeadersEML ($sectionID) - { - $section = $this->sectionGet ($sectionID); - $headersEML = ""; - foreach ($section["_headersArray"] as $val) + /** Add a new section with the default parameters + * @return array The sectionID stored with the default parameters + */ + private function sectionAddDefault() { - $head = key ($val); - $value = $val[$head]; - $headersEML .= "$head: $value"; + return $this->sectionAdd( + array("_headerBodySeparator" => $this->headerBodySeparator, + "_headerCR" => "\r\n", + "_headersEML" => "", + "_headersArray" => array(), + "_contentEML" => "", + "_contentUTF" => "") + ); } - $this->sections[$sectionID]["_headersEML"] = $headersEML; - } - /** Read the complete mail to analyze - * Destroy all the previous definitions of mail - * @param string $content The complete mail to read - */ - public function readMail ($content) - { - $this->sections = array (); - $this->completeEmailEML = $content; - $partinfo = $this->parseMessagePart ($content); - if ($partinfo !== null) - $this->readMailContentRecurse ($partinfo); - } - - /** Read the content of the mail and allow the content to be also multipart. - * Then the method is recursively called to generate the sections - * @param array $partinfo The partinfo from parseMessagePart to analyze - * @param string|null $sectionIDParent The parent sectionID to link with - */ - private function readMailContentRecurse ($partinfo, $sectionIDParent=false) - { - if (key_exists ("_contentType", $partinfo) && - substr ($partinfo["_contentType"], 0, 10) === "multipart/") + /** Del an existing section + * If there is one child, and the section was multiple, remove it and + * associate the child to a new section + * @param string $sectionID The section to delete + */ + private function sectionDel($sectionID) { - // multipart/alternative, multipart/related, multipart/mixed - // Remove the content, as it is not valuable (will be stored in childs) - $tmp = $partinfo; - unset ($tmp["_contentEML"]); - unset ($tmp["_contentUTF"]); - if ($sectionIDParent === false) - $sectionIDParent = $this->sectionAdd ($tmp); - $boundaryArray = preg_split ("#([\r\n]+)#", $partinfo["_contentEML"], - null, PREG_SPLIT_DELIM_CAPTURE); - // Remove the first 2 dashes : the boundary is stored like in the headers - $boundary = ""; - while (count ($boundaryArray) > 0 && substr ($boundary, 0, 2) !== "--") - { - // Skip the lines until the coundary is found. The boundary start by -- - $boundary = array_shift ($boundaryArray); - $boundaryCR = array_shift ($boundaryArray); - } - if ($boundary === false) - throw new \Exception (dgettext ("domframework", - "Can't find boundary in multipart/"), 406); - $boundary = substr ($boundary, 2); - unset ($boundaryArray); - $this->sectionUpdate ($sectionIDParent, - array ("_boundary"=>$boundary, - "_boundaryCR"=>$boundaryCR)); - $parts = preg_split ("#(--".preg_quote ($boundary)."(--)?)([\r\n]+)#", - $partinfo["_contentEML"], - null, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0 ; $i < count ($parts) ; $i = $i + 4) - { - if ($parts[$i] === "") - continue; - $messagePart = $this->parseMessagePart ($parts[$i]); - if ($messagePart === null || - ! array_key_exists ("_contentType", $messagePart)) - continue; - $messagePart["_parentID"] = $sectionIDParent; - $sectionIDChild = $this->sectionAdd ($messagePart); - $this->sectionAddChild ($sectionIDParent, $sectionIDChild); - if (substr ($messagePart["_contentType"], 0, 10) === "multipart/") - { - // Recursive part : multipart in multipart - unset ($this->sections[$sectionIDChild]["_contentEML"]); - unset ($this->sections[$sectionIDChild]["_contentUTF"]); - $this->readMailContentRecurse ($messagePart, $sectionIDChild); + // TODO ! + } + + /** Add a newChild to an existing section at the end of the list + * @param string $sectionIDParent The parent modified by adding a child + * @param string $sectionIDchild The sectionID of the child to add + */ + private function sectionAddChild($sectionIDParent, $sectionIDchild) + { + if (! array_key_exists($sectionIDParent, $this->sections)) { + throw new \Exception(dgettext( + "domframework", + "Section parent not found" + ), 404); } - } + $this->sections[$sectionIDParent]["_partsIDchild"][] = $sectionIDchild; + $this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent; } - else - { - $sectionIDParent = $this->sectionAdd ($partinfo); - } - } - /** Return the data for a part of the mail - * @param string $content The content of the mail to parse - * @return array The data content in the mail - */ - private function parseMessagePart ($content) - { - // Get the HeaderBodySeparator - $pos = strpos ($content, "\r\n\r\n"); - $headerBodySeparator = "\r\n"; - if ($pos === false) + /** Add a newChild to an existing section at the beginning of the list + * @param string $sectionIDParent The parent modified by adding a child + * @param string $sectionIDchild The sectionID of the child to add + */ + private function sectionAddChildFirst($sectionIDParent, $sectionIDchild) { - $pos = strpos ($content, "\n\n"); - $headerBodySeparator = "\n"; - } - if ($pos === false) - { - $pos = strpos ($content, "\r\r"); - $headerBodySeparator = "\r"; - } - if ($pos === false) - //throw new \Exception ("Can't find the header/body separator", 500); - return array ("_contentEML"=>$content); - // Get the headers - $headersEML = ltrim (substr ($content, 0, $pos+ - strlen ($headerBodySeparator))); - $headersArray = array (); - if ($headersEML !== "" && $headersEML !== "--") - { - $prev = ""; - $prevCR = ""; - $headersSplit = preg_split ("#([\r\n]+)#", $headersEML, null, - PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0 ; $i < count ($headersSplit); $i = $i + 2) - { - $h = $headersSplit[$i]; - if (! isset ($headersSplit[$i+1])) - $headersSplit[$i+1] = $headerBodySeparator; - if ($h === "" || $h === "--") - continue; - if ($h[0] === " " || $h[0] === "\t") - { - $prev .= $prevCR.$h; - $prevCR = $headersSplit[$i+1]; + if (! array_key_exists($sectionIDParent, $this->sections)) { + throw new \Exception(dgettext( + "domframework", + "Section parent not found" + ), 404); } - elseif ($prev !== "") - { - $exp = explode (": ", $prev, 2); - if (! array_key_exists (1, $exp)) - { - //trigger_error ("Malformed mail provided: no section header", - // E_USER_NOTICE); - $prev = ""; - continue; - } - list ($head, $value) = $exp; - $value .= $prevCR; - $headersArray[][$head] = $value; - $prev = $h; - $prevCR = $headersSplit[$i+1]; + array_unshift( + $this->sections[$sectionIDParent]["_partsIDchild"], + $sectionIDchild + ); + $this->sections[$sectionIDchild]["_parentID"] = $sectionIDParent; + } + + /** Remove all the defined Childs in the section. Do not remove really the + * childs ! + * @param string $sectionID the section to clean + */ + private function sectionDelChilds($sectionID) + { + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception(dgettext( + "domframework", + "Section not found" + ), 404); } - else - { - $prev = $h; - $prevCR = $headersSplit[$i+1]; + unset($this->sections[$sectionID]["_partsIDchild"]); + } + + /** Update the content of an existing section + * @param string $sectionID The section to modify + * @param array $param The parameters to update + */ + private function sectionUpdate($sectionID, $param) + { + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception( + dgettext("domframework", "Section not found"), + 404 + ); } - } - if ($prev !== "") - { - $exp = explode (": ", $prev, 2); - if (array_key_exists (1, $exp)) - { - list ($head, $value) = $exp; - $value .= $prevCR; - $headersArray[][$head] = $value; + if (! is_array($param)) { + throw new \Exception(dgettext( + "domframework", + "Param provided to sectionUpdate is not array" + ), 406); + } + foreach ($param as $key => $val) { + $this->sections[$sectionID][$key] = $val; } - } } - $contentType = $this->getHeaderValue ("Content-Type", $headersArray); - if ($contentType === false) - { - // If the mail doesn't provide a Content-Type header, it is then a raw - // text mail. Force the Content-Type to continue; - $contentType = "text/plain; charset=utf-8; format=flowed"; - } - $contentTypeArray = $this->contentTypeAnalyze ($contentType); - if (! isset ($contentTypeArray["Content-Type"])) - { - //throw new \Exception ("Can't parse the Content-Type", 500); - return; - } - $contentTransferEncoding = - $this->getHeaderValue ("Content-Transfer-Encoding", - $headersArray); - $charset = (isset ($contentTypeArray["charset"])) ? - $contentTypeArray["charset"] : false; - // Get the body - $pos = strpos ($content, $headerBodySeparator.$headerBodySeparator); - $contentEML = substr ($content, $pos + strlen ($headerBodySeparator) * 2); - if ($contentTransferEncoding === "quoted-printable") - $contentUTF = $this->encodingDecode ($contentEML, - $contentTransferEncoding); - elseif ($contentTransferEncoding === "base64") - $contentUTF = $this->encodingDecode ($contentEML, - $contentTransferEncoding); - else - $contentUTF = $contentEML; - if ($charset !== false) - $contentUTF = iconv ($charset, "utf-8", $contentUTF); - $res = array ("_headerBodySeparator"=>$headerBodySeparator, - "_headerCR"=>$prevCR, - "_headersEML"=>$headersEML, - "_headersArray"=>$headersArray, - "Content-Type"=>$contentType, - "_contentType"=>$contentTypeArray["Content-Type"], - "Content-Transfer-Encoding"=>$contentTransferEncoding, - "_contentEML"=>$contentEML, - "_contentUTF"=>$contentUTF); - preg_match ("#; name=['\"](.+)['\"]#", $contentType, $matches); - if (array_key_exists (1, $matches)) - $res["_name"] = $matches[1]; - if ($charset !== false) - $res["_charset"] = $charset; - $contentID = $this->getHeaderValue ("Content-ID", $headersArray); - if ($contentID !== false) - $res["Content-ID"] = $contentID; - return $res; - } - /** The constuctor verify if the external libraries are available - */ - public function __construct () - { - if (! function_exists ("finfo_buffer")) - throw new \Exception (dgettext ("domframework", - "Missing FileInfo PHP Extension"), 500); - if (! function_exists ("openssl_random_pseudo_bytes")) - throw new \Exception (dgettext ("domframework", - "Missing OpenSSL PHP Extension"), 500); - // Define default headers - $this->addHeader ("Date", date ("r")); - $this->addHeader ("Message-ID", $this->provideMessageID ()); - $user = posix_getpwuid (posix_geteuid()); - $this->addHeader ("From", $user["name"]."@".php_uname('n')); - $this->addHeader ("MIME-Version", "1.0"); - } + /** Get the list of sections ID + * @return array the defined sectionsID + */ + private function sectionList() + { + return array_keys($this->sections); + } - /** Define a HTML body. If the HTML body already exists, overwrite it - * If there is an text body, manage the boundary in alternative mode - * @param string $htmlContent in UTF-8 - * @param string $charset to be stored in the mail - * @param string $encoding the encoding in the mail - */ - public function setBodyHTML ($htmlContent, $charset="utf-8", - $encoding="quoted-printable") - { - // Look if there is an existing section with text (main or - // multipart/alternative) - $sectionList = $this->sectionList (); - $sectionIDtoChange = ""; - foreach ($sectionList as $sectionID) + /** Get the section ID List with parents ID + * @return array the defined sectionsID with the parent ID as value + */ + private function sectionListParent() { - $section = $this->sectionGet ($sectionID); - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/html") - { - $sectionIDtoChange = $sectionID; - break; - } + $res = array(); + foreach ($this->sections as $sectionID => $content) { + if (! array_key_exists("_parentID", $content)) { + $res[$sectionID] = ""; + } else { + $res[$sectionID] = $content["_parentID"]; + } + } + return $res; } - if ($sectionIDtoChange === "") - { - // No existing HTML section found : need to create one - // Check if the main section is empty to use it - $sectionMainID = $this->sectionMainID (); - if (!array_key_exists ("_contentType", - $this->sectionGet ($sectionMainID))) - { - $sectionIDtoChange = $sectionMainID; - } - } - if ($sectionIDtoChange === "") - { - // No existing HTML section found : need to create one - // Check if there is a multipart/related section without HTML to use - $sectionList = $this->sectionList (); - foreach ($sectionList as $sectionID) - { - $section = $this->sectionGet ($sectionID); - if (! array_key_exists ("_contentType", $section) || - array_key_exists ("_contentType", $section) && - $section["_contentType"] !== "multipart/related") - continue; - // Found ! $sectionID is a multipart/related section without HTML - $sectionIDtoChange = $this->sectionAddDefault (); - $this->sectionAddChildFirst ($sectionID, $sectionIDtoChange); - } - } - if ($sectionIDtoChange === "") - { - // No existing HTML section found : need to create one - // Check if there is an text part alone (to be pushed in - // multipart/alternative) - foreach ($sectionList as $sectionID) - { - $section = $this->sectionGet ($sectionID); - if (! array_key_exists ("_contentType", $section) || - $section["_contentType"] !== "text/plain") - continue; - // Found ! $sectionID is text/plain section - // Create a multipart/alternative section - // Move the text section in the multipart/alternative section - $boundary = $this->getBoundary (); - $multiID = $this->sectionAddDefault(); - $this->moveChilds ($multiID); - $this->addHeader ("Content-Type", "multipart/alternative;\r\n". - " boundary=$boundary\r\n", - $multiID); - $this->sectionUpdate ($multiID, - array ("_contentType"=>"multipart/alternative", - "_boundary"=>$boundary, - "_boundaryCR"=>"\r\n", - )); - // Add a HTML section in the multipart/alternative section after the - // defined text section. - $sectionIDtoChange = $this->sectionAddDefault (); - $this->sectionAddChild ($multiID, $sectionIDtoChange); - } - } - if ($sectionIDtoChange === "") + /** Return the content array of the section + * @param string $sectionID The section ID to get + * @return array The content of the section + */ + private function sectionGet($sectionID) { - // No existing section found : need to create one - throw new \Exception (dgettext ("domframework", - "Can't find the place to store the HTML"), 500); + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception(dgettext( + "domframework", + "Section not found" + ), 404); + } + return $this->sections[$sectionID]; } - $htmlContent = iconv ("utf-8", $charset, $htmlContent); - $part["_charset"] = $charset; - $part["_contentType"] = "text/html"; - $this->setHeader ("Content-Transfer-Encoding", $encoding, - $sectionIDtoChange); - // TODO : Add $part["_contentUTF"] ? - $part["_contentEML"] = $this->encodingEncode ($htmlContent, $encoding)."\n"; - $this->setHeader ("Content-Type", "text/html; charset=$charset", - $sectionIDtoChange); - if (isset ($boundary)) $part["_boundary"] = $boundary; - if (isset ($boundaryCR)) $part["_boundaryCR"] = $boundaryCR; - $this->sectionUpdate ($sectionIDtoChange, $part); - $this->createMailEML (); - } - /** Add a Text body. If the text body already exists, overwrite it - * If there is an HTML body, manage the boundary in alternative mode - * @param string $textContent in UTF-8 - * @param string $charset to be stored in the mail - * @param string $encoding the encoding in the mail - */ - public function setBodyText ($textContent, $charset="utf-8", - $encoding="quoted-printable") - { - // Look if there is an existing section with text (main or - // multipart/alternative) - $sectionList = $this->sectionList (); - $sectionIDtoChange = ""; - foreach ($sectionList as $sectionID) + /** Get the section ID of the main part + * @return bool|string the section ID of the main part or FALSE if not found + */ + public function sectionMainID() { - $section = $this->sectionGet ($sectionID); - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/plain") - { - $sectionIDtoChange = $sectionID; - break; - } + foreach ($this->sectionListParent() as $sectionID => $parentID) { + if ($parentID === "") { + return $sectionID; + } + } + return false; } - if ($sectionIDtoChange === "") - { - // No existing section found : need to create one - // Check if the main section is empty to use it - $sectionMainID = $this->sectionMainID (); - if (!array_key_exists ("_contentType", - $this->sectionGet ($sectionMainID))) - { - $sectionIDtoChange = $sectionMainID; - } - } - if ($sectionIDtoChange === "") - { - // No existing section found : need to create one - // Check if there is an html part alone (to be pushed in - // multipart/alternative) - foreach ($sectionList as $sectionID) - { - $section = $this->sectionGet ($sectionID); - if (! array_key_exists ("_contentType", $section) || - $section["_contentType"] !== "text/html") - continue; - $sectionIDhtml = $sectionID; - // Found ! $sectionID is text/html section - // Create a multipart/alternative section - // Move the text section in the multipart/alternative section - $boundary = $this->getBoundary (); - $multiID = $this->sectionAddDefault(); - $this->moveChilds ($multiID); - $this->addHeader ("Content-Type", "multipart/alternative;\r\n". - " boundary=$boundary\r\n", - $multiID); - $this->sectionUpdate ($multiID, - array ("_contentType"=>"multipart/alternative", - "_boundary"=>$boundary, - "_boundaryCR"=>"\r\n", - )); - // Add a HTML section in the multipart/alternative section - $sectionIDtoChange = $this->sectionAddDefault (); - $this->sectionAddChildFirst ($multiID, $sectionIDtoChange); - } - } - if ($sectionIDtoChange === "") - { - // No existing section found : need to create one - throw new \Exception (dgettext ("domframework", - "Can't find the place to store the TEXT"), 500); - } - $textContent = iconv ("utf-8", $charset, $textContent); - $part["_charset"] = $charset; - $part["_contentType"] = "text/plain"; - $this->setHeader ("Content-Transfer-Encoding", $encoding, - $sectionIDtoChange); - $part["_contentEML"] = $this->encodingEncode ($textContent, $encoding)."\n"; - $part["_contentUTF"] = $textContent; - $this->setHeader ("Content-Type", "text/plain; charset=$charset", - $sectionIDtoChange); - if (isset ($boundary)) $part["_boundary"] = $boundary; - if (isset ($boundaryCR)) $part["_boundaryCR"] = $boundaryCR; - $this->sectionUpdate ($sectionIDtoChange, $part); - $this->createMailEML (); - } - /** Return the HTML body if exists in UTF-8. If the body is not in UTF-8, it - * is converted - * Return false if it doesn't exists - * @return string|false The HTML body converted in UTF-8 or false if there is - * no HTML part in the mail - */ - public function getBodyHTML () - { - $sectionList = $this->sectionList (); - $sectionIDtoChange = ""; - foreach ($sectionList as $sectionID) + /** Refresh the _headersEML from the _headersArray + * @param string $sectionID the section to refresh + */ + private function sectionRefreshHeadersEML($sectionID) { - $section = $this->sectionGet ($sectionID); - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/html") - { - $encoding = $this->getHeaderValue ("Content-Transfer-Encoding", - $section["_headersArray"]); - $body = $this->encodingDecode ($section["_contentEML"], - $encoding); - return iconv ($section["_charset"], "UTF-8", $body); - } - } - return false; - } - - /** Get the text body if exists in UTF-8. If the body is not in UTF-8, it is - * converted - * Return false if it doesn't exists - * @return string|false The Text body converted in UTF-8 or false if there is - * no Text part in the mail - */ - public function getBodyText () - { - $sectionList = $this->sectionList (); - $sectionIDtoChange = ""; - foreach ($sectionList as $sectionID) - { - $section = $this->sectionGet ($sectionID); - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/plain") - { - $encoding = $this->getHeaderValue ("Content-Transfer-Encoding", - $section["_headersArray"]); - $body = $this->encodingDecode ($section["_contentEML"], - $encoding); - return iconv ($section["_charset"], "UTF-8", $body); - } - } - return false; - } - - /** Move the sections where the parent is defined to $oldParentID to the - * $newParentID. - * Move the headers from the valid sections to the newParent, except the - * Content-XX lines - * @param string $newParentID The Parent which will be modified - * @param string|null $oldParentID The oldParent to look for - */ - private function moveChilds ($newParentID, $oldParentID=false) - { - if ($newParentID === $oldParentID) - throw new \Exception ("moveChilds : old and new ParentID are the same", - 406); - foreach ($this->sections as $sectionID=>$section) - { - if ($newParentID === $sectionID) - continue; - if ((! isset ($section["_parentID"]) && $oldParentID === false) || - $oldParentID === $section["_parentID"]) - { - $this->sections[$sectionID]["_parentID"] = $newParentID; - $this->sections[$newParentID]["_partsIDchild"][] = $sectionID; - $multipartHeaders = array (); + $section = $this->sectionGet($sectionID); $headersEML = ""; - foreach ($section["_headersArray"] as $key=>$val) - { - $head = key ($val); - $value = $val[$head]; - if (substr ($head, 0, 8) !== "Content-") - { - $this->addHeader ($head, $value, $newParentID); - try - { - // Removing the Received: headers entries can only be done one - // time. An exception is raised, but it is not important - $this->delHeader ($head, $sectionID); - } - catch (\Exception $e) - { - } - } + foreach ($section["_headersArray"] as $val) { + $head = key($val); + $value = $val[$head]; + $headersEML .= "$head: $value"; } - } - else - { - // Section not attached to the wanted parent : skip it - } + $this->sections[$sectionID]["_headersEML"] = $headersEML; } - // Remove empty sections - foreach ($this->sections as $sectionID=>$section) + /** Read the complete mail to analyze + * Destroy all the previous definitions of mail + * @param string $content The complete mail to read + */ + public function readMail($content) { - if (count ($section["_headersArray"]) === 0 && - rtrim ($section["_headersEML"]) === "" && - rtrim ($section["_contentEML"]) === "") - { - if (array_key_exists ("_parentID", $section)) - { - foreach ($this->sections[$section["_parentID"]]["_partsIDchild"] as - $key=>$val) - if ($val === $sectionID) - unset ($this->sections[$section["_parentID"]]["_partsIDchild"][$key] - ); + $this->sections = array(); + $this->completeEmailEML = $content; + $partinfo = $this->parseMessagePart($content); + if ($partinfo !== null) { + $this->readMailContentRecurse($partinfo); } - unset ($this->sections[$sectionID]); - } } - } - /** Add an attachment to the mail. - * The allowed encodings are "quoted-printable" or "base64" - * @param string $name The name of the file - * @param string $fileContent The content of the file in binary - * @param string|null $encoding The output encoding. Can be - * base64/quoted-printable - * @param boolean|null $inline Store the file in inline mode - * (multipart/related) - * If false, store the file in attached mode (multipart/mixed) - */ - public function addAttachment ($name, $fileContent, $encoding="base64", - $inline=false) - { - if ($this->getBodyHTML() === false && $inline !== false) - $this->setBodyHTML ("No HTML provided by inline file added"); - // Look if there is a multipart/mixed where adding the new section. If not, - // create it - $multipart = ($inline === false) ? "multipart/mixed" : "multipart/related"; - $sectionList = $this->sectionList (); - $sectionIDMixed = ""; - foreach ($sectionList as $sectionID) + /** Read the content of the mail and allow the content to be also multipart. + * Then the method is recursively called to generate the sections + * @param array $partinfo The partinfo from parseMessagePart to analyze + * @param string|null $sectionIDParent The parent sectionID to link with + */ + private function readMailContentRecurse($partinfo, $sectionIDParent = false) { - $section = $this->sectionGet ($sectionID); - if (!array_key_exists ("_contentType", $section) || - array_key_exists ("_contentType", $section) && - $section["_contentType"] !== $multipart) - continue; - // Found a multipart/mixed. Will add the new attachment section to it - $sectionIDMixed = $sectionID; + if ( + key_exists("_contentType", $partinfo) && + substr($partinfo["_contentType"], 0, 10) === "multipart/" + ) { + // multipart/alternative, multipart/related, multipart/mixed + // Remove the content, as it is not valuable (will be stored in childs) + $tmp = $partinfo; + unset($tmp["_contentEML"]); + unset($tmp["_contentUTF"]); + if ($sectionIDParent === false) { + $sectionIDParent = $this->sectionAdd($tmp); + } + $boundaryArray = preg_split( + "#([\r\n]+)#", + $partinfo["_contentEML"], + null, + PREG_SPLIT_DELIM_CAPTURE + ); + // Remove the first 2 dashes : the boundary is stored like in the headers + $boundary = ""; + while (count($boundaryArray) > 0 && substr($boundary, 0, 2) !== "--") { + // Skip the lines until the coundary is found. The boundary start by -- + $boundary = array_shift($boundaryArray); + $boundaryCR = array_shift($boundaryArray); + } + if ($boundary === false) { + throw new \Exception(dgettext( + "domframework", + "Can't find boundary in multipart/" + ), 406); + } + $boundary = substr($boundary, 2); + unset($boundaryArray); + $this->sectionUpdate( + $sectionIDParent, + array("_boundary" => $boundary, + "_boundaryCR" => $boundaryCR) + ); + $parts = preg_split( + "#(--" . preg_quote($boundary) . "(--)?)([\r\n]+)#", + $partinfo["_contentEML"], + null, + PREG_SPLIT_DELIM_CAPTURE + ); + for ($i = 0; $i < count($parts); $i = $i + 4) { + if ($parts[$i] === "") { + continue; + } + $messagePart = $this->parseMessagePart($parts[$i]); + if ( + $messagePart === null || + ! array_key_exists("_contentType", $messagePart) + ) { + continue; + } + $messagePart["_parentID"] = $sectionIDParent; + $sectionIDChild = $this->sectionAdd($messagePart); + $this->sectionAddChild($sectionIDParent, $sectionIDChild); + if (substr($messagePart["_contentType"], 0, 10) === "multipart/") { + // Recursive part : multipart in multipart + unset($this->sections[$sectionIDChild]["_contentEML"]); + unset($this->sections[$sectionIDChild]["_contentUTF"]); + $this->readMailContentRecurse($messagePart, $sectionIDChild); + } + } + } else { + $sectionIDParent = $this->sectionAdd($partinfo); + } } - if ($sectionIDMixed === "") + + /** Return the data for a part of the mail + * @param string $content The content of the mail to parse + * @return array The data content in the mail + */ + private function parseMessagePart($content) { - // No multipart/mixed. Need to create one - $headersEML = ""; - $sectionIDMixed = $this->sectionAddDefault (); - // Move all the existing sections in the new multipart/mixed - $this->moveChilds ($sectionIDMixed); - $boundary = $this->getBoundary (); - $this->addHeader ("Content-Type", "$multipart;\r\n". + // Get the HeaderBodySeparator + $pos = strpos($content, "\r\n\r\n"); + $headerBodySeparator = "\r\n"; + if ($pos === false) { + $pos = strpos($content, "\n\n"); + $headerBodySeparator = "\n"; + } + if ($pos === false) { + $pos = strpos($content, "\r\r"); + $headerBodySeparator = "\r"; + } + if ($pos === false) { + //throw new \Exception ("Can't find the header/body separator", 500); + return array("_contentEML" => $content); + } + // Get the headers + $headersEML = ltrim(substr($content, 0, $pos + + strlen($headerBodySeparator))); + $headersArray = array(); + if ($headersEML !== "" && $headersEML !== "--") { + $prev = ""; + $prevCR = ""; + $headersSplit = preg_split( + "#([\r\n]+)#", + $headersEML, + null, + PREG_SPLIT_DELIM_CAPTURE + ); + for ($i = 0; $i < count($headersSplit); $i = $i + 2) { + $h = $headersSplit[$i]; + if (! isset($headersSplit[$i + 1])) { + $headersSplit[$i + 1] = $headerBodySeparator; + } + if ($h === "" || $h === "--") { + continue; + } + if ($h[0] === " " || $h[0] === "\t") { + $prev .= $prevCR . $h; + $prevCR = $headersSplit[$i + 1]; + } elseif ($prev !== "") { + $exp = explode(": ", $prev, 2); + if (! array_key_exists(1, $exp)) { + //trigger_error ("Malformed mail provided: no section header", + // E_USER_NOTICE); + $prev = ""; + continue; + } + list($head, $value) = $exp; + $value .= $prevCR; + $headersArray[][$head] = $value; + $prev = $h; + $prevCR = $headersSplit[$i + 1]; + } else { + $prev = $h; + $prevCR = $headersSplit[$i + 1]; + } + } + if ($prev !== "") { + $exp = explode(": ", $prev, 2); + if (array_key_exists(1, $exp)) { + list($head, $value) = $exp; + $value .= $prevCR; + $headersArray[][$head] = $value; + } + } + } + $contentType = $this->getHeaderValue("Content-Type", $headersArray); + if ($contentType === false) { + // If the mail doesn't provide a Content-Type header, it is then a raw + // text mail. Force the Content-Type to continue; + $contentType = "text/plain; charset=utf-8; format=flowed"; + } + $contentTypeArray = $this->contentTypeAnalyze($contentType); + if (! isset($contentTypeArray["Content-Type"])) { + //throw new \Exception ("Can't parse the Content-Type", 500); + return; + } + $contentTransferEncoding = + $this->getHeaderValue( + "Content-Transfer-Encoding", + $headersArray + ); + $charset = (isset($contentTypeArray["charset"])) ? + $contentTypeArray["charset"] : false; + // Get the body + $pos = strpos($content, $headerBodySeparator . $headerBodySeparator); + $contentEML = substr($content, $pos + strlen($headerBodySeparator) * 2); + if ($contentTransferEncoding === "quoted-printable") { + $contentUTF = $this->encodingDecode( + $contentEML, + $contentTransferEncoding + ); + } elseif ($contentTransferEncoding === "base64") { + $contentUTF = $this->encodingDecode( + $contentEML, + $contentTransferEncoding + ); + } else { + $contentUTF = $contentEML; + } + if ($charset !== false) { + $contentUTF = iconv($charset, "utf-8", $contentUTF); + } + $res = array("_headerBodySeparator" => $headerBodySeparator, + "_headerCR" => $prevCR, + "_headersEML" => $headersEML, + "_headersArray" => $headersArray, + "Content-Type" => $contentType, + "_contentType" => $contentTypeArray["Content-Type"], + "Content-Transfer-Encoding" => $contentTransferEncoding, + "_contentEML" => $contentEML, + "_contentUTF" => $contentUTF); + preg_match("#; name=['\"](.+)['\"]#", $contentType, $matches); + if (array_key_exists(1, $matches)) { + $res["_name"] = $matches[1]; + } + if ($charset !== false) { + $res["_charset"] = $charset; + } + $contentID = $this->getHeaderValue("Content-ID", $headersArray); + if ($contentID !== false) { + $res["Content-ID"] = $contentID; + } + return $res; + } + + /** The constuctor verify if the external libraries are available + */ + public function __construct() + { + if (! function_exists("finfo_buffer")) { + throw new \Exception(dgettext( + "domframework", + "Missing FileInfo PHP Extension" + ), 500); + } + if (! function_exists("openssl_random_pseudo_bytes")) { + throw new \Exception(dgettext( + "domframework", + "Missing OpenSSL PHP Extension" + ), 500); + } + // Define default headers + $this->addHeader("Date", date("r")); + $this->addHeader("Message-ID", $this->provideMessageID()); + $user = posix_getpwuid(posix_geteuid()); + $this->addHeader("From", $user["name"] . "@" . php_uname('n')); + $this->addHeader("MIME-Version", "1.0"); + } + + /** Define a HTML body. If the HTML body already exists, overwrite it + * If there is an text body, manage the boundary in alternative mode + * @param string $htmlContent in UTF-8 + * @param string $charset to be stored in the mail + * @param string $encoding the encoding in the mail + */ + public function setBodyHTML( + $htmlContent, + $charset = "utf-8", + $encoding = "quoted-printable" + ) { + // Look if there is an existing section with text (main or + // multipart/alternative) + $sectionList = $this->sectionList(); + $sectionIDtoChange = ""; + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/html" + ) { + $sectionIDtoChange = $sectionID; + break; + } + } + if ($sectionIDtoChange === "") { + // No existing HTML section found : need to create one + // Check if the main section is empty to use it + $sectionMainID = $this->sectionMainID(); + if ( + !array_key_exists( + "_contentType", + $this->sectionGet($sectionMainID) + ) + ) { + $sectionIDtoChange = $sectionMainID; + } + } + if ($sectionIDtoChange === "") { + // No existing HTML section found : need to create one + // Check if there is a multipart/related section without HTML to use + $sectionList = $this->sectionList(); + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + ! array_key_exists("_contentType", $section) || + array_key_exists("_contentType", $section) && + $section["_contentType"] !== "multipart/related" + ) { + continue; + } + // Found ! $sectionID is a multipart/related section without HTML + $sectionIDtoChange = $this->sectionAddDefault(); + $this->sectionAddChildFirst($sectionID, $sectionIDtoChange); + } + } + if ($sectionIDtoChange === "") { + // No existing HTML section found : need to create one + // Check if there is an text part alone (to be pushed in + // multipart/alternative) + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + ! array_key_exists("_contentType", $section) || + $section["_contentType"] !== "text/plain" + ) { + continue; + } + // Found ! $sectionID is text/plain section + // Create a multipart/alternative section + // Move the text section in the multipart/alternative section + $boundary = $this->getBoundary(); + $multiID = $this->sectionAddDefault(); + $this->moveChilds($multiID); + $this->addHeader( + "Content-Type", + "multipart/alternative;\r\n" . + " boundary=$boundary\r\n", + $multiID + ); + $this->sectionUpdate( + $multiID, + array("_contentType" => "multipart/alternative", + "_boundary" => $boundary, + "_boundaryCR" => "\r\n", + ) + ); + + // Add a HTML section in the multipart/alternative section after the + // defined text section. + $sectionIDtoChange = $this->sectionAddDefault(); + $this->sectionAddChild($multiID, $sectionIDtoChange); + } + } + if ($sectionIDtoChange === "") { + // No existing section found : need to create one + throw new \Exception(dgettext( + "domframework", + "Can't find the place to store the HTML" + ), 500); + } + $htmlContent = iconv("utf-8", $charset, $htmlContent); + $part["_charset"] = $charset; + $part["_contentType"] = "text/html"; + $this->setHeader( + "Content-Transfer-Encoding", + $encoding, + $sectionIDtoChange + ); + // TODO : Add $part["_contentUTF"] ? + $part["_contentEML"] = $this->encodingEncode($htmlContent, $encoding) . "\n"; + $this->setHeader( + "Content-Type", + "text/html; charset=$charset", + $sectionIDtoChange + ); + if (isset($boundary)) { + $part["_boundary"] = $boundary; + } + if (isset($boundaryCR)) { + $part["_boundaryCR"] = $boundaryCR; + } + $this->sectionUpdate($sectionIDtoChange, $part); + $this->createMailEML(); + } + + /** Add a Text body. If the text body already exists, overwrite it + * If there is an HTML body, manage the boundary in alternative mode + * @param string $textContent in UTF-8 + * @param string $charset to be stored in the mail + * @param string $encoding the encoding in the mail + */ + public function setBodyText( + $textContent, + $charset = "utf-8", + $encoding = "quoted-printable" + ) { + // Look if there is an existing section with text (main or + // multipart/alternative) + $sectionList = $this->sectionList(); + $sectionIDtoChange = ""; + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/plain" + ) { + $sectionIDtoChange = $sectionID; + break; + } + } + if ($sectionIDtoChange === "") { + // No existing section found : need to create one + // Check if the main section is empty to use it + $sectionMainID = $this->sectionMainID(); + if ( + !array_key_exists( + "_contentType", + $this->sectionGet($sectionMainID) + ) + ) { + $sectionIDtoChange = $sectionMainID; + } + } + if ($sectionIDtoChange === "") { + // No existing section found : need to create one + // Check if there is an html part alone (to be pushed in + // multipart/alternative) + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + ! array_key_exists("_contentType", $section) || + $section["_contentType"] !== "text/html" + ) { + continue; + } + $sectionIDhtml = $sectionID; + // Found ! $sectionID is text/html section + // Create a multipart/alternative section + // Move the text section in the multipart/alternative section + $boundary = $this->getBoundary(); + $multiID = $this->sectionAddDefault(); + $this->moveChilds($multiID); + $this->addHeader( + "Content-Type", + "multipart/alternative;\r\n" . + " boundary=$boundary\r\n", + $multiID + ); + $this->sectionUpdate( + $multiID, + array("_contentType" => "multipart/alternative", + "_boundary" => $boundary, + "_boundaryCR" => "\r\n", + ) + ); + // Add a HTML section in the multipart/alternative section + $sectionIDtoChange = $this->sectionAddDefault(); + $this->sectionAddChildFirst($multiID, $sectionIDtoChange); + } + } + if ($sectionIDtoChange === "") { + // No existing section found : need to create one + throw new \Exception(dgettext( + "domframework", + "Can't find the place to store the TEXT" + ), 500); + } + $textContent = iconv("utf-8", $charset, $textContent); + $part["_charset"] = $charset; + $part["_contentType"] = "text/plain"; + $this->setHeader( + "Content-Transfer-Encoding", + $encoding, + $sectionIDtoChange + ); + $part["_contentEML"] = $this->encodingEncode($textContent, $encoding) . "\n"; + $part["_contentUTF"] = $textContent; + $this->setHeader( + "Content-Type", + "text/plain; charset=$charset", + $sectionIDtoChange + ); + if (isset($boundary)) { + $part["_boundary"] = $boundary; + } + if (isset($boundaryCR)) { + $part["_boundaryCR"] = $boundaryCR; + } + $this->sectionUpdate($sectionIDtoChange, $part); + $this->createMailEML(); + } + + /** Return the HTML body if exists in UTF-8. If the body is not in UTF-8, it + * is converted + * Return false if it doesn't exists + * @return string|false The HTML body converted in UTF-8 or false if there is + * no HTML part in the mail + */ + public function getBodyHTML() + { + $sectionList = $this->sectionList(); + $sectionIDtoChange = ""; + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/html" + ) { + $encoding = $this->getHeaderValue( + "Content-Transfer-Encoding", + $section["_headersArray"] + ); + $body = $this->encodingDecode( + $section["_contentEML"], + $encoding + ); + return iconv($section["_charset"], "UTF-8", $body); + } + } + return false; + } + + /** Get the text body if exists in UTF-8. If the body is not in UTF-8, it is + * converted + * Return false if it doesn't exists + * @return string|false The Text body converted in UTF-8 or false if there is + * no Text part in the mail + */ + public function getBodyText() + { + $sectionList = $this->sectionList(); + $sectionIDtoChange = ""; + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/plain" + ) { + $encoding = $this->getHeaderValue( + "Content-Transfer-Encoding", + $section["_headersArray"] + ); + $body = $this->encodingDecode( + $section["_contentEML"], + $encoding + ); + return iconv($section["_charset"], "UTF-8", $body); + } + } + return false; + } + + /** Move the sections where the parent is defined to $oldParentID to the + * $newParentID. + * Move the headers from the valid sections to the newParent, except the + * Content-XX lines + * @param string $newParentID The Parent which will be modified + * @param string|null $oldParentID The oldParent to look for + */ + private function moveChilds($newParentID, $oldParentID = false) + { + if ($newParentID === $oldParentID) { + throw new \Exception( + "moveChilds : old and new ParentID are the same", + 406 + ); + } + foreach ($this->sections as $sectionID => $section) { + if ($newParentID === $sectionID) { + continue; + } + if ( + (! isset($section["_parentID"]) && $oldParentID === false) || + $oldParentID === $section["_parentID"] + ) { + $this->sections[$sectionID]["_parentID"] = $newParentID; + $this->sections[$newParentID]["_partsIDchild"][] = $sectionID; + $multipartHeaders = array(); + $headersEML = ""; + foreach ($section["_headersArray"] as $key => $val) { + $head = key($val); + $value = $val[$head]; + if (substr($head, 0, 8) !== "Content-") { + $this->addHeader($head, $value, $newParentID); + try { + // Removing the Received: headers entries can only be done one + // time. An exception is raised, but it is not important + $this->delHeader($head, $sectionID); + } catch (\Exception $e) { + } + } + } + } else { + // Section not attached to the wanted parent : skip it + } + } + + // Remove empty sections + foreach ($this->sections as $sectionID => $section) { + if ( + count($section["_headersArray"]) === 0 && + rtrim($section["_headersEML"]) === "" && + rtrim($section["_contentEML"]) === "" + ) { + if (array_key_exists("_parentID", $section)) { + foreach ( + $this->sections[$section["_parentID"]]["_partsIDchild"] as $key => $val + ) { + if ($val === $sectionID) { + unset($this->sections[$section["_parentID"]]["_partsIDchild"][$key]); + } + } + } + unset($this->sections[$sectionID]); + } + } + } + + /** Add an attachment to the mail. + * The allowed encodings are "quoted-printable" or "base64" + * @param string $name The name of the file + * @param string $fileContent The content of the file in binary + * @param string|null $encoding The output encoding. Can be + * base64/quoted-printable + * @param boolean|null $inline Store the file in inline mode + * (multipart/related) + * If false, store the file in attached mode (multipart/mixed) + */ + public function addAttachment( + $name, + $fileContent, + $encoding = "base64", + $inline = false + ) { + if ($this->getBodyHTML() === false && $inline !== false) { + $this->setBodyHTML("No HTML provided by inline file added"); + } + // Look if there is a multipart/mixed where adding the new section. If not, + // create it + $multipart = ($inline === false) ? "multipart/mixed" : "multipart/related"; + $sectionList = $this->sectionList(); + $sectionIDMixed = ""; + foreach ($sectionList as $sectionID) { + $section = $this->sectionGet($sectionID); + if ( + !array_key_exists("_contentType", $section) || + array_key_exists("_contentType", $section) && + $section["_contentType"] !== $multipart + ) { + continue; + } + // Found a multipart/mixed. Will add the new attachment section to it + $sectionIDMixed = $sectionID; + } + if ($sectionIDMixed === "") { + // No multipart/mixed. Need to create one + $headersEML = ""; + $sectionIDMixed = $this->sectionAddDefault(); + // Move all the existing sections in the new multipart/mixed + $this->moveChilds($sectionIDMixed); + $boundary = $this->getBoundary(); + $this->addHeader( + "Content-Type", + "$multipart;\r\n" . " boundary=$boundary\r\n", - $sectionIDMixed); - $this->sectionUpdate ($sectionIDMixed, - array ("_contentType"=>$multipart, - "_boundary"=>$boundary, - "_boundaryCR"=>"\r\n", - )); - } - if ($sectionIDMixed === "") - { - throw new \Exception ( - "Can't find the multipart/mixed section to add an attachment"); - } - // Add the new section to the mixed section - $sectionID = $this->sectionAddDefault (); - $this->sectionAddChild ($sectionIDMixed, $sectionID); - $finfo = new \finfo(FILEINFO_MIME); - $mimetype = $finfo->buffer($fileContent); - $this->addHeader ("Content-Type", "$mimetype; name=\"". - str_replace ("\"", "=22", - $this->encodeHeaderStringWithPosition ($name, - "quoted-printable", - strlen ("Content-Type: $mimetype; name=")))."\"\r\n", - $sectionID); - if ($inline === false) - $this->addHeader ("Content-Disposition", "attachment; filename=\"". - str_replace ("\"", "=22", - $this->encodeHeaderStringWithPosition ($name, - "quoted-printable", - strlen ("Content-Disposition: attachment; ". - "filename="))). + $sectionIDMixed + ); + $this->sectionUpdate( + $sectionIDMixed, + array("_contentType" => $multipart, + "_boundary" => $boundary, + "_boundaryCR" => "\r\n", + ) + ); + } + if ($sectionIDMixed === "") { + throw new \Exception( + "Can't find the multipart/mixed section to add an attachment" + ); + } + // Add the new section to the mixed section + $sectionID = $this->sectionAddDefault(); + $this->sectionAddChild($sectionIDMixed, $sectionID); + $finfo = new \finfo(FILEINFO_MIME); + $mimetype = $finfo->buffer($fileContent); + $this->addHeader( + "Content-Type", + "$mimetype; name=\"" . + str_replace( + "\"", + "=22", + $this->encodeHeaderStringWithPosition( + $name, + "quoted-printable", + strlen("Content-Type: $mimetype; name=") + ) + ) . "\"\r\n", + $sectionID + ); + if ($inline === false) { + $this->addHeader( + "Content-Disposition", + "attachment; filename=\"" . + str_replace( + "\"", + "=22", + $this->encodeHeaderStringWithPosition( + $name, + "quoted-printable", + strlen("Content-Disposition: attachment; " . + "filename=") + ) + ) . "\"\r\n", - $sectionID); - else - { - $this->addHeader ("Content-Disposition", "inline; filename=". - str_replace ("\"", "=22", - $this->encodeHeaderStringWithPosition ($name, - "quoted-printable", - strlen ("Content-Disposition: inline; filename=") - ))."\r\n", - $sectionID); - $contentID = $this->provideMessageID (); - $this->addHeader ("Content-ID", "$contentID\r\n", $sectionID); - } - $this->addHeader ("Content-Transfer-Encoding", "$encoding\r\n", $sectionID); - $part["_name"] = $name; - $part["_contentEML"] = $this->encodingEncode ($fileContent, $encoding); - $part["_mimetype"] = $mimetype; - $part["_sizeReal"] = strlen ($fileContent); - $this->sectionUpdate ($sectionID, $part); - $this->createMailEML (); - if ($inline === true) - return substr ($contentID, 1, -1); - } - - /** Add an inline attachment to the mail. - * The allowed encodings are "quoted-printable" or "base64" - * Return the Content-ID needed to be used in HTML page like : - * - * @param string $name The name of the file - * @param string $fileContent The content of the file in binary - * @param string|null $encoding The output encoding. Can be - * base64/quoted-printable - * @return string The content ID created - */ - public function addAttachmentInline ($name, $fileContent, $encoding="base64") - { - return $this->addAttachment ($name, $fileContent, $encoding, true); - } - - /** Get an attachment of the mail - * @param integer $number the number of attach to get starting to 0 - * @param boolean|null $inline Return only the attachments Inline if true - * @return string the content of the attachment. Can be binary - */ - public function getAttachment ($number, $inline = false) - { - $attachmentIDs = $this->getAttachmentID ($inline); - if (! array_key_exists ($number, $attachmentIDs)) - throw new \Exception (sprintf (dgettext ("domframework", - "Attachment '%d' not found"), $number), 404); - $part = $this->sectionGet ($attachmentIDs[$number]); - $encoding = $this->getHeaderValue ("Content-Transfer-Encoding", - $part["_headersArray"]); - return $this->encodingDecode ($part["_contentEML"], $encoding); - } - - /** Get the attachment details - * @param integer $number the number of attach to get starting to 0 - * @param boolean|null $inline Return only the attachments Inline if true - * @return array containing the information of the attachment - */ - public function getAttachmentDetails ($number, $inline = false) - { - $attachmentIDs = $this->getAttachmentID ($inline); - if (! array_key_exists ($number, $attachmentIDs)) - throw new \Exception (sprintf (dgettext ("domframework", - "Attachment '%d' not found"), $number), 404); - $part = $this->sectionGet ($attachmentIDs[$number]); - foreach ($part as $key=>$val) - { - if ($key[0] === "_") - { - if ($key !== "_contentEML" && $key !== "_contentUTF" && - $key !== "_parentID" && $key !== "_headersArray" && - $key !== "_headersEML" && $key !== "_headerCR" && - $key !== "_headerBodySeparator") - $res[substr ($key, 1)] = $val; - } - else - $res[$key] = $val; - } - return $res; - } - - /** Return the list of the sectionID containing a attachment. Contains the - * inline attachments too. - * @param boolean $inline Return only the sections Inline if true - * @return array The sectionIDs - */ - private function getAttachmentID ($inline = false) - { - $res = array (); - foreach ($this->sections as $sectionID=>$section) - { - if (! key_exists ("_headersArray", $section)) - continue; - $disposition = $this->getHeaderValue ("Content-Disposition", - $section["_headersArray"]); - if ($disposition !== false) - { - if ($inline === true && substr ($disposition, 0, 6) === "inline") - $res[] = $sectionID; - elseif ($inline === false && - substr ($disposition, 0, 10) === "attachment") - $res[] = $sectionID; - continue; - } - // The Mailer-Daemons use Content-Type: message/XXXX - $contentType = $this->getHeaderValue ("Content-Type", - $section["_headersArray"]); - if ($contentType !== false && substr ($contentType, 0, 8) === "message/") - { - if ($inline === false) - $res[] = $sectionID; - } - } - return $res; - } - - /** Add a To: header. If it already exists, add a new recipient - * @param string $toMail The mail to add - * @param string|null $toName The name of the recipient - */ - public function addTo ($toMail, $toName = "") - { - if (strspn ($toName, "abcdefghijklmnopqrstuvwxyz". - "ABCDEFGHIJKLMNOPQRSTUVWXYZ". - "0123456789 -_") !== strlen ($toName)) - $toName = $this->encodeHeaders ("To", $toName, - "quoted-printable"); - if ($toName !== "") - $toName .= " "; - $toField = "$toName<$toMail>"; - $oldTo = $this->getTo (); - if ($oldTo !== false) - $this->setHeader ("To", rtrim ($oldTo).",\r\n $toField"); - else - $this->setHeader ("To", $toField); - } - - /** Get the To Header as it is written in the mail - * @return string The To Header defined in the mail - */ - public function getTo () - { - return $this->getHeader ("To"); - } - - /** Add a From: header. If it already exists, overwrite the existing one - * @param string $fromMail The from Mail to define - * @param string|null $fromName The from Name to define - */ - public function setFrom ($fromMail, $fromName= "") - { - if (strspn ($fromName, "abcdefghijklmnopqrstuvwxyz". - "ABCDEFGHIJKLMNOPQRSTUVWXYZ". - "0123456789 -_") !== strlen ($fromName)) - $fromName = $this->encodeHeaders ("From", $fromName, - "quoted-printable"); - if ($fromName !== "") - $fromName .= " "; - $this->setHeader ("From", "$fromName<$fromMail>"); - } - - /** Return the From header as it is written in the mail - * @return string The From Header defined in the mail - */ - public function getFrom () - { - return $this->getHeader ("From"); - } - - /** Return the From header converted to array with mail and name keys - * @return array The From details - */ - public function getFromArray () - { - $from = $this->getHeader ("From"); - $res = array (); - $from = $this->decodeHeaders ("From", $from); - $from = $this->convertPeopleToArray ($from); - return reset ($from); - } - - /** Set the subject - * @param string $subject In UTF8 - */ - public function setSubject ($subject) - { - $this->setHeader ("Subject", - $this->encodeHeaders ("Subject", $subject, - "quoted-printable")); - } - - /** Set the Date - * @param string $date In RFC 2822 format - */ - public function setDate ($date) - { - // TODO : Check if the date format is valid - $this->setHeader ("Date", $date); - } - - /** Set the Date - * @param string $timestamp In Timestamp format - */ - public function setDateTimestamp ($timestamp) - { - // TODO : Check if the timestamp is valid - $this->setHeader ("Date", date ("r", $timestamp)); - } - - /** Get the Date header if defined. - * Return false if not defined - * @return string|bool The date Header if defined or false if not defined - */ - public function getDate () - { - return $this->getHeader ("Date"); - } - - /** Return the Date header (if defined) in timestamp - * Return false if not defined - * @return integer|bool The date Header if defined or false if not defined - */ - public function getDateTimestamp () - { - $datetimestamp = false; - $date = rtrim ($this->getDate ()); - if ($date !== false) - { - $dateTimestamp = \DateTime::createFromFormat (\DateTime::RFC2822, - $date); - if ($dateTimestamp === false) - $dateTimestamp = \DateTime::createFromFormat (\DateTime::RFC822, - $date); - if ($dateTimestamp !== false) - $dateTimestamp = $dateTimestamp->getTimestamp(); - } - return $dateTimestamp; - } - - /** Set a generic header - * @param string $header The name of the Header (without colon) - * @param string $value The value the store. The format must be correct ! - * @param string|null $sectionID The section to modify. If null, use the main - */ - public function setHeader ($header, $value, $sectionID=null) - { - if (substr ($value, -1) !== "\n" && - substr ($value, -1) !== "\r" && - substr ($value, -2) !== "\r\n") - $value .= "\r\n"; - if ($sectionID === null) - { - $sectionMainID = $this->sectionMainID (); - if ($sectionMainID === false) - $sectionMainID = $this->sectionAddDefault (); - } - else - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception ("Wanted section not found in setHeader", 404); - $sectionMainID = $sectionID; + $sectionID + ); + } else { + $this->addHeader( + "Content-Disposition", + "inline; filename=" . + str_replace( + "\"", + "=22", + $this->encodeHeaderStringWithPosition( + $name, + "quoted-printable", + strlen("Content-Disposition: inline; filename=") + ) + ) . "\r\n", + $sectionID + ); + $contentID = $this->provideMessageID(); + $this->addHeader("Content-ID", "$contentID\r\n", $sectionID); + } + $this->addHeader("Content-Transfer-Encoding", "$encoding\r\n", $sectionID); + $part["_name"] = $name; + $part["_contentEML"] = $this->encodingEncode($fileContent, $encoding); + $part["_mimetype"] = $mimetype; + $part["_sizeReal"] = strlen($fileContent); + $this->sectionUpdate($sectionID, $part); + $this->createMailEML(); + if ($inline === true) { + return substr($contentID, 1, -1); + } } - $found = false; - foreach ($this->sections[$sectionMainID]["_headersArray"] as $key=>$val) + /** Add an inline attachment to the mail. + * The allowed encodings are "quoted-printable" or "base64" + * Return the Content-ID needed to be used in HTML page like : + * + * @param string $name The name of the file + * @param string $fileContent The content of the file in binary + * @param string|null $encoding The output encoding. Can be + * base64/quoted-printable + * @return string The content ID created + */ + public function addAttachmentInline($name, $fileContent, $encoding = "base64") { - $head = key ($val); - if ($head === $header) - { - $this->sections[$sectionMainID]["_headersArray"][$key][$header] = + return $this->addAttachment($name, $fileContent, $encoding, true); + } + + /** Get an attachment of the mail + * @param integer $number the number of attach to get starting to 0 + * @param boolean|null $inline Return only the attachments Inline if true + * @return string the content of the attachment. Can be binary + */ + public function getAttachment($number, $inline = false) + { + $attachmentIDs = $this->getAttachmentID($inline); + if (! array_key_exists($number, $attachmentIDs)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Attachment '%d' not found" + ), $number), 404); + } + $part = $this->sectionGet($attachmentIDs[$number]); + $encoding = $this->getHeaderValue( + "Content-Transfer-Encoding", + $part["_headersArray"] + ); + return $this->encodingDecode($part["_contentEML"], $encoding); + } + + /** Get the attachment details + * @param integer $number the number of attach to get starting to 0 + * @param boolean|null $inline Return only the attachments Inline if true + * @return array containing the information of the attachment + */ + public function getAttachmentDetails($number, $inline = false) + { + $attachmentIDs = $this->getAttachmentID($inline); + if (! array_key_exists($number, $attachmentIDs)) { + throw new \Exception(sprintf(dgettext( + "domframework", + "Attachment '%d' not found" + ), $number), 404); + } + $part = $this->sectionGet($attachmentIDs[$number]); + foreach ($part as $key => $val) { + if ($key[0] === "_") { + if ( + $key !== "_contentEML" && $key !== "_contentUTF" && + $key !== "_parentID" && $key !== "_headersArray" && + $key !== "_headersEML" && $key !== "_headerCR" && + $key !== "_headerBodySeparator" + ) { + $res[substr($key, 1)] = $val; + } + } else { + $res[$key] = $val; + } + } + return $res; + } + + /** Return the list of the sectionID containing a attachment. Contains the + * inline attachments too. + * @param boolean $inline Return only the sections Inline if true + * @return array The sectionIDs + */ + private function getAttachmentID($inline = false) + { + $res = array(); + foreach ($this->sections as $sectionID => $section) { + if (! key_exists("_headersArray", $section)) { + continue; + } + $disposition = $this->getHeaderValue( + "Content-Disposition", + $section["_headersArray"] + ); + if ($disposition !== false) { + if ($inline === true && substr($disposition, 0, 6) === "inline") { + $res[] = $sectionID; + } elseif ( + $inline === false && + substr($disposition, 0, 10) === "attachment" + ) { + $res[] = $sectionID; + } + continue; + } + // The Mailer-Daemons use Content-Type: message/XXXX + $contentType = $this->getHeaderValue( + "Content-Type", + $section["_headersArray"] + ); + if ($contentType !== false && substr($contentType, 0, 8) === "message/") { + if ($inline === false) { + $res[] = $sectionID; + } + } + } + return $res; + } + + /** Add a To: header. If it already exists, add a new recipient + * @param string $toMail The mail to add + * @param string|null $toName The name of the recipient + */ + public function addTo($toMail, $toName = "") + { + if ( + strspn($toName, "abcdefghijklmnopqrstuvwxyz" . + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . + "0123456789 -_") !== strlen($toName) + ) { + $toName = $this->encodeHeaders( + "To", + $toName, + "quoted-printable" + ); + } + if ($toName !== "") { + $toName .= " "; + } + $toField = "$toName<$toMail>"; + $oldTo = $this->getTo(); + if ($oldTo !== false) { + $this->setHeader("To", rtrim($oldTo) . ",\r\n $toField"); + } else { + $this->setHeader("To", $toField); + } + } + + /** Get the To Header as it is written in the mail + * @return string The To Header defined in the mail + */ + public function getTo() + { + return $this->getHeader("To"); + } + + /** Add a From: header. If it already exists, overwrite the existing one + * @param string $fromMail The from Mail to define + * @param string|null $fromName The from Name to define + */ + public function setFrom($fromMail, $fromName = "") + { + if ( + strspn($fromName, "abcdefghijklmnopqrstuvwxyz" . + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . + "0123456789 -_") !== strlen($fromName) + ) { + $fromName = $this->encodeHeaders( + "From", + $fromName, + "quoted-printable" + ); + } + if ($fromName !== "") { + $fromName .= " "; + } + $this->setHeader("From", "$fromName<$fromMail>"); + } + + /** Return the From header as it is written in the mail + * @return string The From Header defined in the mail + */ + public function getFrom() + { + return $this->getHeader("From"); + } + + /** Return the From header converted to array with mail and name keys + * @return array The From details + */ + public function getFromArray() + { + $from = $this->getHeader("From"); + $res = array(); + $from = $this->decodeHeaders("From", $from); + $from = $this->convertPeopleToArray($from); + return reset($from); + } + + /** Set the subject + * @param string $subject In UTF8 + */ + public function setSubject($subject) + { + $this->setHeader( + "Subject", + $this->encodeHeaders( + "Subject", + $subject, + "quoted-printable" + ) + ); + } + + /** Set the Date + * @param string $date In RFC 2822 format + */ + public function setDate($date) + { + // TODO : Check if the date format is valid + $this->setHeader("Date", $date); + } + + /** Set the Date + * @param string $timestamp In Timestamp format + */ + public function setDateTimestamp($timestamp) + { + // TODO : Check if the timestamp is valid + $this->setHeader("Date", date("r", $timestamp)); + } + + /** Get the Date header if defined. + * Return false if not defined + * @return string|bool The date Header if defined or false if not defined + */ + public function getDate() + { + return $this->getHeader("Date"); + } + + /** Return the Date header (if defined) in timestamp + * Return false if not defined + * @return integer|bool The date Header if defined or false if not defined + */ + public function getDateTimestamp() + { + $datetimestamp = false; + $date = rtrim($this->getDate()); + if ($date !== false) { + $dateTimestamp = \DateTime::createFromFormat( + \DateTime::RFC2822, + $date + ); + if ($dateTimestamp === false) { + $dateTimestamp = \DateTime::createFromFormat( + \DateTime::RFC822, + $date + ); + } + if ($dateTimestamp !== false) { + $dateTimestamp = $dateTimestamp->getTimestamp(); + } + } + return $dateTimestamp; + } + + /** Set a generic header + * @param string $header The name of the Header (without colon) + * @param string $value The value the store. The format must be correct ! + * @param string|null $sectionID The section to modify. If null, use the main + */ + public function setHeader($header, $value, $sectionID = null) + { + if ( + substr($value, -1) !== "\n" && + substr($value, -1) !== "\r" && + substr($value, -2) !== "\r\n" + ) { + $value .= "\r\n"; + } + if ($sectionID === null) { + $sectionMainID = $this->sectionMainID(); + if ($sectionMainID === false) { + $sectionMainID = $this->sectionAddDefault(); + } + } else { + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception("Wanted section not found in setHeader", 404); + } + $sectionMainID = $sectionID; + } + + $found = false; + foreach ($this->sections[$sectionMainID]["_headersArray"] as $key => $val) { + $head = key($val); + if ($head === $header) { + $this->sections[$sectionMainID]["_headersArray"][$key][$header] = $value; - $found = true; - } + $found = true; + } + } + if ($found === false) { + $this->sections[$sectionMainID]["_headersArray"][][$header] = $value; + } + // Re-create the _headersEML for the section + $_headerEML = ""; + foreach ($this->sections[$sectionMainID]["_headersArray"] as $val) { + $head = key($val); + $value = $val[$head]; + $_headerEML .= "$head: $value"; + } + $this->sections[$sectionMainID]["_headersEML"] = $_headerEML; + $this->createMailEML(); } - if ($found === false) - $this->sections[$sectionMainID]["_headersArray"][][$header] = $value; - // Re-create the _headersEML for the section - $_headerEML = ""; - foreach ($this->sections[$sectionMainID]["_headersArray"] as $val) - { - $head = key ($val); - $value = $val[$head]; - $_headerEML .= "$head: $value"; - } - $this->sections[$sectionMainID]["_headersEML"] = $_headerEML; - $this->createMailEML (); - } - /** Add a generic header - * @param string $header The name of the Header (without colon) - * @param string $value The value the store. The format must be correct ! - * @param string|null $sectionID The section to modify. If null, use the main - */ - public function addHeader ($header, $value, $sectionID=null) - { - if (substr ($value, -1) !== "\n" && - substr ($value, -1) !== "\r" && - substr ($value, -2) !== "\r\n") - $value .= "\r\n"; - if ($sectionID === null) + /** Add a generic header + * @param string $header The name of the Header (without colon) + * @param string $value The value the store. The format must be correct ! + * @param string|null $sectionID The section to modify. If null, use the main + */ + public function addHeader($header, $value, $sectionID = null) { - $sectionMainID = $this->sectionMainID (); - if ($sectionMainID === false) - $sectionMainID = $this->sectionAddDefault (); + if ( + substr($value, -1) !== "\n" && + substr($value, -1) !== "\r" && + substr($value, -2) !== "\r\n" + ) { + $value .= "\r\n"; + } + if ($sectionID === null) { + $sectionMainID = $this->sectionMainID(); + if ($sectionMainID === false) { + $sectionMainID = $this->sectionAddDefault(); + } + } else { + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception("Wanted section not found in addHeader", 404); + } + $sectionMainID = $sectionID; + } + if ($header === "Return-Path") { + // Must be placed on the first line and must be unique + reset($this->sections[$sectionMainID]["_headersArray"]); + if ( + key_exists(0, $this->sections[$sectionMainID]["_headersArray"]) && + key_exists( + "Return-Path", + $this->sections[$sectionMainID]["_headersArray"][0] + ) + ) { + // Remove the old one + array_shift($this->sections[$sectionMainID]["_headersArray"]); + $this->sections[$sectionMainID]["_headersEML"] = + substr( + $this->sections[$sectionMainID]["_headersEML"], + strpos($this->sections[$sectionMainID]["_headersEML"], "\n") + 1 + ); + } + array_unshift( + $this->sections[$sectionMainID]["_headersArray"], + array($header => $value) + ); + $this->sections[$sectionMainID]["_headersEML"] = "$header: $value" . + $this->sections[$sectionMainID]["_headersEML"]; + } else { + // The "normal" headers are places sequentially at the end of the headers + $this->sections[$sectionMainID]["_headersArray"][][$header] = $value; + // TODO : Encode ? Strip ? + $this->sections[$sectionMainID]["_headersEML"] .= "$header: $value"; + } + $this->createMailEML(); } - else - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception ("Wanted section not found in addHeader", 404); - $sectionMainID = $sectionID; - } - if ($header === "Return-Path") - { - // Must be placed on the first line and must be unique - reset ($this->sections[$sectionMainID]["_headersArray"]); - if (key_exists (0, $this->sections[$sectionMainID]["_headersArray"]) && - key_exists ("Return-Path", - $this->sections[$sectionMainID]["_headersArray"][0])) - { - // Remove the old one - array_shift ($this->sections[$sectionMainID]["_headersArray"]); - $this->sections[$sectionMainID]["_headersEML"] = - substr ($this->sections[$sectionMainID]["_headersEML"], - strpos ($this->sections[$sectionMainID]["_headersEML"], "\n") +1); - } - array_unshift ($this->sections[$sectionMainID]["_headersArray"], - array ($header => $value)); - $this->sections[$sectionMainID]["_headersEML"] = "$header: $value". - $this->sections[$sectionMainID]["_headersEML"]; - } - else - { - // The "normal" headers are places sequentially at the end of the headers - $this->sections[$sectionMainID]["_headersArray"][][$header] = $value; - // TODO : Encode ? Strip ? - $this->sections[$sectionMainID]["_headersEML"] .= "$header: $value"; - } - $this->createMailEML (); - } - /** Delete a specific header - * @param string $header The header to remove - * @param string|null $sectionID The section to modify. If null, use the main - */ - public function delHeader ($header, $sectionID=null) - { - if ($sectionID === null) + /** Delete a specific header + * @param string $header The header to remove + * @param string|null $sectionID The section to modify. If null, use the main + */ + public function delHeader($header, $sectionID = null) { - $sectionMainID = $this->sectionMainID (); - if ($sectionMainID === false) - $sectionMainID = $this->sectionAddDefault (); + if ($sectionID === null) { + $sectionMainID = $this->sectionMainID(); + if ($sectionMainID === false) { + $sectionMainID = $this->sectionAddDefault(); + } + } else { + if (! array_key_exists($sectionID, $this->sections)) { + throw new \Exception("Wanted section not found in delHeader", 404); + } + $sectionMainID = $sectionID; + } + $found = false; + foreach ($this->sections[$sectionMainID]["_headersArray"] as $key => $val) { + $head = key($val); + if ($head === $header) { + unset($this->sections[$sectionMainID]["_headersArray"][$key]); + $found = true; + } + } + if ($found === false) { + throw new \Exception(sprintf( + "Header to remove '%s' not found", + $header + ), 404); + } + // Re-create the _headersEML for the section + $_headerEML = ""; + foreach ($this->sections[$sectionMainID]["_headersArray"] as $val) { + $head = key($val); + $value = $val[$head]; + $_headerEML .= "$head: $value"; + } + $this->sections[$sectionMainID]["_headersEML"] = $_headerEML; + $this->createMailEML(); } - else - { - if (! array_key_exists ($sectionID, $this->sections)) - throw new \Exception ("Wanted section not found in delHeader", 404); - $sectionMainID = $sectionID; - } - $found = false; - foreach ($this->sections[$sectionMainID]["_headersArray"] as $key=>$val) - { - $head = key ($val); - if ($head === $header) - { - unset ($this->sections[$sectionMainID]["_headersArray"][$key]); - $found = true; - } - } - if ($found === false) - throw new \Exception (sprintf ("Header to remove '%s' not found", - $header), 404); - // Re-create the _headersEML for the section - $_headerEML = ""; - foreach ($this->sections[$sectionMainID]["_headersArray"] as $val) - { - $head = key ($val); - $value = $val[$head]; - $_headerEML .= "$head: $value"; - } - $this->sections[$sectionMainID]["_headersEML"] = $_headerEML; - $this->createMailEML (); - } - /** Get all the headers, in the order in EML. The format is - * [] => array ("header" => "value") - * @param array|null $headers The headers to examine - * @return array - */ - public function getHeaders ($headers=null) - { - $sectionMainID = $this->sectionMainID (); - if ($sectionMainID === false || - ! key_exists ("_headersArray", $this->sections[$sectionMainID])) - $headers = array (); - else - $headers = $this->sections[$sectionMainID]["_headersArray"]; - return $headers; - } - - /** Get a generic header - * If there is multiple headers with the same name, return the first - * @param string $header The header to get - * @param array|null $headers Optional headers to examine - * @return string|bool the literal value or false if it doesn't exist - */ - public function getHeader ($header, $headers=null) - { - $headers = $this->getHeaders ($headers); - foreach ($headers as $key=>$val) + /** Get all the headers, in the order in EML. The format is + * [] => array ("header" => "value") + * @param array|null $headers The headers to examine + * @return array + */ + public function getHeaders($headers = null) { - $head = key ($val); - $value = $val[$head]; - if ($head === $header) - return $value; + $sectionMainID = $this->sectionMainID(); + if ( + $sectionMainID === false || + ! key_exists("_headersArray", $this->sections[$sectionMainID]) + ) { + $headers = array(); + } else { + $headers = $this->sections[$sectionMainID]["_headersArray"]; + } + return $headers; } - return false; - } - /** Get a generic header with removing the carriage return - * If there is multiple headers with the same name, return the first - * @param string $header The header to get - * @param array $headers The _headersArray array - * @return string|bool the literal value or false if it doesn't exist - */ - public function getHeaderValue ($header, $headers=null) - { - $headers = $this->getHeaders ($headers); - foreach ($headers as $key=>$val) + /** Get a generic header + * If there is multiple headers with the same name, return the first + * @param string $header The header to get + * @param array|null $headers Optional headers to examine + * @return string|bool the literal value or false if it doesn't exist + */ + public function getHeader($header, $headers = null) { - $head = key ($val); - $value = $val[$head]; - if ($head === $header) - { - $value = preg_replace ("#[\r\n]+[ \t]+#", " ", $value); - if (substr ($value, -2) === "\r\n") - return substr ($value, 0, -2); - return substr ($value, 0, -1); - } + $headers = $this->getHeaders($headers); + foreach ($headers as $key => $val) { + $head = key($val); + $value = $val[$head]; + if ($head === $header) { + return $value; + } + } + return false; } - return false; - } - /** Create the complete mail structure - */ - public function createMailEML () - { - $complete = ""; - $this->recurse = 0; - foreach ($this->sectionListParent() as $sectionID=>$sectionParent) + /** Get a generic header with removing the carriage return + * If there is multiple headers with the same name, return the first + * @param string $header The header to get + * @param array $headers The _headersArray array + * @return string|bool the literal value or false if it doesn't exist + */ + public function getHeaderValue($header, $headers = null) { - if ($sectionParent !== "") - continue; - $part = $this->sectionGet ($sectionID); - $complete .= $part["_headersEML"]; - $complete .= $part["_headerBodySeparator"]; - if (array_key_exists ("_contentEML", $part)) - $complete.= $part["_contentEML"]; - $complete .= $this->createMailEMLSub ($part); + $headers = $this->getHeaders($headers); + foreach ($headers as $key => $val) { + $head = key($val); + $value = $val[$head]; + if ($head === $header) { + $value = preg_replace("#[\r\n]+[ \t]+#", " ", $value); + if (substr($value, -2) === "\r\n") { + return substr($value, 0, -2); + } + return substr($value, 0, -1); + } + } + return false; } - $this->completeEmailEML = $complete; - } - /** Recursive email EML creation for childs - * @param array $parent The parent array - */ - private function createMailEMLSub ($parent) - { - $this->recurse++; - if ($this->recurse > 120) - throw new \Exception ("Recurse createMailEMLSub > 120", 500); - if (!array_key_exists ("_partsIDchild", $parent)) - return ""; - $complete = ""; - foreach ($parent["_partsIDchild"] as $childID) + /** Create the complete mail structure + */ + public function createMailEML() { - $child = $this->sectionGet ($childID); - // The boundary is not defined in the child, but in the parent - if (array_key_exists ("_boundary", $parent)) - $complete .= "--".$parent["_boundary"].$parent["_boundaryCR"]; - if (array_key_exists ("_headersEML", $child)) - $complete .= $child["_headersEML"]; - if (array_key_exists ("_headerBodySeparator", $child)) - $complete .= $child["_headerBodySeparator"]; - $complete .= $this->createMailEMLSub ($child); - if (array_key_exists ("_contentEML", $child)) - $complete.= $child["_contentEML"]; + $complete = ""; + $this->recurse = 0; + foreach ($this->sectionListParent() as $sectionID => $sectionParent) { + if ($sectionParent !== "") { + continue; + } + $part = $this->sectionGet($sectionID); + $complete .= $part["_headersEML"]; + $complete .= $part["_headerBodySeparator"]; + if (array_key_exists("_contentEML", $part)) { + $complete .= $part["_contentEML"]; + } + $complete .= $this->createMailEMLSub($part); + } + $this->completeEmailEML = $complete; } - if (array_key_exists ("_boundary", $parent)) - $complete .= "--".$parent["_boundary"]."--".$parent["_boundaryCR"]; - return $complete; - } - /** Return the complete mail - * @return string The complete mail - */ - public function getMail () - { - if (trim ($this->getBodyHTML()) === "No HTML provided by inline file added") - throw new \Exception ("No HTML provided by inline file added", 500); - - return $this->completeEmailEML; - } - - /** Return an array with the details of the mail : - * the number of attachments, the from, to, subject in UTF-8, if there is - * a text and/or html body - * @return array The details of the mail - */ - public function getDetails () - { - $bodyTextExists = false; - $bodyHTMLExists = false; - $attachmentNb = count ($this->getAttachmentID ()); - $attachmentInlineNb = count ($this->getAttachmentID (true)); - foreach ($this->sections as $sectionID=>$section) + /** Recursive email EML creation for childs + * @param array $parent The parent array + */ + private function createMailEMLSub($parent) { - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/plain") - $bodyTextExists = true; - if (array_key_exists ("_contentType", $section) && - $section["_contentType"] === "text/html") - $bodyHTMLExists = true; + $this->recurse++; + if ($this->recurse > 120) { + throw new \Exception("Recurse createMailEMLSub > 120", 500); + } + if (!array_key_exists("_partsIDchild", $parent)) { + return ""; + } + $complete = ""; + foreach ($parent["_partsIDchild"] as $childID) { + $child = $this->sectionGet($childID); + // The boundary is not defined in the child, but in the parent + if (array_key_exists("_boundary", $parent)) { + $complete .= "--" . $parent["_boundary"] . $parent["_boundaryCR"]; + } + if (array_key_exists("_headersEML", $child)) { + $complete .= $child["_headersEML"]; + } + if (array_key_exists("_headerBodySeparator", $child)) { + $complete .= $child["_headerBodySeparator"]; + } + $complete .= $this->createMailEMLSub($child); + if (array_key_exists("_contentEML", $child)) { + $complete .= $child["_contentEML"]; + } + } + if (array_key_exists("_boundary", $parent)) { + $complete .= "--" . $parent["_boundary"] . "--" . $parent["_boundaryCR"]; + } + return $complete; } - unset ($sectionID); - unset ($section); - $attachmentDetails = array (); - $attachmentInlineDetails = array (); - for ($i = 0 ; $i < $attachmentNb ; $i ++) - $attachmentDetails[$i] = $this->getAttachmentDetails($i); - for ($i = 0 ; $i < $attachmentInlineNb ; $i ++) - $attachmentInlineDetails[$i] = $this->getAttachmentDetails($i, true); - unset ($i); - $size = strlen ($this->getMail()); - $from = trim ($this->getHeader ("From")); - if ($from !== false) - { - $fromArray = $this->convertPeopleToArray ( - $this->decodeHeaders ("From", $from)); - } - $to = trim ($this->getHeader ("To")); - if ($to !== false) - { - $toArray = $this->convertPeopleToArray ( - $this->decodeHeaders ("To", $to)); - } - $date = trim ($this->getDate ()); - $dateTimestamp = $this->getDateTimestamp (); - $subject = $this->decodeHeaders ("Subject", $this->getHeader ("Subject")); - return get_defined_vars(); - } - /** Create a boundary - * @return string the textual boundary - */ - private function getBoundary () - { - $data = openssl_random_pseudo_bytes (16); - $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 - $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 - return "-----".vsprintf ('%s%s%s%s%s%s%s%s', - str_split (bin2hex ($data), 4)); - } - - /** Create a messageID - * @return string the textual MessageID - */ - public function provideMessageID () - { - $data = openssl_random_pseudo_bytes (16); - $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 - $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 - return "<".vsprintf ('%s%s-%s-%s-%s-%s%s%s', - str_split (bin2hex ($data), 4))."@". - php_uname('n').">"; - } - - /** Convert the content to correct encoding. - * The allowed encodings are "quoted-printable" or "base64" or "flowed" - * Cut the long lines to 76 chars with the correct separator - * @param string $content The content to encode - * @param string $encoding The encoding to use - * @return string the content encoded by $encoding - */ - private function encodingEncode ($content, $encoding) - { - if ($encoding === "quoted-printable") + /** Return the complete mail + * @return string The complete mail + */ + public function getMail() { - $tmp = quoted_printable_encode ($content); - return $tmp; - } - elseif ($encoding === "base64") - { - $tmp = base64_encode ($content); - return chunk_split ($tmp); - } - elseif ($encoding === "flowed") - { - return chunk_split ($content); - } - throw new \Exception (sprintf ( - dgettext ("domframework", - "Invalid encoding provided to encodingEncode : %s"), $encoding), 500); - } + if (trim($this->getBodyHTML()) === "No HTML provided by inline file added") { + throw new \Exception("No HTML provided by inline file added", 500); + } - /** Decode the content with correct encoding. - * The allowed encodings are "quoted-printable" or "base64" or "8bit" - * @param string $content The content to decode - * @param string $encoding The encoding to use - * @return the content decoded by $encoding - */ - private function encodingDecode ($content, $encoding) - { - if ($encoding === "quoted-printable") - return quoted_printable_decode ($content); - elseif ($encoding === "base64") - return base64_decode ($content); - elseif ($encoding === "8bit" || $encoding === "7bit" || $encoding === false) - return $content; - throw new \Exception (sprintf ( - dgettext ("domframework", - "Invalid encoding provided to encodingDecode : '%s'"), $encoding), 500); - } + return $this->completeEmailEML; + } - /** Encode a string to be compliant with MIME (used in headers) - * @param string $header The header to be used. Will not be returned, but the - * length of the result will be adapted to it - * @param string $content The content to encode - * @param string $encoding The encoding to use. - * The allowed encodings are "quoted-printable" or "base64" - * @return string the content encoded by $encoding - */ - private function encodeHeaders ($header, $content, $encoding) - { - $prefs = array ("input-charset" => "utf-8", + /** Return an array with the details of the mail : + * the number of attachments, the from, to, subject in UTF-8, if there is + * a text and/or html body + * @return array The details of the mail + */ + public function getDetails() + { + $bodyTextExists = false; + $bodyHTMLExists = false; + $attachmentNb = count($this->getAttachmentID()); + $attachmentInlineNb = count($this->getAttachmentID(true)); + foreach ($this->sections as $sectionID => $section) { + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/plain" + ) { + $bodyTextExists = true; + } + if ( + array_key_exists("_contentType", $section) && + $section["_contentType"] === "text/html" + ) { + $bodyHTMLExists = true; + } + } + unset($sectionID); + unset($section); + $attachmentDetails = array(); + $attachmentInlineDetails = array(); + for ($i = 0; $i < $attachmentNb; $i++) { + $attachmentDetails[$i] = $this->getAttachmentDetails($i); + } + for ($i = 0; $i < $attachmentInlineNb; $i++) { + $attachmentInlineDetails[$i] = $this->getAttachmentDetails($i, true); + } + unset($i); + $size = strlen($this->getMail()); + $from = trim($this->getHeader("From")); + if ($from !== false) { + $fromArray = $this->convertPeopleToArray( + $this->decodeHeaders("From", $from) + ); + } + $to = trim($this->getHeader("To")); + if ($to !== false) { + $toArray = $this->convertPeopleToArray( + $this->decodeHeaders("To", $to) + ); + } + $date = trim($this->getDate()); + $dateTimestamp = $this->getDateTimestamp(); + $subject = $this->decodeHeaders("Subject", $this->getHeader("Subject")); + return get_defined_vars(); + } + + /** Create a boundary + * @return string the textual boundary + */ + private function getBoundary() + { + $data = openssl_random_pseudo_bytes(16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 + return "-----" . vsprintf( + '%s%s%s%s%s%s%s%s', + str_split(bin2hex($data), 4) + ); + } + + /** Create a messageID + * @return string the textual MessageID + */ + public function provideMessageID() + { + $data = openssl_random_pseudo_bytes(16); + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0010 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10 + return "<" . vsprintf( + '%s%s-%s-%s-%s-%s%s%s', + str_split(bin2hex($data), 4) + ) . "@" . + php_uname('n') . ">"; + } + + /** Convert the content to correct encoding. + * The allowed encodings are "quoted-printable" or "base64" or "flowed" + * Cut the long lines to 76 chars with the correct separator + * @param string $content The content to encode + * @param string $encoding The encoding to use + * @return string the content encoded by $encoding + */ + private function encodingEncode($content, $encoding) + { + if ($encoding === "quoted-printable") { + $tmp = quoted_printable_encode($content); + return $tmp; + } elseif ($encoding === "base64") { + $tmp = base64_encode($content); + return chunk_split($tmp); + } elseif ($encoding === "flowed") { + return chunk_split($content); + } + throw new \Exception(sprintf( + dgettext( + "domframework", + "Invalid encoding provided to encodingEncode : %s" + ), + $encoding + ), 500); + } + + /** Decode the content with correct encoding. + * The allowed encodings are "quoted-printable" or "base64" or "8bit" + * @param string $content The content to decode + * @param string $encoding The encoding to use + * @return the content decoded by $encoding + */ + private function encodingDecode($content, $encoding) + { + if ($encoding === "quoted-printable") { + return quoted_printable_decode($content); + } elseif ($encoding === "base64") { + return base64_decode($content); + } elseif ($encoding === "8bit" || $encoding === "7bit" || $encoding === false) { + return $content; + } + throw new \Exception(sprintf( + dgettext( + "domframework", + "Invalid encoding provided to encodingDecode : '%s'" + ), + $encoding + ), 500); + } + + /** Encode a string to be compliant with MIME (used in headers) + * @param string $header The header to be used. Will not be returned, but the + * length of the result will be adapted to it + * @param string $content The content to encode + * @param string $encoding The encoding to use. + * The allowed encodings are "quoted-printable" or "base64" + * @return string the content encoded by $encoding + */ + private function encodeHeaders($header, $content, $encoding) + { + $prefs = array("input-charset" => "utf-8", "output-charset" => "utf-8"); - if ($encoding === "quoted-printable") - $prefs["scheme"] = "Q"; - elseif ($encoding === "base64") - $prefs["scheme"] = "B"; - else - throw new \Exception (dgettext ("domframework", - "Invalid encoding provided to encodeHeaders"), 500); - return substr (iconv_mime_encode ($header, $content, $prefs), - strlen ($header)+2); - } + if ($encoding === "quoted-printable") { + $prefs["scheme"] = "Q"; + } elseif ($encoding === "base64") { + $prefs["scheme"] = "B"; + } else { + throw new \Exception(dgettext( + "domframework", + "Invalid encoding provided to encodeHeaders" + ), 500); + } + return substr( + iconv_mime_encode($header, $content, $prefs), + strlen($header) + 2 + ); + } - /** Convert the header to text - * @param string $header The header to decode - * @param string $content The content of the header to decode - * @return string the header converted - */ - private function decodeHeaders ($header, $content) - { - return substr (iconv_mime_decode ("$header: $content", 0, "utf-8"), - strlen ($header)+2); - } + /** Convert the header to text + * @param string $header The header to decode + * @param string $content The content of the header to decode + * @return string the header converted + */ + private function decodeHeaders($header, $content) + { + return substr( + iconv_mime_decode("$header: $content", 0, "utf-8"), + strlen($header) + 2 + ); + } - /** Encode a header string not starting on first column. The number of chars - * need to be skipped is passed as argument. The function will correctely - * managethe associated carriage returns - * @param string $content The content to encode - * @param string $encoding The The encoding to use. - * The allowed encodings are "quoted-printable" or "base64" - * @param integer $blanks Initial blanks to be added on string - * @return string the content encoded by $encoding - */ - private function encodeHeaderStringWithPosition ($content, $encoding, $blanks) - { - $prefs = array ("input-charset" => "utf-8", + /** Encode a header string not starting on first column. The number of chars + * need to be skipped is passed as argument. The function will correctely + * managethe associated carriage returns + * @param string $content The content to encode + * @param string $encoding The The encoding to use. + * The allowed encodings are "quoted-printable" or "base64" + * @param integer $blanks Initial blanks to be added on string + * @return string the content encoded by $encoding + */ + private function encodeHeaderStringWithPosition($content, $encoding, $blanks) + { + $prefs = array("input-charset" => "utf-8", "output-charset" => "utf-8"); - if ($encoding === "quoted-printable") - $prefs["scheme"] = "Q"; - elseif ($encoding === "base64") - $prefs["scheme"] = "B"; - else - throw new \Exception (dgettext ("domframework", - "Invalid encoding provided to encodeHeaderStringWithPosition"), 500); - return substr (iconv_mime_encode (str_repeat (" ", $blanks), $content, - $prefs), - $blanks+2); - } - - /** Convert a From/To string to array. Manage multiple recipients - * Ex. : toto toto , titi - * array (array ("name"=>"toto toto", "mail"=>"toto@toto.com"), - * array ("name"=>"titi", "mail"=>"titi@titi.com")) - * @param string $data The From/To field content - * @return array The array with the converted data - */ - public function convertPeopleToArray ($data) - { - $elements = explode (",", $data); - $res = array (); - foreach ($elements as $element) - { - @list ($name, $mail) = explode ("<", $element); - if ($mail === null) - { - $mail = $name; - $name = ""; - } - else - { - $name = trim ($name); - $mail = substr (trim ($mail), 0, -1); - } - $array = array ("name"=>$name, "mail"=>$mail); - $res[] = $array; + if ($encoding === "quoted-printable") { + $prefs["scheme"] = "Q"; + } elseif ($encoding === "base64") { + $prefs["scheme"] = "B"; + } else { + throw new \Exception(dgettext( + "domframework", + "Invalid encoding provided to encodeHeaderStringWithPosition" + ), 500); + } + return substr( + iconv_mime_encode( + str_repeat(" ", $blanks), + $content, + $prefs + ), + $blanks + 2 + ); } - return $res; - } - /** Analyze the Content-Type line and return an array with the values - * @param string $contentType The content Type to analyze - * @return array The analyzed Content-Type - */ - public function contentTypeAnalyze ($contentType) - { - $contentType = preg_replace ("#[\r\n]+[ \t]+#", " ", $contentType); - $elements = explode (";", $contentType); - $res = array (); - foreach ($elements as $elem) + /** Convert a From/To string to array. Manage multiple recipients + * Ex. : toto toto , titi + * array (array ("name"=>"toto toto", "mail"=>"toto@toto.com"), + * array ("name"=>"titi", "mail"=>"titi@titi.com")) + * @param string $data The From/To field content + * @return array The array with the converted data + */ + public function convertPeopleToArray($data) { - @list ($key, $val) = explode ("=", $elem, 2); - if ($val === null) - $res["Content-Type"] = $key; - else - { - if ($val[0] === "'" || $val[0] === "\"") - $val = substr ($val, 1, -1); - $res[trim ($key)] = $val; - } + $elements = explode(",", $data); + $res = array(); + foreach ($elements as $element) { + @list($name, $mail) = explode("<", $element); + if ($mail === null) { + $mail = $name; + $name = ""; + } else { + $name = trim($name); + $mail = substr(trim($mail), 0, -1); + } + $array = array("name" => $name, "mail" => $mail); + $res[] = $array; + } + return $res; + } + + /** Analyze the Content-Type line and return an array with the values + * @param string $contentType The content Type to analyze + * @return array The analyzed Content-Type + */ + public function contentTypeAnalyze($contentType) + { + $contentType = preg_replace("#[\r\n]+[ \t]+#", " ", $contentType); + $elements = explode(";", $contentType); + $res = array(); + foreach ($elements as $elem) { + @list($key, $val) = explode("=", $elem, 2); + if ($val === null) { + $res["Content-Type"] = $key; + } else { + if ($val[0] === "'" || $val[0] === "\"") { + $val = substr($val, 1, -1); + } + $res[trim($key)] = $val; + } + } + return $res; } - return $res; - } } diff --git a/src/Markdown.php b/src/Markdown.php index 75b2da2..234d602 100644 --- a/src/Markdown.php +++ b/src/Markdown.php @@ -1,4 +1,5 @@ @@ -11,463 +12,484 @@ namespace Domframework; */ class Markdown { - /** To debug the markdown analyzer, activate the option */ - public $debug = false; + /** To debug the markdown analyzer, activate the option */ + public $debug = false; - /** The list of the HTML elements used by block */ - private $blockid = array ("

                ", "

                ", "

                ", "

                ", "

                ", "
                ", + /** The list of the HTML elements used by block */ + private $blockid = array("

                ", "

                ", "

                ", "

                ", "

                ", "
                ", "
                "); - /** Convert the markdown text to html - * @param string $markdown The markdown to convert - */ - public function html ($markdown) - { - $markdown = rtrim ($markdown); - $markdown = htmlentities ($markdown); - - // Here are the regexp on multilines - $search = array (); - $replace = array (); - // Titles with underline (SeText) - // Titre1 - // ====== - $search[] = "/(.+)\\n==+$/Um"; - $replace[] = "

                \\1

                \n

                "; - // Titre2 - // ------ - $search[] = "/(.+)\\n--+$/Um"; - $replace[] = "

                \\1

                \n

                "; - - // SEPARATORS : *** --- ___ * * * - - - _ _ _ - // Must be placed before EMPHASIS - $search[] = "/^[*_-] ?[*_-] ?[*_-]$/Um"; - $replace[] = "


                \n

                "; - - $markdown = preg_replace ($search, $replace, $markdown); - - $textArray = explode ("\n", $markdown); - $pos = 0; - $html = $this->detectBlock ($textArray, 0, $pos); - $html = str_replace ("

                ", "", $html); - $html = str_replace ("

                ", "", $html); - $html = trim ($html); - return $html; - } - - /** Search and replace in the paragraph on one line - * @param string $line The line to analyze - */ - private function searchReplace ($line) - { - if ($this->debug) - echo "CALL searchReplace ($line)\n"; - // REMEMBER : THE $line is already in HTML ENTITIES ! - // Quotes : " - $res = $line; - // Manage the
                separators - $search = array ("***", "---", "___", "* * *", "- - -", "_ _ _"); - foreach ($search as $key=>$pattern) + /** Convert the markdown text to html + * @param string $markdown The markdown to convert + */ + public function html($markdown) { - $start = 0; - while (1) - { - $start = strpos ($res, $pattern, $start); - if ($start === false) - break; - if ($res[$start+1] === $pattern) - { - // Pattern too long, not this test : skip it - $start += strlen ($pattern) + 1; - continue; - } - if ($start > 1 && $res[$start-1] === "\\") - { - // Search the ending pattern to skip it. Remove the backslash - $res = substr ($res, 0, $start - 1) . substr ($res, $start); - } - else - { - $res = substr ($res, 0, $start) . "
                " . - substr ($res, $start+strlen ($pattern)); - } - } + $markdown = rtrim($markdown); + $markdown = htmlentities($markdown); + + // Here are the regexp on multilines + $search = array(); + $replace = array(); + // Titles with underline (SeText) + // Titre1 + // ====== + $search[] = "/(.+)\\n==+$/Um"; + $replace[] = "

                \\1

                \n

                "; + // Titre2 + // ------ + $search[] = "/(.+)\\n--+$/Um"; + $replace[] = "

                \\1

                \n

                "; + + // SEPARATORS : *** --- ___ * * * - - - _ _ _ + // Must be placed before EMPHASIS + $search[] = "/^[*_-] ?[*_-] ?[*_-]$/Um"; + $replace[] = "


                \n

                "; + + $markdown = preg_replace($search, $replace, $markdown); + + $textArray = explode("\n", $markdown); + $pos = 0; + $html = $this->detectBlock($textArray, 0, $pos); + $html = str_replace("

                ", "", $html); + $html = str_replace("

                ", "", $html); + $html = trim($html); + return $html; } - // Manage the emphasis and code correctely with the backslash - $search = array (); - $replace = array (); - $search[] = "__"; - $replace[] = "\\1"; - $search[] = "_"; - $replace[] = "\\1"; - $search[] = "**"; - $replace[] = "\\1"; - $search[] = "*"; - $replace[] = "\\1"; - $search[] = "`"; - $replace[] = "\\1"; - - foreach ($search as $key=>$pattern) + /** Search and replace in the paragraph on one line + * @param string $line The line to analyze + */ + private function searchReplace($line) { - $start = 0; - while (1) - { - $start = strpos ($res, $pattern, $start); - if ($start === false) - break; - $end = strpos ($res, $pattern, $start + strlen ($pattern)); - if ($end === false) - break; - if ($res[$start+1] === $pattern) - { - // Pattern too long, not this test : skip it - $start += strlen ($pattern) + strspn ($res, $pattern, $start+1); - continue; + if ($this->debug) { + echo "CALL searchReplace ($line)\n"; } - if ($start > 1 && $res[$start-1] === "\\") - { - // Search the ending pattern to skip it. Remove the backslash - $res = substr ($res, 0, $start - 1) . substr ($res, $start); + // REMEMBER : THE $line is already in HTML ENTITIES ! + // Quotes : " + $res = $line; + // Manage the
                separators + $search = array("***", "---", "___", "* * *", "- - -", "_ _ _"); + foreach ($search as $key => $pattern) { + $start = 0; + while (1) { + $start = strpos($res, $pattern, $start); + if ($start === false) { + break; + } + if ($res[$start + 1] === $pattern) { + // Pattern too long, not this test : skip it + $start += strlen($pattern) + 1; + continue; + } + if ($start > 1 && $res[$start - 1] === "\\") { + // Search the ending pattern to skip it. Remove the backslash + $res = substr($res, 0, $start - 1) . substr($res, $start); + } else { + $res = substr($res, 0, $start) . "
                " . + substr($res, $start + strlen($pattern)); + } + } } - else - { - // It is the real pattern found, without backslash. Replace by the - // $replace value - $content = substr ($res, $start + strlen ($pattern), - $end - $start - strlen ($pattern)); - if (trim ($content) !== "") - { - $first = substr ($replace[$key], 0, strpos ($replace[$key], "\\1")); - $second = substr ($replace[$key], strpos ($replace[$key], "\\1")+2); - $res = substr ($res, 0, $start).$first.$content.$second. - substr ($res, $end + strlen ($pattern)); - } + + // Manage the emphasis and code correctely with the backslash + $search = array(); + $replace = array(); + $search[] = "__"; + $replace[] = "\\1"; + $search[] = "_"; + $replace[] = "\\1"; + $search[] = "**"; + $replace[] = "\\1"; + $search[] = "*"; + $replace[] = "\\1"; + $search[] = "`"; + $replace[] = "\\1"; + + foreach ($search as $key => $pattern) { + $start = 0; + while (1) { + $start = strpos($res, $pattern, $start); + if ($start === false) { + break; + } + $end = strpos($res, $pattern, $start + strlen($pattern)); + if ($end === false) { + break; + } + if ($res[$start + 1] === $pattern) { + // Pattern too long, not this test : skip it + $start += strlen($pattern) + strspn($res, $pattern, $start + 1); + continue; + } + if ($start > 1 && $res[$start - 1] === "\\") { + // Search the ending pattern to skip it. Remove the backslash + $res = substr($res, 0, $start - 1) . substr($res, $start); + } else { + // It is the real pattern found, without backslash. Replace by the + // $replace value + $content = substr( + $res, + $start + strlen($pattern), + $end - $start - strlen($pattern) + ); + if (trim($content) !== "") { + $first = substr($replace[$key], 0, strpos($replace[$key], "\\1")); + $second = substr($replace[$key], strpos($replace[$key], "\\1") + 2); + $res = substr($res, 0, $start) . $first . $content . $second . + substr($res, $end + strlen($pattern)); + } + } + $start = $end + strlen($pattern); + } } - $start = $end + strlen ($pattern); - } + + // Manage the others cases + $search = array(); + $replace = array(); + // Titles short + // == TITRE1 + $search[] = '~^([^\\\\]|^)(==+ (.+)( ==+)?)$~Um'; + $replace[] = '

                ' . "\n" . '

                \3

                ' . "\n" . '

                '; + // -- TITRE2 + $search[] = '~^([^\\\\]|^)(--+ (.+)( --+)?)$~Um'; + $replace[] = '

                \n

                \3

                \n

                '; + + // LINKS (can be relative) + // images + $search[] = '~([^\\\\]|^)(!\[(.+)\]\((.+)\))~'; + $replace[] = '\1\'\3\'/'; + // [Google Site](http://google.fr/ "With help bubble") + $search[] = '~([^\\\\!]|^)(\[(.+)\]\((.+) "(.+)"\))~'; + $replace[] = '\1\3'; + // [Google Site](http://google.fr/) + $search[] = '~([^\\\\!]|^)(\[(.+)\]\((.+)\))~U'; + $replace[] = '\1\3'; + + // Automatics links : + // + // + $search[] = '~([^\\\\]|^)(<(https?://.+)>)~U'; + $replace[] = '\1\3'; + $search[] = '~([^\\\\]|^)(<(.+@.+)>)~U'; + $replace[] = '\1\3'; + // The links must not allow the : redo the conversion + $search[] = '~((.*)(.*\'>.*)(.*)(.*)~'; + $replace[] = '\1_\2_\3_\4_\5'; + // TODO : Links by reference : + // Voici un petit texte écrit par [Michel Fortin][mf]. + // [mf]: http://michelf.ca/ "Mon site web" + + // TITLES + // Titles ATX (Optionnal sharp at the end) + // ###### Title6 + $search[] = '~^([^\\\\]|^)?(###### (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // ##### Title5 + $search[] = '~^([^\\\\]|^)?(##### (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // #### Title4 + $search[] = '~^([^\\\\]|^)?(#### (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // ### Title3 + $search[] = '~^([^\\\\]|^)?(### (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // ## Title2 + $search[] = '~^([^\\\\]|^)?(## (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // # Title1 + $search[] = '~^([^\\\\]|^)?(# (.+)( +#+)?)$~Um'; + $replace[] = '

                \3

                '; + // Remove the backslashes on the existing regex + foreach ($search as $s) { + $s = str_replace('([^\\\\]|^)?', '([\\\\])', $s); + $s = str_replace('([^\\\\]|^)', '([\\\\])', $s); + $s = str_replace('([^\\\\!]|^)', '([\\\\])', $s); + $s = str_replace('([^\\\\*]|^)', '([\\\\])', $s); + $s = str_replace('([^\\\\_]|^)', '([\\\\])', $s); + $search[] = $s; + $replace[] = '\2'; + } + /*foreach ($search as $key=>$s) + { + echo "$key => $s\n"; + $res = preg_replace ($s, $replace[$key], $res); + echo "$res\n"; + }*/ + $res = preg_replace($search, $replace, $res); + return $res; } - // Manage the others cases - $search = array (); - $replace = array (); - // Titles short - // == TITRE1 - $search[] = '~^([^\\\\]|^)(==+ (.+)( ==+)?)$~Um'; - $replace[] = '

                '."\n".'

                \3

                '."\n".'

                '; - // -- TITRE2 - $search[] = '~^([^\\\\]|^)(--+ (.+)( --+)?)$~Um'; - $replace[] = '

                \n

                \3

                \n

                '; - - // LINKS (can be relative) - // images - $search[] = '~([^\\\\]|^)(!\[(.+)\]\((.+)\))~'; - $replace[] = '\1\'\3\'/'; - // [Google Site](http://google.fr/ "With help bubble") - $search[] = '~([^\\\\!]|^)(\[(.+)\]\((.+) "(.+)"\))~'; - $replace[] = '\1\3'; - // [Google Site](http://google.fr/) - $search[] = '~([^\\\\!]|^)(\[(.+)\]\((.+)\))~U'; - $replace[] = '\1\3'; - - // Automatics links : - // - // - $search[] = '~([^\\\\]|^)(<(https?://.+)>)~U'; - $replace[] = '\1\3'; - $search[] = '~([^\\\\]|^)(<(.+@.+)>)~U'; - $replace[] = '\1\3'; - // The links must not allow the : redo the conversion - $search[] = '~((.*)(.*\'>.*)(.*)(.*)~'; - $replace[] = '\1_\2_\3_\4_\5'; - // TODO : Links by reference : - // Voici un petit texte écrit par [Michel Fortin][mf]. - // [mf]: http://michelf.ca/ "Mon site web" - - // TITLES - // Titles ATX (Optionnal sharp at the end) - // ###### Title6 - $search[] = '~^([^\\\\]|^)?(###### (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // ##### Title5 - $search[] = '~^([^\\\\]|^)?(##### (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // #### Title4 - $search[] = '~^([^\\\\]|^)?(#### (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // ### Title3 - $search[] = '~^([^\\\\]|^)?(### (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // ## Title2 - $search[] = '~^([^\\\\]|^)?(## (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // # Title1 - $search[] = '~^([^\\\\]|^)?(# (.+)( +#+)?)$~Um'; - $replace[] = '

                \3

                '; - // Remove the backslashes on the existing regex - foreach ($search as $s) + /** Return HTML code corresponding to the code block + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + */ + private function typeCode($text, $depth, &$pos) { - $s = str_replace ('([^\\\\]|^)?', '([\\\\])', $s); - $s = str_replace ('([^\\\\]|^)', '([\\\\])', $s); - $s = str_replace ('([^\\\\!]|^)', '([\\\\])', $s); - $s = str_replace ('([^\\\\*]|^)', '([\\\\])', $s); - $s = str_replace ('([^\\\\_]|^)', '([\\\\])', $s); - $search[] = $s; - $replace[] = '\2'; - } -/*foreach ($search as $key=>$s) -{ -echo "$key => $s\n"; - $res = preg_replace ($s, $replace[$key], $res); -echo "$res\n"; -}*/ - $res = preg_replace ($search, $replace, $res); - return $res; - } - - /** Return HTML code corresponding to the code block - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - */ - private function typeCode ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL typeCode (\$text, $depth, $pos)\n"; - $posStart = $pos; - $content = ""; - // End of code block : end of markdown text / depth lighter than $depth - while (isset ($text[$pos]) && - $this->depth($text[$pos]) >= $depth) - { - // The Code blocks can't be imbricated - if ($pos > $posStart) - $content .= "\n"; - $content .= substr ($text[$pos], $depth); - $pos++; - } - // Insert Geshi on $content - if ($this->debug) - echo "RETURN typeCode :

                $content
                \n"; - return "
                $content
                \n"; - } - - /** Return HTML code corresponding to the OL block - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - */ - private function typeOL ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL typeOL (\$text, $depth, $pos)\n"; - $content = $this->typeOLUL ($text, $depth, $pos, "ol"); - if ($this->debug) echo "RETURN typeOL : $content\n"; - return $content; - } - - /** Return HTML code corresponding to the UL block - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - */ - private function typeUL ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL typeUL (\$text, $depth, $pos)\n"; - $content = $this->typeOLUL ($text, $depth, $pos, "ul"); - if ($this->debug) echo "RETURN typeUL : $content\n"; - return $content; - } - - /** Return the HTML code corresponding to the OL/UL block - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - * @param string $type The block type : "ul" or "ol" - */ - private function typeOLUL ($text, $depth, &$pos, $type) - { - if ($this->debug) echo "CALL typeOLUL (\$text, $depth, $pos, $type)\n"; - $content = ""; - // End of OL/UL block : end of markdown text / depth lighter than $depth / - // linetype changed - $blockStart = $pos; - $blockContent = ""; - while (isset ($text[$pos]) && - $this->depth($text[$pos]) >= $depth && - $this->lineType ($text[$pos]) === $type) - { - if ($this->debug) - echo "Start while $pos\n"; - if (1) - { - $content .= str_repeat (" ", ($depth+2))."
              1. "; - $blockContent .= $text[$pos]; - $pos++; - // Look at continuous lines - while (isset ($text[$pos]) && - $this->lineType ($text[$pos]) !== "NONE" && - $this->lineType ($text[$pos]) !== $type && - $this->depth($text[$pos]) === $depth) - { - if ($this->debug) - echo "Continuous line : ".$pos."\n"; - $blockContent .= " ".$text[$pos]; - $pos++; - continue; + if ($this->debug) { + echo "CALL typeCode (\$text, $depth, $pos)\n"; } - // Indent the li and remove the number and dot and space at start - if ($type === "ol") - preg_match ("/^( *)[0-9]+\. +(.*)/", $blockContent, $matches); - else - preg_match ("/^( *)[-+*] +(.*)/", $blockContent, $matches); - if (!isset ($matches[2])) - $lineTxt = $blockContent; - else - $lineTxt = $matches[2]; - $lineTxt = $this->searchReplace ($lineTxt); - $content .= $lineTxt; + $posStart = $pos; + $content = ""; + // End of code block : end of markdown text / depth lighter than $depth + while ( + isset($text[$pos]) && + $this->depth($text[$pos]) >= $depth + ) { + // The Code blocks can't be imbricated + if ($pos > $posStart) { + $content .= "\n"; + } + $content .= substr($text[$pos], $depth); + $pos++; + } + // Insert Geshi on $content + if ($this->debug) { + echo "RETURN typeCode :
                $content
                \n"; + } + return "
                $content
                \n"; + } + + /** Return HTML code corresponding to the OL block + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + */ + private function typeOL($text, $depth, &$pos) + { + if ($this->debug) { + echo "CALL typeOL (\$text, $depth, $pos)\n"; + } + $content = $this->typeOLUL($text, $depth, $pos, "ol"); + if ($this->debug) { + echo "RETURN typeOL : $content\n"; + } + return $content; + } + + /** Return HTML code corresponding to the UL block + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + */ + private function typeUL($text, $depth, &$pos) + { + if ($this->debug) { + echo "CALL typeUL (\$text, $depth, $pos)\n"; + } + $content = $this->typeOLUL($text, $depth, $pos, "ul"); + if ($this->debug) { + echo "RETURN typeUL : $content\n"; + } + return $content; + } + + /** Return the HTML code corresponding to the OL/UL block + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + * @param string $type The block type : "ul" or "ol" + */ + private function typeOLUL($text, $depth, &$pos, $type) + { + if ($this->debug) { + echo "CALL typeOLUL (\$text, $depth, $pos, $type)\n"; + } + $content = ""; + // End of OL/UL block : end of markdown text / depth lighter than $depth / + // linetype changed $blockStart = $pos; $blockContent = ""; - } - if (isset ($text[$pos]) && $this->depth($text[$pos]) > $depth) - { - if ($this->debug) - echo "Detect Block\n"; - $content .= "\n". - $this->detectBlock ($text, $this->depth($text[$pos]), $pos). - str_repeat (" ", ($depth+2))."
              2. \n"; - } - else - { - $content .= "\n"; - } + while ( + isset($text[$pos]) && + $this->depth($text[$pos]) >= $depth && + $this->lineType($text[$pos]) === $type + ) { + if ($this->debug) { + echo "Start while $pos\n"; + } + if (1) { + $content .= str_repeat(" ", ($depth + 2)) . "
              3. "; + $blockContent .= $text[$pos]; + $pos++; + // Look at continuous lines + while ( + isset($text[$pos]) && + $this->lineType($text[$pos]) !== "NONE" && + $this->lineType($text[$pos]) !== $type && + $this->depth($text[$pos]) === $depth + ) { + if ($this->debug) { + echo "Continuous line : " . $pos . "\n"; + } + $blockContent .= " " . $text[$pos]; + $pos++; + continue; + } + // Indent the li and remove the number and dot and space at start + if ($type === "ol") { + preg_match("/^( *)[0-9]+\. +(.*)/", $blockContent, $matches); + } else { + preg_match("/^( *)[-+*] +(.*)/", $blockContent, $matches); + } + if (!isset($matches[2])) { + $lineTxt = $blockContent; + } else { + $lineTxt = $matches[2]; + } + $lineTxt = $this->searchReplace($lineTxt); + $content .= $lineTxt; + $blockStart = $pos; + $blockContent = ""; + } + if (isset($text[$pos]) && $this->depth($text[$pos]) > $depth) { + if ($this->debug) { + echo "Detect Block\n"; + } + $content .= "\n" . + $this->detectBlock($text, $this->depth($text[$pos]), $pos) . + str_repeat(" ", ($depth + 2)) . "
              4. \n"; + } else { + $content .= "\n"; + } + } + if ($this->debug) { + echo "RETURN typeOLUL : <$type>\n$content\n"; + } + return "<$type>\n$content" . str_repeat(" ", $depth) . "\n"; } - if ($this->debug) echo "RETURN typeOLUL : <$type>\n$content\n"; - return "<$type>\n$content".str_repeat (" ", $depth)."\n"; - } - - /** Return HTML code corresponding to the NONE block - * The NONE type exists only on empty strings. Just skip the current and - * empty line, and return an empty string - * @param string $text The Markdown text to translate split by \n - * @param integer $depth The depth of the current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - */ - private function typeNONE ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL typeNONE (\$text, $depth, $pos)\n"; - $pos++; - return ""; - } - - /** Return HTML code corresponding to the P block - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - */ - private function typeP ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL typeP (\$text, $depth, $pos)\n"; - $content = ""; - // End of P block : end of markdown text / depth lighter than $depth / - // linetype changed - $Pinc = $pos; - while (isset ($text[$pos]) && - $this->depth($text[$pos]) == $depth && - $this->lineType ($text[$pos]) === "p") + /** Return HTML code corresponding to the NONE block + * The NONE type exists only on empty strings. Just skip the current and + * empty line, and return an empty string + * @param string $text The Markdown text to translate split by \n + * @param integer $depth The depth of the current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + */ + private function typeNONE($text, $depth, &$pos) { - if (substr ($text[$pos], -2) === " ") - { - // Two spaces at end of line : add
                - $content .= $this->searchReplace (substr ($text[$pos], 0, -2)) ."
                "; - } - elseif ($pos > $Pinc && substr ($content, -5) !== "
                ") - { - // Add a space between two lines from the same block, if this is not - // the continuity of the block - $content .= " ".$this->searchReplace ($text[$pos]); - } - else - { - $content .= $this->searchReplace ($text[$pos]); - } - $pos++; + if ($this->debug) { + echo "CALL typeNONE (\$text, $depth, $pos)\n"; + } + $pos++; + return ""; } - if ($this->debug) echo "RETURN typeP :

                $content

                \n"; - return "

                $content

                \n"; - } - /** Detect the type of the text and call the appropriate function * - * @param array $text The Markdown text to translate split by \n - * @param integer $depth The depth of current bloc (in number of space) - * @param integer &$pos The start line number of the bloc - * @return the HTML code - */ - private function detectBlock ($text, $depth, &$pos) - { - if ($this->debug) echo "CALL detectBlock (\$text, $depth, $pos)\n"; - $content = ""; - $blockContent = ""; - // detect the type and call the right type function - while (isset ($text[$pos])) + /** Return HTML code corresponding to the P block + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + */ + private function typeP($text, $depth, &$pos) { - if ($this->depth ($text[$pos]) > $depth && $depth === 0) - { - // New block code - if ($this->debug) - echo "New block code\n"; - $content .= $this->typeCode ($text, $this->depth ($text[$pos]), $pos); - continue; - } - elseif ($this->depth ($text[$pos]) > $depth) - { - if ($this->debug) - echo "CALL DEPTH > MINDEPTH (".$this->depth ($text[$pos]). - " > $depth)\n"; - $content .= $this->detectBlock ($text, $this->depth ($text[$pos]), - $pos); - continue; - } - elseif ($this->depth ($text[$pos]) < $depth) - { - if ($this->debug) - echo "CALL DEPTH > MINDEPTH (".$this->depth ($text[$pos]). - " < $depth)\n"; + if ($this->debug) { + echo "CALL typeP (\$text, $depth, $pos)\n"; + } + $content = ""; + // End of P block : end of markdown text / depth lighter than $depth / + // linetype changed + $Pinc = $pos; + while ( + isset($text[$pos]) && + $this->depth($text[$pos]) == $depth && + $this->lineType($text[$pos]) === "p" + ) { + if (substr($text[$pos], -2) === " ") { + // Two spaces at end of line : add
                + $content .= $this->searchReplace(substr($text[$pos], 0, -2)) . "
                "; + } elseif ($pos > $Pinc && substr($content, -5) !== "
                ") { + // Add a space between two lines from the same block, if this is not + // the continuity of the block + $content .= " " . $this->searchReplace($text[$pos]); + } else { + $content .= $this->searchReplace($text[$pos]); + } + $pos++; + } + if ($this->debug) { + echo "RETURN typeP :

                $content

                \n"; + } + return "

                $content

                \n"; + } + + /** Detect the type of the text and call the appropriate function * + * @param array $text The Markdown text to translate split by \n + * @param integer $depth The depth of current bloc (in number of space) + * @param integer &$pos The start line number of the bloc + * @return the HTML code + */ + private function detectBlock($text, $depth, &$pos) + { + if ($this->debug) { + echo "CALL detectBlock (\$text, $depth, $pos)\n"; + } + $content = ""; + $blockContent = ""; + // detect the type and call the right type function + while (isset($text[$pos])) { + if ($this->depth($text[$pos]) > $depth && $depth === 0) { + // New block code + if ($this->debug) { + echo "New block code\n"; + } + $content .= $this->typeCode($text, $this->depth($text[$pos]), $pos); + continue; + } elseif ($this->depth($text[$pos]) > $depth) { + if ($this->debug) { + echo "CALL DEPTH > MINDEPTH (" . $this->depth($text[$pos]) . + " > $depth)\n"; + } + $content .= $this->detectBlock( + $text, + $this->depth($text[$pos]), + $pos + ); + continue; + } elseif ($this->depth($text[$pos]) < $depth) { + if ($this->debug) { + echo "CALL DEPTH > MINDEPTH (" . $this->depth($text[$pos]) . + " < $depth)\n"; + } + return $content; + } + + $type = $this->lineType($text[$pos]); + $func = "type$type"; + if ($this->debug) { + echo "FROM DETECT : CALL $func (line=" . $text[$pos] . ")\n"; + } + $content .= str_repeat(" ", $depth) . $this->$func($text, $depth, $pos); + } return $content; - } - - $type = $this->lineType ($text[$pos]); - $func = "type$type"; - if ($this->debug) - echo "FROM DETECT : CALL $func (line=".$text[$pos].")\n"; - $content .= str_repeat (" ", $depth). $this->$func ($text, $depth, $pos); } - return $content; - } - /** Return the Type of object in the provided line - * p, ul, ol, code - * @param string $line The line to get the type - */ - private function lineType ($line) - { - if (! isset ($line[0])) - return "NONE"; - if (preg_match ("/^[ \t]*[+*-] /", $line) === 1) - return "ul"; - if (preg_match ("/^[ \t]*[0-9]+\. /", $line) === 1) - return "ol"; - if (preg_match ("/^( |\t)+/", $line) === 1) - return "code"; - return "p"; - } + /** Return the Type of object in the provided line + * p, ul, ol, code + * @param string $line The line to get the type + */ + private function lineType($line) + { + if (! isset($line[0])) { + return "NONE"; + } + if (preg_match("/^[ \t]*[+*-] /", $line) === 1) { + return "ul"; + } + if (preg_match("/^[ \t]*[0-9]+\. /", $line) === 1) { + return "ol"; + } + if (preg_match("/^( |\t)+/", $line) === 1) { + return "code"; + } + return "p"; + } - /** Return the depth of the provided line - * @param string $line Line to analyze - * @return the depth of the line - */ - private function depth ($line) - { - return strspn ($line, " "); - } + /** Return the depth of the provided line + * @param string $line Line to analyze + * @return the depth of the line + */ + private function depth($line) + { + return strspn($line, " "); + } } diff --git a/src/Module.php b/src/Module.php index e9ea0e2..451355c 100644 --- a/src/Module.php +++ b/src/Module.php @@ -1,4 +1,5 @@ @@ -11,77 +12,103 @@ namespace Domframework; */ class Module { - /** The modules are not allowed if $toplevel=0 - * The modules can be in a module directory if $toplevel=1 - * The modules can be in the parent directory if $toplevel=2 - * The modules can be in the local directory if $toplevel=4 - * The values can be added to allow multiple possibilities - */ - public $toplevel = 0; + /** The modules are not allowed if $toplevel=0 + * The modules can be in a module directory if $toplevel=1 + * The modules can be in the parent directory if $toplevel=2 + * The modules can be in the local directory if $toplevel=4 + * The values can be added to allow multiple possibilities + */ + public $toplevel = 0; - /** List all the available (enable or disable) modules - * @return array The list of the available modules names with the path - */ - public function listAvailable () - { - $list = array (); - $tmp = array (); - if ($this->toplevel%2 >= 1 ) - $tmp = array_merge ($tmp, glob ("modules/*")); - if ($this->toplevel%4 >= 2 ) - $tmp = array_merge ($tmp, glob ("../*")); - if ($this->toplevel%8 >= 4 ) - $tmp = array_merge ($tmp, glob ("*")); - foreach ($tmp as $path) + /** List all the available (enable or disable) modules + * @return array The list of the available modules names with the path + */ + public function listAvailable() { - $name = basename ($path); - if (! is_dir ($path)) continue; - if ($name === ".") continue; - if ($name === "..") continue; - if ($name === "cli") continue; - if ($name === "controllers") continue; - if ($name === "data") continue; - if ($name === "datas") continue; - if ($name === "locale") continue; - if ($name === "models") continue; - if ($name === "modules") continue; - if ($name === "public") continue; - if ($name === "views") continue; - $list[$name] = $path; + $list = array(); + $tmp = array(); + if ($this->toplevel % 2 >= 1) { + $tmp = array_merge($tmp, glob("modules/*")); + } + if ($this->toplevel % 4 >= 2) { + $tmp = array_merge($tmp, glob("../*")); + } + if ($this->toplevel % 8 >= 4) { + $tmp = array_merge($tmp, glob("*")); + } + foreach ($tmp as $path) { + $name = basename($path); + if (! is_dir($path)) { + continue; + } + if ($name === ".") { + continue; + } + if ($name === "..") { + continue; + } + if ($name === "cli") { + continue; + } + if ($name === "controllers") { + continue; + } + if ($name === "data") { + continue; + } + if ($name === "datas") { + continue; + } + if ($name === "locale") { + continue; + } + if ($name === "models") { + continue; + } + if ($name === "modules") { + continue; + } + if ($name === "public") { + continue; + } + if ($name === "views") { + continue; + } + $list[$name] = $path; + } + ksort($list); + return $list; } - ksort ($list); - return $list; - } - /** List all the enable modules coming from the configuration and available - * in the system - * @param array $confModules the list of the available modules coming from - * the configuration. Can have some non available modules. - * @return array the list of the available modules names with the path - */ - public function listEnable ($confModules) - { - $listAvailable = $this->listAvailable (); - $list = array (); - foreach ($confModules as $module) + /** List all the enable modules coming from the configuration and available + * in the system + * @param array $confModules the list of the available modules coming from + * the configuration. Can have some non available modules. + * @return array the list of the available modules names with the path + */ + public function listEnable($confModules) { - if (array_key_exists ($module, $listAvailable)) - $list[$module] = $listAvailable[$module]; + $listAvailable = $this->listAvailable(); + $list = array(); + foreach ($confModules as $module) { + if (array_key_exists($module, $listAvailable)) { + $list[$module] = $listAvailable[$module]; + } + } + ksort($list); + return $list; } - ksort ($list); - return $list; - } - /** Return the name of the module translated in the provided language - * The module name must be defined in the translation under the "modulename" - * item - * @param string $modulepath The module path - * @param string $lang The lang to use - */ - public function translateName ($modulepath, $lang) - { - // TODO : Do really the function ! With the language selection, and - // searching in the directories - return basename ($modulepath); - } + /** Return the name of the module translated in the provided language + * The module name must be defined in the translation under the "modulename" + * item + * @param string $modulepath The module path + * @param string $lang The lang to use + */ + public function translateName($modulepath, $lang) + { + // TODO : Do really the function ! With the language selection, and + // searching in the directories + return basename($modulepath); + } } diff --git a/src/Output.php b/src/Output.php index 33ffb16..1079f46 100644 --- a/src/Output.php +++ b/src/Output.php @@ -1,4 +1,5 @@ @@ -11,10 +12,10 @@ namespace Domframework; */ class Output { - /** Class used to display data - @param mixed $data The data to be displayed */ - public function out ($data) - { - throw new \Exception ("No type of output selected"); - } + /** Class used to display data + @param mixed $data The data to be displayed */ + public function out($data) + { + throw new \Exception("No type of output selected"); + } } diff --git a/src/Outputcsv.php b/src/Outputcsv.php index 47b79a3..924cc3c 100644 --- a/src/Outputcsv.php +++ b/src/Outputcsv.php @@ -1,4 +1,5 @@ @@ -11,33 +12,38 @@ namespace Domframework; */ class Outputcsv extends Output { - /** Don't allow to output in CSV if the functions are not available in PHP */ - function __construct () - { - if (!function_exists ("fputcsv")) - throw new \Exception ("CSV support not available in PHP !", 500); - } + /** Don't allow to output in CSV if the functions are not available in PHP */ + public function __construct() + { + if (!function_exists("fputcsv")) { + throw new \Exception("CSV support not available in PHP !", 500); + } + } - /** Display in CSV the data provided - @param mixed $data The data to be displayed */ - public function out ($data) - { - 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'); - if (! is_array ($data[0])) - $data = array ($data); - foreach ($data as $vals) - fputcsv ($out, $vals); - fclose ($out); - if (!defined ("PHPUNIT")) - exit; - } + /** Display in CSV the data provided + @param mixed $data The data to be displayed */ + public function out($data) + { + 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'); + if (! is_array($data[0])) { + $data = array($data); + } + foreach ($data as $vals) { + fputcsv($out, $vals); + } + fclose($out); + if (!defined("PHPUNIT")) { + exit; + } + } } diff --git a/src/Outputdl.php b/src/Outputdl.php index b342250..7fe9282 100644 --- a/src/Outputdl.php +++ b/src/Outputdl.php @@ -1,4 +1,5 @@ @@ -13,210 +14,232 @@ namespace Domframework; */ class Outputdl { - /** Allow or deny the resuming of the HTTP transferts - */ - private $resumeAllow = true; + /** Allow or deny the resuming of the HTTP transferts + */ + private $resumeAllow = true; - /** The base dir used as root - */ - private $base = "/"; + /** The base dir used as root + */ + private $base = "/"; - /** Store the headers to allow the unit tests to get them - */ - private $headers = array (); + /** Store the headers to allow the unit tests to get them + */ + private $headers = array(); - /** Headers sent - */ - private $headersSent = false; + /** Headers sent + */ + private $headersSent = false; - /** Get/Set Allow/Deny the resuming of transferts - * @param boolean|null $resumeAllow True : resume OK, false : resume forbid - * @return $this|boolean - */ - public function resumeAllow ($resumeAllow = null) - { - if ($resumeAllow === null) - return $this->resumeAllow; - $this->resumeAllow = !! $resumeAllow; - return $this; - } - - /** Get/Set Base of filesystem - * The base directory is use to secure the download. A user can not request - * a file outside the base. Example : if the base is /var/lib/files, the - * user can not request /etc/passwd file (out of scope). If not defined, - * all the filesystem is allowed - * @param string|null $base The filesystem base - * @return $this|string - */ - public function base ($base = null) - { - if ($base === null) - return $this->base; - $this->base = $base; - return $this; - } - - /** Get headers from headers list - * The headers can be tested too - * @return array - */ - public function headers () - { - return $this->headers; - } - - /** Add a new header and send it if possible - * @param string $header The header to send - * @return $this - */ - private function header ($header) - { - if (! headers_sent()) - header ($header); - $this->headers[] = $header; - return $this; - } - - /** Download a file with management of Partial Download (like resume) - * Manage the HTTP headers to allow to resume the download if it is allowed - * Do not go throw the renderer, exit at end of transfert - * @param string $path The path to download - * @param string|null $filename The filename to send to the browser - */ - public function downloadFile ($path, $filename = null) - { - if (!file_exists ($path)) - throw new \Exception (dgettext ("domframework", - "Invalid file to download : file doesn't exists"), 404); - if (is_link ($path) || is_dir ($path)) - throw new \Exception (dgettext ("domframework", - "Invalid file to download : not a file"), 406); - $path = realpath ($path); - if (substr ($path, 0, strlen ($this->base)) !== $this->base) - throw new \Exception (dgettext ("domframework", - "Invalid file to download : out of base"), 406); - if (! is_file ($path)) - throw new \Exception (dgettext ("domframework", - "Invalid file to download : not a file"), 406); - if (! is_readable ($path)) - throw new \Exception (dgettext ("domframework", - "Invalid file to download : file not readable"), 406); - ini_set ('display_errors', 0); - ini_set ('display_startup_errors', 0); - if (! defined ("PHPUNIT") && ob_get_level ()) - ob_end_clean (); - - if ($filename === null) - $filename = basename ($path); - $this->header ('Content-Description: File Transfer'); - $this->header ('Content-Type: application/octet-stream'); - $this->header ('Content-Disposition: attachment; filename="'.$filename.'"'); - $this->header ('Content-Transfer-Encoding: binary'); - //header ('Expires: 0'); - //header ('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - //header ('Pragma: public'); - $filesize = filesize ($path); - if (! $this->resumeAllow) + /** Get/Set Allow/Deny the resuming of transferts + * @param boolean|null $resumeAllow True : resume OK, false : resume forbid + * @return $this|boolean + */ + public function resumeAllow($resumeAllow = null) { - $this->header ('Accept-Ranges: none'); + if ($resumeAllow === null) { + return $this->resumeAllow; + } + $this->resumeAllow = !! $resumeAllow; + return $this; } - else - { - $this->header ('Accept-Ranges: bytes'); - if (isset ($_SERVER["HTTP_RANGE"]) && - strtolower (substr ($_SERVER["HTTP_RANGE"], 0, 6)) === "bytes=") - { - $boundary = "Qm91bmRhcnk="; - $rangeTxt = trim (substr ($_SERVER["HTTP_RANGE"], 6)); - $ranges = explode (",", $rangeTxt); - if (count ($ranges) > 1) - $this->header ( - "Content-Type: multipart/byteranges; boundary=$boundary"); - foreach ($ranges as $nb => $range) - { - if (trim ($range) === "-") - throw new \Exception ("Invalid range provided", 416); - @list ($start, $stop) = explode ("-", trim ($range)); - if ($stop === null || $stop === "") - $stop = $filesize; - if ($stop && ($start === null || $start === "")) - { - $start = $filesize - $stop; - $stop = $filesize; - } - $start = intval ($start); - $stop = intval ($stop); - if ($start > $stop) - throw new \Exception ("Invalid range provided", 416); - if ($start < 0 || $stop > $filesize || $start > $filesize) - throw new \Exception ("Invalid range provided", 416); - if (count ($ranges) > 1) - { - if ($nb > 0) - echo "\r\n"; - echo "--".$boundary."\r\n"; - echo "Content-Range: bytes $start-$stop/$filesize\r\n"; - echo "Content-Type: application/octet-stream\r\n"; - echo "\r\n"; - } - else - { - $this->header ("Content-Range: bytes $start-$stop/$filesize"); - } - http_response_code (206); - $this->downloadFileRange ($path, $start, $stop); + /** Get/Set Base of filesystem + * The base directory is use to secure the download. A user can not request + * a file outside the base. Example : if the base is /var/lib/files, the + * user can not request /etc/passwd file (out of scope). If not defined, + * all the filesystem is allowed + * @param string|null $base The filesystem base + * @return $this|string + */ + public function base($base = null) + { + if ($base === null) { + return $this->base; } - if (count ($ranges) > 1) - { - if ($nb > 0) - echo "\r\n"; - echo "--".$boundary."--\r\n"; + $this->base = $base; + return $this; + } + + /** Get headers from headers list + * The headers can be tested too + * @return array + */ + public function headers() + { + return $this->headers; + } + + /** Add a new header and send it if possible + * @param string $header The header to send + * @return $this + */ + private function header($header) + { + if (! headers_sent()) { + header($header); + } + $this->headers[] = $header; + return $this; + } + + /** Download a file with management of Partial Download (like resume) + * Manage the HTTP headers to allow to resume the download if it is allowed + * Do not go throw the renderer, exit at end of transfert + * @param string $path The path to download + * @param string|null $filename The filename to send to the browser + */ + public function downloadFile($path, $filename = null) + { + if (!file_exists($path)) { + throw new \Exception(dgettext( + "domframework", + "Invalid file to download : file doesn't exists" + ), 404); + } + if (is_link($path) || is_dir($path)) { + throw new \Exception(dgettext( + "domframework", + "Invalid file to download : not a file" + ), 406); + } + $path = realpath($path); + if (substr($path, 0, strlen($this->base)) !== $this->base) { + throw new \Exception(dgettext( + "domframework", + "Invalid file to download : out of base" + ), 406); + } + if (! is_file($path)) { + throw new \Exception(dgettext( + "domframework", + "Invalid file to download : not a file" + ), 406); + } + if (! is_readable($path)) { + throw new \Exception(dgettext( + "domframework", + "Invalid file to download : file not readable" + ), 406); + } + ini_set('display_errors', 0); + ini_set('display_startup_errors', 0); + if (! defined("PHPUNIT") && ob_get_level()) { + ob_end_clean(); + } + + if ($filename === null) { + $filename = basename($path); + } + $this->header('Content-Description: File Transfer'); + $this->header('Content-Type: application/octet-stream'); + $this->header('Content-Disposition: attachment; filename="' . $filename . '"'); + $this->header('Content-Transfer-Encoding: binary'); + //header ('Expires: 0'); + //header ('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + //header ('Pragma: public'); + $filesize = filesize($path); + if (! $this->resumeAllow) { + $this->header('Accept-Ranges: none'); + } else { + $this->header('Accept-Ranges: bytes'); + if ( + isset($_SERVER["HTTP_RANGE"]) && + strtolower(substr($_SERVER["HTTP_RANGE"], 0, 6)) === "bytes=" + ) { + $boundary = "Qm91bmRhcnk="; + $rangeTxt = trim(substr($_SERVER["HTTP_RANGE"], 6)); + $ranges = explode(",", $rangeTxt); + if (count($ranges) > 1) { + $this->header( + "Content-Type: multipart/byteranges; boundary=$boundary" + ); + } + foreach ($ranges as $nb => $range) { + if (trim($range) === "-") { + throw new \Exception("Invalid range provided", 416); + } + @list($start, $stop) = explode("-", trim($range)); + if ($stop === null || $stop === "") { + $stop = $filesize; + } + if ($stop && ($start === null || $start === "")) { + $start = $filesize - $stop; + $stop = $filesize; + } + $start = intval($start); + $stop = intval($stop); + if ($start > $stop) { + throw new \Exception("Invalid range provided", 416); + } + if ($start < 0 || $stop > $filesize || $start > $filesize) { + throw new \Exception("Invalid range provided", 416); + } + if (count($ranges) > 1) { + if ($nb > 0) { + echo "\r\n"; + } + echo "--" . $boundary . "\r\n"; + echo "Content-Range: bytes $start-$stop/$filesize\r\n"; + echo "Content-Type: application/octet-stream\r\n"; + echo "\r\n"; + } else { + $this->header("Content-Range: bytes $start-$stop/$filesize"); + } + http_response_code(206); + $this->downloadFileRange($path, $start, $stop); + } + if (count($ranges) > 1) { + if ($nb > 0) { + echo "\r\n"; + } + echo "--" . $boundary . "--\r\n"; + } + if (! defined("PHPUNIT")) { + exit; + } + return; + } + } + // No range or error : send all the file + $this->header('Content-Length: ' . $filesize); + $this->downloadFileRange($path, 0, $filesize); + if (! defined("PHPUNIT")) { + exit; } - if (! defined ("PHPUNIT")) - exit; return; - } } - // No range or error : send all the file - $this->header ('Content-Length: '. $filesize); - $this->downloadFileRange ($path, 0, $filesize); - if (! defined ("PHPUNIT")) - exit; - return; - } - /** Download the file. Do not go through the renderer - * @param string $path The path to download - * @param integer $start The start range - * @param integer $stop The stop range - */ - private function downloadFileRange ($path, $start, $stop) - { - $file = realpath ($path); - $chunksize = 10*1024*1024; // how many bytes per chunk - $start = intval ($start); - $stop = intval ($stop); - $handle = fopen ($file, 'rb'); - if ($handle === false) + /** Download the file. Do not go through the renderer + * @param string $path The path to download + * @param integer $start The start range + * @param integer $stop The stop range + */ + private function downloadFileRange($path, $start, $stop) { - die ("error"); + $file = realpath($path); + $chunksize = 10 * 1024 * 1024; // how many bytes per chunk + $start = intval($start); + $stop = intval($stop); + $handle = fopen($file, 'rb'); + if ($handle === false) { + die("error"); + } + if (fseek($handle, $start) === false) { + die("Can not seek"); + } + $size = $start; + while (! feof($handle)) { + $block = fread($handle, $chunksize); + if ($size + $chunksize > $stop) { + $block = substr($block, 0, $stop - $size + 1); + } + $size += strlen($block); + echo $block; + flush(); + if ($size >= $stop) { + break; + } + } + fclose($handle); } - if (fseek ($handle, $start) === false) - die ("Can not seek"); - $size = $start; - while (! feof ($handle)) - { - $block = fread ($handle, $chunksize); - if ($size + $chunksize > $stop) - $block = substr ($block, 0, $stop - $size + 1); - $size += strlen ($block); - echo $block; - flush (); - if ($size >= $stop) - break; - } - fclose($handle); - } } diff --git a/src/Outputhtml.php b/src/Outputhtml.php index 84c0855..de47379 100644 --- a/src/Outputhtml.php +++ b/src/Outputhtml.php @@ -1,4 +1,5 @@ @@ -11,68 +12,77 @@ namespace Domframework; */ 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") - * @param mixed $data Data to display on the page - * @param string|null $title Title to put on head of page - * @param string|null $viewClass Class in views to use to display - * @param string|null $viewMethod Method in the class in views - * @param string|null $layout Layout file in views - * @param array|null $replacement Replace the {key}=>value - * @param array|null $variable PHP variables send to the view and to layout - * (can be processed by foreach, if...) - * @param string|null $module The module name to use if needed - * @return mixed Exit from PHP at the end of HTML display - */ - public function out ($data, $title = FALSE, - $viewClass = FALSE, $viewMethod = FALSE, - $layout = FALSE, $replacement = array(), - $variable = array (), $module = "") - { - @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) - { - if (! class_exists ($viewClass)) - { - if ($module !== "" && - file_exists ("modules/$module/views/$viewClass.php")) - require_once ("modules/$module/views/$viewClass.php"); - elseif (file_exists ("views/$viewClass.php")) - require_once ("views/$viewClass.php"); - // If the file doesn't exists, an autoloader maybe exists. If it is not + /** 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") + * @param mixed $data Data to display on the page + * @param string|null $title Title to put on head of page + * @param string|null $viewClass Class in views to use to display + * @param string|null $viewMethod Method in the class in views + * @param string|null $layout Layout file in views + * @param array|null $replacement Replace the {key}=>value + * @param array|null $variable PHP variables send to the view and to layout + * (can be processed by foreach, if...) + * @param string|null $module The module name to use if needed + * @return mixed Exit from PHP at the end of HTML display + */ + public function out( + $data, + $title = false, + $viewClass = false, + $viewMethod = false, + $layout = false, + $replacement = array(), + $variable = array(), + $module = "" + ) { + @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) { + if (! class_exists($viewClass)) { + if ( + $module !== "" && + file_exists("modules/$module/views/$viewClass.php") + ) { + require_once("modules/$module/views/$viewClass.php"); + } elseif (file_exists("views/$viewClass.php")) { + require_once("views/$viewClass.php"); + } + // If the file doesn't exists, an autoloader maybe exists. If it is not // the case, the class will not be found - } - $obj = new $viewClass; - $resView = $obj->$viewMethod ($data, $variable); - if (is_array ($resView)) - { - if (isset ($resView["title"])) - $title = $resView["title"]; - if (! isset ($resView["content"])) - throw new \Exception (sprintf ( dgettext ("domframework", - "No data provided from view %s::%s"), $viewClass, $viewMethod), - 500); - } - } + } + $obj = new $viewClass(); + $resView = $obj->$viewMethod($data, $variable); + if (is_array($resView)) { + if (isset($resView["title"])) { + $title = $resView["title"]; + } + if (! isset($resView["content"])) { + throw new \Exception( + sprintf(dgettext( + "domframework", + "No data provided from view %s::%s" + ), $viewClass, $viewMethod), + 500 + ); + } + } + } - if ($layout !== FALSE) - { - if (! file_exists ($layout) && file_exists ("views/$layout.html")) - $layout = "views/$layout.html"; - $layoutPage = $this->layoutVariables ($layout, $variable); - } - else - { - // No layout : display a very basic HTML page - $layoutPage = <<< EOT + if ($layout !== false) { + if (! file_exists($layout) && file_exists("views/$layout.html")) { + $layout = "views/$layout.html"; + } + $layoutPage = $this->layoutVariables($layout, $variable); + } else { + // No layout : display a very basic HTML page + $layoutPage = <<< EOT @@ -85,113 +95,126 @@ class Outputhtml extends Output EOT; + } + // Get all the substitute zones + preg_match_all("~({[\w_-]+})~", $layoutPage, $matches); + $zones = $matches[1]; + + // All the entries coming from views in array are substitute in layout + // {content}, {title} + if (is_array($resView)) { + foreach ($resView as $key => $val) { + $layoutPage = str_replace("{" . $key . "}", $val, $layoutPage); + } + } else { + $layoutPage = str_replace("{content}", $resView, $layoutPage); + } + + // Do the title replacement in the replacement structure + if (! isset($replacement["{flash}"])) { + $replacement["{flash}"] = ""; + } + foreach ($replacement as $key => $val) { + $layoutPage = str_replace($key, $val, $layoutPage); + } + + // Remove the not used {XXX} + foreach ($zones as $zone) { + $layoutPage = str_replace($zone, "", $layoutPage); + } + + //echo $layoutPage;exit; + // Manage the timestamp/md5sum for the external files managed by this + // server. + if (! class_exists("DOMDocument")) { + die( + "PHP Support for XML not enabled or not installed : " . + "apt-get install php-xml\n" + ); + } + $dom = new \DOMDocument(); + libxml_use_internal_errors(true); + $dom->loadHTML($layoutPage); + $errors = libxml_get_errors(); + foreach ($errors as $key => $err) { + // Tag YYY invalid : code 801 + // Like in