Horus Framework Version 3.0

" Code Must Be Smart "


Quick start

Classes

More

What is Horus ?

An OOP PHP micro-framework, a lightweight toolkit to help developers lay down the foundation of their PHP-based websites and applications . The Horus Framework is a pretty solid attempt at designing a good OOP framework in as a small package as possible. Focused on a light codebase and on a solid, standards-friendly approach, Horus can be used to write advanced applications without having to deal with complex coding toolkits like Zend or CakePHP. Horus is easy to learn and the code is pretty well commented in case developers need help figuring out what's going on -- "Softpedia"

Horus Framework Features:

  • Full Options Framework
  • No Complex Code
  • Built-in Smart Router
  • Built-in Events/Hooks
  • Built-in Database Class
  • Built-in Simple ORM
  • Built-in Secure Session Management
  • Built-in Full Output Control
  • Built-in Views Manager
  • Built-in Smart Autoloader
  • Built-in HTTP Manager
  • Built-in helpful functions
  • Easy Configurations
  • Extensible
  • Control Any thing in Horus Without Hacking The Core
  • No Big files on loading to start

What is the new in this version ?

  • Removed events_* functions, added new smart events oop class
  • Fixed all past versions bugs
  • Re-built the router from scratch
  • Router now supports permissions !
  • New Class Container
  • Removed some functions
  • New Functions
  • Re-Optimized the core
  • Removed non-good codes

Download Horus

After downloading horus, extract it to your server, then, open index.php and see it, it just contains:

    
        // load horus kernel
        require_once "Horus/Horus.php";
        
        // start horus
        new Horus;
        
        // hello world !!
        echo "hello world";
    

Only that ?!, yes only that , that is the simple way to use horus, raw php code because horus is full optional, so if you are a php starter , just start horus then use it's functions, classes, ... in your raw code easily .
But if you want to digg into horus also it's very simple , let's see how to use with simple routing,:


// require horus
require_once 'Horus/Horus.php';

// start it
// and tell it that i need Router { Configuration }
new Horus(array('horus.use_router' => yes));

// very simple to respond to a get request
// horus(): is a function that gets the instance of horus with no hassle
horus()->router->get('/', function(){
    echo 'hi we are in get request in the index';
});

// another way to do the same code:
horus('router')->get('/', function(){
    echo 'hi we are in get request in the index';
});

Now goto Configurations tab on the left to know how to configure horus or customize it .

Horus Framework is built-in very easy configurations to control what you want .


How to config Horus ?


    // 1)- when you construct horus, just give it an assoc-array of configurations, like this
    new Horus(array('key' => 'value'));
    
    // 2)- using config() method
    horus()->config(array('key' => 'value'));
    
    // to fetch any configuration
    echo horus()->config('key');
    
    // to fetch all
    $all = horus()->config();
    

List of available configurations

key value default
horus.use_router true / false false
horus.timezone see it on PHP.net PHP Default
horus.default_404 a callback e.g function(){ echo '404 not found'; } Horus Default
horus.auto_run true / false true
if you set it to false, you must type horus()->run(); at the end of your index.php
horus.http_version string 1.1
horus.enable_simulator true / false false
if your server has no support for mod_rewrite, set to true/yes
horus.session_name string HORUS_SESSID
horus.session_hash_function Se it on PHP.net 1
horus.session_use_only_cookies Se it on PHP.net true
horus.session_http_only Se it on PHP.net true
horus.session_regenerate_id true / false true
horus.session_save_path string PHP Default
horus.enable_gzip true / false true
horus.mode dev / production dev

Features

  • Supports Callbacks Routing
  • Supports Class Routing
  • Supports Nested Routing
  • Supports RESTful Request Routing
  • Easy to use
  • Light & Small Code
  • Regex Based
  • Built-in Regex shortcuts
  • Clean Urls even if you have no support for mod_rewrite, just enable horus simulator
  • Respond to any HTTP Method even custom

Supported HTTP Methods

With Horus Router You can respond to GET, POST, PUT , HEAD, DELETE, .... etc .

Examples:


    // include horus core
    require_once "Horus/Horus.php";
    
    // Construct it
    // Note that my server supports mod_rewrite, so i don't need simulator
    // And i'm working on PHP 5.4, so i use the new array style [], you can use array()
    new Horus( [ 'horus.use_router' => yes ] );
    
    // i'll use horus('router')-> or horus()->router->
    
    // Respond to a get request on the '/page-1' path
    horus('router') -> get('/page-1', function(){
        echo 'We are in get request';
    });
    
    // Respond to a post request on the '/page-1' path
    horus('router') -> post('/page-1', function(){
        echo 'We are in post request';
    });

    // Respond to a put request on the '/page-1' path
    horus('router') -> put('/page-1', function(){
        echo 'We are in put request';
    });
    
    // Respond to a put, get request on the '/page-1' path
    horus('router') -> put_get('/page-1', function(){
        echo 'We are in put or get request';
    });
    
    // Respond to a put, post get request on the '/page-1' path
    horus('router') -> put_post_get('/page-1', function(){
        echo 'We are in put,post or get request';
    });
    
    // Respond to all/any requests ( get, post, put, patch, ... etc ) on the '/page-1' path
    horus('router') -> any('/page-1', function(){
        echo 'We are in any request';
    });
    
    // And so, you can use any http method
    // just "horus('router') -> {method}($pattern, $callback)"
    

Supported Callbacks


Anonymous/Lambada Function


// after you included horus and started it

// sample usage
horus('router') -> any('/', function(){
    echo 'hello';
});

// with parameters
horus('router') -> any('/{alpha}', function($arg){
    echo 'hello ', $arg;
});

horus('router') -> any('/{alpha}/{num}', function($alpha, $num){
    echo 'hello ', $alpha, ' ', $num;
});

// NOTE: anonymous function is only available in PHP >= PHP 5.3

// You can use lambada
horus('router') -> any('/', create_function('', 'echo "hello";'));

# {alpha} is a regexp shortuct, all shortucts are:
# {num}     --->    ([0-9\.]+)          { example "152423" }
# {alpha}   --->    ([a-zA-Z]+)         { example: "mystring" }
# {alnum}   --->    ([a-zA-Z0-9\.]+)    { example: "mystring132.321" }
# {str}     --->    ([a-zA-Z0-9-_\.]+)  { example: "my-string_132.345" }
# {any}     --->    '.+'                { supports any char }
# {*}       --->    '?|(.*?)'           { to apply the callback on all sub-paths }

// you can set/unset shortcuts easily
horus('router')->shortcut('key', 'value');  //  add
horus('router')->unshortcut('key');         //  remove

Basic Function


// after you included horus and started it

// sample usage
function func_1()
{
    echo 'hello';
}
horus('router') -> any('/', 'func_1');

// with parameters
function func_2($name)
{
    echo "hello ", $name;
}
horus('router') -> any('/{alpha}', 'func_2');

function func_3($alpha, $num)
{
    echo 'hello ', $alpha, ' ', $num;
}
horus('router') -> any('/{alpha}/{num}', 'func_3');

Class methods


// after you included horus and started it

// Simple Class
Class Test
{
    public static function page1()
    {
        echo we are in "page1";
    }
    
    public function page2()
    {
        echo we are in "page2";
    }
    
    function insert()
    {
        // ...
    }
}

// construct it
$text = new Test;

// Route some methods from it
horus('router') -> any('/p1', 'Test::page1');
horus('router') -> any('/p2', array( $test, 'page2' ));
horus('router') -> any('/p2', [ $test, 'page2' ]); // only in PHP >= PHP 5.4

Class Routing


// after you included horus and started it

// Simple Class
Class Test2
{
    public function index()
    {
        // this method is important in each class
    }
    
    public function page1()
    {
        echo we are in "page1";
    }
    
    public function page2()
    {
        echo we are in "page2";
    }
    
    public function page_3()
    {
        echo 'page-3';
    }
}

// Route some methods from it
horus('router') -> any('/', 'Test2');
// Now each method works as a page .
// Now you can enter '/page1', '/page2', '/page_3', '/page-3', 'page-3.html', '/page1.php', '/index' and '/'
// You noticed that Horus Router converts '-' to '_' and ignore any '.extension' to be very easy

Nested Routes



// load and start horus
require 'Horus/Horus.php';
new Horus(['horus.use_horus'=>yes]);

horus('router')->any('/{*}', function(){
    echo "/ ";
    horus('router')->any('/page1/{*}', function(){
        echo "/page1/ ";
        horus('router')->any('page1/page2/', function(){
            echo "/page1/page2";
        });
    });
});



Routes and Permissions

this is a combination of router and session, that helps you restrict access to any route based on it's permission,


// load and start horus
require 'Horus/Horus.php';
new Horus(['horus.use_horus'=>yes]);

// start the session { using horus built-in session function }
session_init(3600); // started for 1 hour

// now to use routes permissions you must pass
// the user level/permission in the session array
$_SESSION['permission'] =  1;

// horus('router')->method('pattern', 'callback', 'permission(s)');
// permissions is by default '*' means any one can access it

// now create a route for only who has "1"
horus('router')->any('/admin', function($allowed){
    // the state of user ( allowed or not ) is passed
    // as last param. here i named it as "$allowed"
    if($allowed) echo 'ok';
    else 'access denied';
},1); // <--- NOTICE IT

// now create a route for only who has "1" or "2"
horus('router')->any('/admin', function($allowed){
    // the state of user ( allowed or not ) is passed
    // as last param. here i named it as "$allowed"
    if($allowed) echo 'ok';
    else 'access denied';
},array(1, 2)); // <--- NOTICE IT

// now create a route for all
horus('router')->any('/', function(){
    echo 'hi';
}); // <--- NOTICE IT

New view idea to save memory and be flexible ,


// load and start horus
require 'Horus/Horus.php';
new Horus;

// initialize view
// and set the views directory and views files extension
$view = new Horus_View('/views/', 'html');

// you can only $view = new Horus_View;
// and set the irectory and extension
$view->setup('/views/dir/', 'html');

// render any file , e.g: header
$view->render('header');

// render files , e.g: header, body, footer
$view->render('header ,body, footer');

// render and pass vars
$vars = array('var_1' => 'val_1'); // assoc array varname => value
$view->render('header', $vars);

// you can also load without renering
// also you can pass vars
$vars = array();
$output = $view->load('header', $vars);

// add global var(s)
$view->set('key', 'value');
#or
$view->set(array('key'=>'value'));

// get a var
echo $view->get('varname');

// delete/unset var(s)
$view->del('varname'); // or $view->del(array('varname1', 'varname2'));

// has a var ?
$view->has('varname'); // returns bool


    // after you included and started horus
    
    // start the view
    $lang = new Horus_Lang;
    
    // set the languages path and it's extension
    $lang -> setup('path/to/langs_dir', '.lang');
    
    // load a language file { the file must return an array contains keys => values }
    // say that we have lang-file "en.lang" then it's contents is
    /*
        <?php
            return array
            (
                'key1' => 'val1',
                'key2' => 'val2'
            );
        ?>
    */
    $lang->load('en');
    
    // add translations ( assoc-array )
    $lang -> add(array('key' => 'value'));
    
    // get a translation
    echo $lang->get('key');
    
    // translate full subject
    echo $lang->translate('my subject');
    

// after you included and started horus

// add/listen event
// horus('events')->listen('event_name', 'callback'),e.g:
horus('events')->listen('before.x', function(){
    echo 'before.x';
});

// fire/trigger event
// horus('events')->trigger('event_name', 'reverse or not: default false');
horus('events')->trigger('before.x');    

// event exists ?
horus('events')->has('before.x');

// remove !
horus('events')->remove('before.x');

// get all {array}
$events = horus('events')->get();

Horus Framework has built-in smart autoloader . by default it's registered using spl_autoload_register(), you can add your own, but here i'll speak about horus autoloader .
Horus Autoloader Converts any underscore and backslash to the system directory separator, based on the horus installation directory, so new Horus_View will converted to '/path/to/horus_installation/Horus/View.php' .


Examples:


# say that we have the next directory structure
/*

------------------------
    -\
    --\MyApp
    --\Horus
    --\index.php
    --\.htaccess
------------------------    

# when you call "new MyApp_ClassName", then horus autoloader will
  load "\MyApp\ClassName.php" or "\MyApp\ClassName\ClassName.php" then start it.

# e.g "new Horus_View" , then horus autoloader will
  load "\Horus\View.php" then start it.

# or "use \MyApp\Namespace\File" , then horus autoloader will
  load "\MyApp\Namespace\File.php" then start it.

------------------------

*/

// add new autoload path with it's alias/name "MY"
// every class will be with the prefix/namespace 'MY_' or '\MY\'
// just like "Horus_"
autoload_path_register('MY', 'path/to/folder');

// remove one
autoload_path_unregister('MY');


// after loading and starting horus
// lets create our custome container ( works like registry pattern )
$cc = new Horus_Container;

$cc->var = "value";
echo $cc->var;

$cc->method = function(){
    echo 'hi';
};

$cc->method();

$cc['x'] = 'y';
echo $cc['x'];

unset($cc->var);
unset($cc['var']);

isset($cc->var);

Horus Framework doesn't love any overhead so it extends PDO and simplified some things let's see it:


# start horus ...
$horus = new Horus;

# just like PDO to connect
$horus->db = new Horus_DB; // or horus()->db = ....
$horus->db->connect('dns', 'username', 'password', $options);

// OR

# Connect to mysql server
$horus->db->mysql('db server', 'db name', 'username', 'password');

# Connect to sqlite
$horus->db->sqlite('db_filepath');

# Connect to mssql {sql server} server
$horus->db->mssql('db server', 'db name', 'username', 'password');

# Connect to oracle server
$horus->db->oracle('db server', 'db name', 'username', 'password');

# Connect to postgre server
$horus->db->pgsql('db server', 'db name', 'username', 'password');

# create a query (improved function) 
# (and optionally pass array of binds inputs)
$horus->db->query(
    'select * from table where col1=? and col2 = ?', 
    array('value1', 'value2'
));

// fetch just what pdo does
var_dump($horus->db->fetchAll());

// Yes every thing from just from one object
// So i call it (PDO Improved) as it merged PDO with PDOStatement
// So you can access any method of them just from that object '$horus->db'


ORM

Horus Framework provides you a simple extensible ORM For the database
ORM is "Object Rational Mapper" for database operations, to simplify dealing with it .


// start horus
$horus = new Horus;

// use it
// you will need the horus_db construction
$horus->db = new Horus_DB;
$orm = new Horus_DB_ORM($horus->db);

// you can access any 'db' method from 'orm' too
$orm -> mysql('server', 'dbname', 'username', 'password');

// set the table
$users = $orm->on('users');

# insert
// insert into users(name, city, icon) values(?, ?, ?)
// return bool
$users->insert(array
( 
    'name'  =>  'user name',
    'city'  =>  'user city',
    'icon'  =>  'user icon'
))->end();

// only show the generated sql statement ?
echo $users->insert(array
( 
    'name'  =>  'user name',
    'city'  =>  'user city',
    'icon'  =>  'user icon'
))->getSQL();

// show the inputs only ?
dump($users->getInputs());
 

# update
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ?', 5)->end();

# or
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ? and name = ?', array(5, 'old name'))->end();

# or
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ? and name = ?')->inputs(array(5, 'old name'))->end();

# select
// return bool
$users->select('*')
                    ->where('id = ?', 5)
                    ->limit(1)
                    ->order('id', 'DESC')
                    ->end();
// now fetch, just like pdo, any fetch method
$users->fetchAll(PDO::FETCH_OBJ);

# delete
// return bool
$users->delete()->where('id' , 5)->end();

// you can also add a sql statement
$users->delete()->sql('where id = ?', 5)->end();
// or
$users->delete()->sql('where id = ?')->inputs(5)->end();

# you can add any feature !
# smart, advanced development
$users->multi_delete = function(array $ids){
    $inputs = $ids;
    $ids = array_fill(1, count($ids), '?');
    $ids = implode(', ', $inputs);
    
    horus()->orm->delete()->where('id in ('.$ids.')');
    horus()->orm->inputs($inputs);
    
    return horus()->orm->on(horus()->orm->table);
};
// now use it
$users->multi_delete(array(1, 12, 3));

Horus comes with simple common helpers that will help you while developing .

function dump($var, $var_dump = false)
Print var in human readable way
By default it uses print_r + pre but if you like var_dump + pre
just set $var_dump to true .


function headeri($string, $replace = false, $http_response_code = null)
An improved function instead of header() uses the new http class .


function go($to, $using = 302)
Redirect to another page using 302|301|'html'|'js'
example
go('http://google.com', 'js:5') redirect using javascript after 5 seconds, you could write 'js' only
go('http://google.com', 'html:5') redirect using html after 5 seconds, you could write 'html' only
go('http://google.com', 302) redirect using http-302
go('http://google.com', 301) redirect using http-301


function session_init($lifetime = 0)
Start new session (alternative to session_start())
$lifetime: the period (in sec) of the session, default 0 means 900 sec


function session_started()
check if the session is started .


function session_end()
Destroy session and free $_SESSION array .


function server($key = null)
get value from $_SERVER
example
echo server('request uri'); or echo server('request-uri'); or echo server('request_uri'); or echo server('request/uri'); or echo server('REQUEST_URI'); if $key is null will return all $_SERVER array


function is_https()
check if the request is using HTTPS, return bool


function is_ajax()
check if the request is under Ajax, return bool


function is_apache()
check if the server is apache, return bool


function is_cli()
check if the script run under Command line, return bool


function is_cgi()
check if the script run under CGI, return bool


function uri($to = null)
Generate uri to an internal page in horus application


function asset($to = null)
Generate direct url to an asset file in horus application


function random_str($length = 5)
Generate random string with a certain length


function random_serial($serials_count = 1, $blocks_count = 5, $block_size = 5, $separaor = '-')
Generate random serial .
$serials_count: how many serials do you need ?
$blocks_count: how many blocks per serials ?
$block_size: size of each block ?
$separator: the blocks delimiter ?


function limit_words($subject, $offset, $limit, $ends = ' ...')
Limit subject based on words, e.g: you need only 5 words from the start of subject and end it with ...: echo limit_words('this is test statement and this is test', 0, 5)


function array_insert(array $into, mixed $new, int $position)
insert array or element into any position of another array

example:


        $into = array(1,2,3,6,7);
        $new = array(4, 5);
        $position = 3;
        $result = array_insert($into, $new, $position);
        // will be: array(1, 2, 3, 4, 5, 6, 7)
    


function horus($using = null)
to get horus instance
function array_start(array $array)
to get the first element in an array

example:


        echo array_start(array(1,2,3,4,5));
        // will output '1'
    

function array_end(array $array)
to get the last element in an array

example:



        echo array_end(array(1,2,3,4,5));
        // will output '5'
    

function mdefine(array $defines)
just like define() but will work over an array

example:



        mdefine(array(
            'DS' => DIRECTORY_SEPARATOR,
            'NAME' => 'HORUS_FRAMEWORK',
        ));
        echo DS;
        echo NAME;
    

function mempty()
check whether var(s) empty

example:



        if(mempty($_GET['key1'], $_GET['key2'], $_GET['key3'])) {
            echo 'empty';
        }
    

function halt($code = 200, $message = null)
exit application and set status code and show message

example:



        halt(404, 'not found');
        // or
        halt(404, horus()->errDocs()->e404);
    

function password_hash($password, $algo = PASSWORD_DEFAULT, array $options = array())
Horus introduces this api in any PHP 5 version not only PHP 5.5, you don't need to upgrade to PHP 5.5 :D
Creates a new password hash using a strong one-way hashing algorithm.
See More Here Here
function password_get_info($hash)
See More Here Here
function password_needs_rehash($hash, $algo = PASSWORD_DEFAULT, array $options = array())
See More Here Here
function password_verify($password, $hash)
See More Here Here
function paginate($data_size, $current_page, $limit = 5, $link_format = '?p=%d', $max_links = 5)
Smart Tiny Pagination Function, No need to download big class for small operation ;)

example:



    // how many results to paginate ?
    $count = 45;
    // how many results per page ?
    $perpage = 5;
    // what is the current page ?
    $current = $_GET['p']; // we used site.com/?p=xxx as our pager counter
    // what is the target link format ?
    // i'll use site.com/?p=xxx where xxx is an integer, we replace
    // the integer parameter with '%d'
    // e.g: for site.com/?go=news&new=blog&p=%d
    $target = '?p=%d';
    // how many links do you want ?
    // < 1 2 3 4 5 > those are 5 
    $links = 5;
    // now paginate
    $p = paginate($count, $current, $perpage, $target, $links);
    // now the var '$p' is an array contains
    // 1)- pages_count  (how many pages)
    // 2)- start        (the offset used for e.g: 'select .... limit $start, $limit')
    // 3)- limit        (the data limit = perpage)
    // 4)- links[]      (array contains generated links)
    //                  they are: next, prev, current, first, last and (from 1 to links_limit)
    $sql = "select * from table limit {$p['start']},{$p['limit']}";
    $query = horus('db')->query($sql);
    while($row = horus('db')->fetch()) {
        // show data here
    }
    // show links ?
    foreach( $p['links'] as $name => $href) {
           echo sprintf(' %s     ', $href, $name);
    }
    // will print next prev first last current 1 2 3 4 5
    // note: if there is no prev, next, then the $href of them will be false
    // to help you detect it and make it "disabled=''"

function maili($from, $to, $subject, $message, $name = '',array $headers = array())
mail-[i]-mproved function

    // yourmail
    $from = 'yourmail@gmail.com';
    // to (supports multiple)
    $to =  'to@gmail.com'; // or array('m1@gmail.com', 'm2@gmail.com', ... );
    // subject
    $subject = 'test';
    // message [supports html, and also it set to utf-8]
    $message = 'hi this is message';
    // name [will show in target mailbox from ] "Optional"
    $name = 'myname';
    // more headers ? assoc array of your custom headers
    $headers  = array('Content-Type'=>'text/html; charset=UTF-8'); // this is the default
    // now send [ returns bool ]
    dump(maili($from, $to, $subject, $message, $name, $headers));

function str_clean($string)
Clean string from non-printable chars

// horus using events to extend it's core
// you will just use horus()->events->listen() to do it

# 1)- before sending the output to http manager ( 'horus.before.output' )

# 2)- after sending the output and finalizing ( 'horus.after.output' )

# NOTE: Horus output stored in a horus variable ( horus()->__output )

// example:

# minify the output
horus()->events->listen('horus.before_output', function(){
    horus()->__output = preg_replace('/\s+/', '', horus()->__output);
});

// -----------------------------

# you can use horus() as a container too .
horus()->myvar = 'value';
echo horus()->myvar;

horus()->func = function(){
    echo 'func';
}
horus()->func();

// ...