├── README.md ├── app ├── controllers │ ├── Controller.php │ └── MainController.php ├── models │ └── Messages.php └── views │ └── template.htm ├── composer.json ├── config.ini ├── index.php ├── routes.ini └── vendor ├── autoload.php ├── bcosca └── fatfree │ ├── .htaccess │ ├── composer.json │ ├── config.ini │ ├── index.php │ ├── lib │ ├── CHANGELOG │ ├── COPYING │ ├── audit.php │ ├── auth.php │ ├── base.php │ ├── basket.php │ ├── bcrypt.php │ ├── code.css │ ├── db │ │ ├── cursor.php │ │ ├── jig.php │ │ ├── jig │ │ │ ├── mapper.php │ │ │ └── session.php │ │ ├── mongo.php │ │ ├── mongo │ │ │ ├── mapper.php │ │ │ └── session.php │ │ ├── sql.php │ │ └── sql │ │ │ ├── mapper.php │ │ │ └── session.php │ ├── f3.php │ ├── image.php │ ├── log.php │ ├── magic.php │ ├── markdown.php │ ├── matrix.php │ ├── session.php │ ├── smtp.php │ ├── template.php │ ├── test.php │ ├── utf.php │ ├── web.php │ └── web │ │ ├── geo.php │ │ ├── google │ │ └── staticmap.php │ │ ├── openid.php │ │ └── pingback.php │ ├── readme.md │ └── ui │ ├── css │ ├── base.css │ └── theme.css │ ├── images │ ├── bitcoin.png │ ├── logo.png │ ├── paypal.png │ └── twitter.png │ ├── layout.htm │ ├── userref.htm │ └── welcome.htm └── composer ├── ClassLoader.php ├── autoload_classmap.php ├── autoload_files.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php └── installed.json /README.md: -------------------------------------------------------------------------------- 1 | # Fat-Free-PHP-MVC-Sample-Project 2 | 3 | This a sample project to kick-start an MVC web application based on the Fat-Free PHP Framework. 4 | 5 | The project is a result of a tutorial series that you can follow on http://takacsmark.com. 6 | 7 | The sample project works with a MySQL database. After cloning the repository update database configuration info in the config.ini file. 8 | 9 | You can run the project from the project directory by issuing the command "php -S localhost:8088 -t .". 10 | 11 | If you prefer to use your own web server, please make sure that it is configured to support f3 routing as described on http://fatfreeframework.com/routing-engine. 12 | -------------------------------------------------------------------------------- /app/controllers/Controller.php: -------------------------------------------------------------------------------- 1 | f3=$f3; 20 | 21 | $db=new DB\SQL( 22 | $f3->get('devdb'), 23 | $f3->get('devdbusername'), 24 | $f3->get('devdbpassword'), 25 | array( \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION ) 26 | ); 27 | 28 | $this->db=$db; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/controllers/MainController.php: -------------------------------------------------------------------------------- 1 | db); 8 | $message->key = 'Second message'; 9 | $message->message = 'This is the second message inserted from code'; 10 | $message->save(); 11 | 12 | $messages = new Messages($this->db); 13 | $msg = $messages->all()[0]; 14 | 15 | $this->f3->set('msg',$msg); 16 | $template=new Template; 17 | echo $template->render('template.htm'); 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /app/models/Messages.php: -------------------------------------------------------------------------------- 1 | load(); 11 | return $this->query; 12 | } 13 | 14 | public function getById($id) { 15 | $this->load(array('id=?',$id)); 16 | return $this->query; 17 | } 18 | 19 | public function add() { 20 | $this->copyFrom('POST'); 21 | $this->save(); 22 | } 23 | 24 | public function edit($id) { 25 | $this->load(array('id=?',$id)); 26 | $this->copyFrom('POST'); 27 | $this->update(); 28 | } 29 | 30 | public function delete($id) { 31 | $this->load(array('id=?',$id)); 32 | $this->erase(); 33 | } 34 | } -------------------------------------------------------------------------------- /app/views/template.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |{{ @msg.message }}
8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "takacsmark/fatfreetutorial1", 3 | "authors": [ 4 | { 5 | "name": "Mark Takacs", 6 | "email": "takacs.mark@gmail.com" 7 | } 8 | ], 9 | "require": { 10 | "bcosca/fatfree": "3.5.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [globals] 2 | 3 | DEBUG=3 4 | UI=app/views/ 5 | AUTOLOAD=app/controllers/|app/models/ 6 | 7 | devdb = "mysql:host=127.0.0.1;port=3306;dbname=f3MVC" 8 | devdbusername = "f3MVCadmin" 9 | devdbpassword = "f3MVCadmin" 10 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | config('config.ini'); 8 | $f3->config('routes.ini'); 9 | 10 | $f3->run(); 11 | -------------------------------------------------------------------------------- /routes.ini: -------------------------------------------------------------------------------- 1 | [routes] 2 | 3 | ;base routes 4 | GET /=MainController->render 5 | 6 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | =5.3.6" 8 | }, 9 | "repositories": [ 10 | { 11 | "type": "vcs", 12 | "url": "https://github.com/bcosca/fatfree" 13 | } 14 | ], 15 | "autoload": { 16 | "files": ["lib/base.php"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/config.ini: -------------------------------------------------------------------------------- 1 | [globals] 2 | 3 | DEBUG=3 4 | UI=ui/ 5 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/index.php: -------------------------------------------------------------------------------- 1 | set('DEBUG',1); 7 | if ((float)PCRE_VERSION<7.9) 8 | trigger_error('PCRE version is out of date'); 9 | 10 | // Load configuration 11 | $f3->config('config.ini'); 12 | 13 | $f3->route('GET /', 14 | function($f3) { 15 | $classes=array( 16 | 'Base'=> 17 | array( 18 | 'hash', 19 | 'json', 20 | 'session' 21 | ), 22 | 'Cache'=> 23 | array( 24 | 'apc', 25 | 'memcache', 26 | 'wincache', 27 | 'xcache' 28 | ), 29 | 'DB\SQL'=> 30 | array( 31 | 'pdo', 32 | 'pdo_dblib', 33 | 'pdo_mssql', 34 | 'pdo_mysql', 35 | 'pdo_odbc', 36 | 'pdo_pgsql', 37 | 'pdo_sqlite', 38 | 'pdo_sqlsrv' 39 | ), 40 | 'DB\Jig'=> 41 | array('json'), 42 | 'DB\Mongo'=> 43 | array( 44 | 'json', 45 | 'mongo' 46 | ), 47 | 'Auth'=> 48 | array('ldap','pdo'), 49 | 'Bcrypt'=> 50 | array( 51 | 'mcrypt', 52 | 'openssl' 53 | ), 54 | 'Image'=> 55 | array('gd'), 56 | 'Lexicon'=> 57 | array('iconv'), 58 | 'SMTP'=> 59 | array('openssl'), 60 | 'Web'=> 61 | array('curl','openssl','simplexml'), 62 | 'Web\Geo'=> 63 | array('geoip','json'), 64 | 'Web\OpenID'=> 65 | array('json','simplexml'), 66 | 'Web\Pingback'=> 67 | array('dom','xmlrpc') 68 | ); 69 | $f3->set('classes',$classes); 70 | $f3->set('content','welcome.htm'); 71 | echo View::instance()->render('layout.htm'); 72 | } 73 | ); 74 | 75 | $f3->route('GET /userref', 76 | function($f3) { 77 | $f3->set('content','userref.htm'); 78 | echo View::instance()->render('layout.htm'); 79 | } 80 | ); 81 | 82 | $f3->run(); 83 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/audit.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Data validator 24 | class Audit extends Prefab { 25 | 26 | //@{ User agents 27 | const 28 | UA_Mobile='android|blackberry|phone|ipod|palm|windows\s+ce', 29 | UA_Desktop='bsd|linux|os\s+[x9]|solaris|windows', 30 | UA_Bot='bot|crawl|slurp|spider'; 31 | //@} 32 | 33 | /** 34 | * Return TRUE if string is a valid URL 35 | * @return bool 36 | * @param $str string 37 | **/ 38 | function url($str) { 39 | return is_string(filter_var($str,FILTER_VALIDATE_URL)); 40 | } 41 | 42 | /** 43 | * Return TRUE if string is a valid e-mail address; 44 | * Check DNS MX records if specified 45 | * @return bool 46 | * @param $str string 47 | * @param $mx boolean 48 | **/ 49 | function email($str,$mx=TRUE) { 50 | $hosts=array(); 51 | return is_string(filter_var($str,FILTER_VALIDATE_EMAIL)) && 52 | (!$mx || getmxrr(substr($str,strrpos($str,'@')+1),$hosts)); 53 | } 54 | 55 | /** 56 | * Return TRUE if string is a valid IPV4 address 57 | * @return bool 58 | * @param $addr string 59 | **/ 60 | function ipv4($addr) { 61 | return (bool)filter_var($addr,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4); 62 | } 63 | 64 | /** 65 | * Return TRUE if string is a valid IPV6 address 66 | * @return bool 67 | * @param $addr string 68 | **/ 69 | function ipv6($addr) { 70 | return (bool)filter_var($addr,FILTER_VALIDATE_IP,FILTER_FLAG_IPV6); 71 | } 72 | 73 | /** 74 | * Return TRUE if IP address is within private range 75 | * @return bool 76 | * @param $addr string 77 | **/ 78 | function isprivate($addr) { 79 | return !(bool)filter_var($addr,FILTER_VALIDATE_IP, 80 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6|FILTER_FLAG_NO_PRIV_RANGE); 81 | } 82 | 83 | /** 84 | * Return TRUE if IP address is within reserved range 85 | * @return bool 86 | * @param $addr string 87 | **/ 88 | function isreserved($addr) { 89 | return !(bool)filter_var($addr,FILTER_VALIDATE_IP, 90 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6|FILTER_FLAG_NO_RES_RANGE); 91 | } 92 | 93 | /** 94 | * Return TRUE if IP address is neither private nor reserved 95 | * @return bool 96 | * @param $addr string 97 | **/ 98 | function ispublic($addr) { 99 | return (bool)filter_var($addr,FILTER_VALIDATE_IP, 100 | FILTER_FLAG_IPV4|FILTER_FLAG_IPV6| 101 | FILTER_FLAG_NO_PRIV_RANGE|FILTER_FLAG_NO_RES_RANGE); 102 | } 103 | 104 | /** 105 | * Return TRUE if user agent is a desktop browser 106 | * @return bool 107 | * @param $agent string 108 | **/ 109 | function isdesktop($agent=NULL) { 110 | if (!isset($agent)) 111 | $agent=Base::instance()->get('AGENT'); 112 | return (bool)preg_match('/('.self::UA_Desktop.')/i',$agent) && 113 | !$this->ismobile($agent); 114 | } 115 | 116 | /** 117 | * Return TRUE if user agent is a mobile device 118 | * @return bool 119 | * @param $agent string 120 | **/ 121 | function ismobile($agent=NULL) { 122 | if (!isset($agent)) 123 | $agent=Base::instance()->get('AGENT'); 124 | return (bool)preg_match('/('.self::UA_Mobile.')/i',$agent); 125 | } 126 | 127 | /** 128 | * Return TRUE if user agent is a Web bot 129 | * @return bool 130 | * @param $agent string 131 | **/ 132 | function isbot($agent=NULL) { 133 | if (!isset($agent)) 134 | $agent=Base::instance()->get('AGENT'); 135 | return (bool)preg_match('/('.self::UA_Bot.')/i',$agent); 136 | } 137 | 138 | /** 139 | * Return TRUE if specified ID has a valid (Luhn) Mod-10 check digit 140 | * @return bool 141 | * @param $id string 142 | **/ 143 | function mod10($id) { 144 | if (!ctype_digit($id)) 145 | return FALSE; 146 | $id=strrev($id); 147 | $sum=0; 148 | for ($i=0,$l=strlen($id);$i<$l;$i++) 149 | $sum+=$id[$i]+$i%2*(($id[$i]>4)*-4+$id[$i]%5); 150 | return !($sum%10); 151 | } 152 | 153 | /** 154 | * Return credit card type if number is valid 155 | * @return string|FALSE 156 | * @param $id string 157 | **/ 158 | function card($id) { 159 | $id=preg_replace('/[^\d]/','',$id); 160 | if ($this->mod10($id)) { 161 | if (preg_match('/^3[47][0-9]{13}$/',$id)) 162 | return 'American Express'; 163 | if (preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/',$id)) 164 | return 'Diners Club'; 165 | if (preg_match('/^6(?:011|5[0-9][0-9])[0-9]{12}$/',$id)) 166 | return 'Discover'; 167 | if (preg_match('/^(?:2131|1800|35\d{3})\d{11}$/',$id)) 168 | return 'JCB'; 169 | if (preg_match('/^5[1-5][0-9]{14}$/',$id)) 170 | return 'MasterCard'; 171 | if (preg_match('/^4[0-9]{12}(?:[0-9]{3})?$/',$id)) 172 | return 'Visa'; 173 | } 174 | return FALSE; 175 | } 176 | 177 | /** 178 | * Return entropy estimate of a password (NIST 800-63) 179 | * @return int|float 180 | * @param $str string 181 | **/ 182 | function entropy($str) { 183 | $len=strlen($str); 184 | return 4*min($len,1)+($len>1?(2*(min($len,8)-1)):0)+ 185 | ($len>8?(1.5*(min($len,20)-8)):0)+($len>20?($len-20):0)+ 186 | 6*(bool)(preg_match( 187 | '/[A-Z].*?[0-9[:punct:]]|[0-9[:punct:]].*?[A-Z]/',$str)); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/auth.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | 24 | //! Authorization/authentication plug-in 25 | class Auth { 26 | 27 | //@{ Error messages 28 | const 29 | E_LDAP='LDAP connection failure', 30 | E_SMTP='SMTP connection failure'; 31 | //@} 32 | 33 | protected 34 | //! Auth storage 35 | $storage, 36 | //! Mapper object 37 | $mapper, 38 | //! Storage options 39 | $args; 40 | 41 | /** 42 | * Jig storage handler 43 | * @return bool 44 | * @param $id string 45 | * @param $pw string 46 | * @param $realm string 47 | **/ 48 | protected function _jig($id,$pw,$realm) { 49 | return (bool) 50 | call_user_func_array( 51 | array($this->mapper,'load'), 52 | array( 53 | array_merge( 54 | array( 55 | '@'.$this->args['id'].'==? AND '. 56 | '@'.$this->args['pw'].'==?'. 57 | (isset($this->args['realm'])? 58 | (' AND @'.$this->args['realm'].'==?'):''), 59 | $id,$pw 60 | ), 61 | (isset($this->args['realm'])?array($realm):array()) 62 | ) 63 | ) 64 | ); 65 | } 66 | 67 | /** 68 | * MongoDB storage handler 69 | * @return bool 70 | * @param $id string 71 | * @param $pw string 72 | * @param $realm string 73 | **/ 74 | protected function _mongo($id,$pw,$realm) { 75 | return (bool) 76 | $this->mapper->load( 77 | array( 78 | $this->args['id']=>$id, 79 | $this->args['pw']=>$pw 80 | )+ 81 | (isset($this->args['realm'])? 82 | array($this->args['realm']=>$realm):array()) 83 | ); 84 | } 85 | 86 | /** 87 | * SQL storage handler 88 | * @return bool 89 | * @param $id string 90 | * @param $pw string 91 | * @param $realm string 92 | **/ 93 | protected function _sql($id,$pw,$realm) { 94 | return (bool) 95 | call_user_func_array( 96 | array($this->mapper,'load'), 97 | array( 98 | array_merge( 99 | array( 100 | $this->args['id'].'=? AND '. 101 | $this->args['pw'].'=?'. 102 | (isset($this->args['realm'])? 103 | (' AND '.$this->args['realm'].'=?'):''), 104 | $id,$pw 105 | ), 106 | (isset($this->args['realm'])?array($realm):array()) 107 | ) 108 | ) 109 | ); 110 | } 111 | 112 | /** 113 | * LDAP storage handler 114 | * @return bool 115 | * @param $id string 116 | * @param $pw string 117 | **/ 118 | protected function _ldap($id,$pw) { 119 | $dc=@ldap_connect($this->args['dc']); 120 | if ($dc && 121 | ldap_set_option($dc,LDAP_OPT_PROTOCOL_VERSION,3) && 122 | ldap_set_option($dc,LDAP_OPT_REFERRALS,0) && 123 | ldap_bind($dc,$this->args['rdn'],$this->args['pw']) && 124 | ($result=ldap_search($dc,$this->args['base_dn'], 125 | 'uid='.$id)) && 126 | ldap_count_entries($dc,$result) && 127 | ($info=ldap_get_entries($dc,$result)) && 128 | @ldap_bind($dc,$info[0]['dn'],$pw) && 129 | @ldap_close($dc)) { 130 | return $info[0]['uid'][0]==$id; 131 | } 132 | user_error(self::E_LDAP,E_USER_ERROR); 133 | } 134 | 135 | /** 136 | * SMTP storage handler 137 | * @return bool 138 | * @param $id string 139 | * @param $pw string 140 | **/ 141 | protected function _smtp($id,$pw) { 142 | $socket=@fsockopen( 143 | (strtolower($this->args['scheme'])=='ssl'? 144 | 'ssl://':'').$this->args['host'], 145 | $this->args['port']); 146 | $dialog=function($cmd=NULL) use($socket) { 147 | if (!is_null($cmd)) 148 | fputs($socket,$cmd."\r\n"); 149 | $reply=''; 150 | while (!feof($socket) && 151 | ($info=stream_get_meta_data($socket)) && 152 | !$info['timed_out'] && $str=fgets($socket,4096)) { 153 | $reply.=$str; 154 | if (preg_match('/(?:^|\n)\d{3} .+\r\n/s', 155 | $reply)) 156 | break; 157 | } 158 | return $reply; 159 | }; 160 | if ($socket) { 161 | stream_set_blocking($socket,TRUE); 162 | $dialog(); 163 | $fw=Base::instance(); 164 | $dialog('EHLO '.$fw->get('HOST')); 165 | if (strtolower($this->args['scheme'])=='tls') { 166 | $dialog('STARTTLS'); 167 | stream_socket_enable_crypto( 168 | $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT); 169 | $dialog('EHLO '.$fw->get('HOST')); 170 | } 171 | // Authenticate 172 | $dialog('AUTH LOGIN'); 173 | $dialog(base64_encode($id)); 174 | $reply=$dialog(base64_encode($pw)); 175 | $dialog('QUIT'); 176 | fclose($socket); 177 | return (bool)preg_match('/^235 /',$reply); 178 | } 179 | user_error(self::E_SMTP,E_USER_ERROR); 180 | } 181 | 182 | /** 183 | * Login auth mechanism 184 | * @return bool 185 | * @param $id string 186 | * @param $pw string 187 | * @param $realm string 188 | **/ 189 | function login($id,$pw,$realm=NULL) { 190 | return $this->{'_'.$this->storage}($id,$pw,$realm); 191 | } 192 | 193 | /** 194 | * HTTP basic auth mechanism 195 | * @return bool 196 | * @param $func callback 197 | **/ 198 | function basic($func=NULL) { 199 | $fw=Base::instance(); 200 | $realm=$fw->get('REALM'); 201 | $hdr=NULL; 202 | if (isset($_SERVER['HTTP_AUTHORIZATION'])) 203 | $hdr=$_SERVER['HTTP_AUTHORIZATION']; 204 | elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) 205 | $hdr=$_SERVER['REDIRECT_HTTP_AUTHORIZATION']; 206 | if (!empty($hdr)) 207 | list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])= 208 | explode(':',base64_decode(substr($hdr,6))); 209 | if (isset($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) && 210 | $this->login( 211 | $_SERVER['PHP_AUTH_USER'], 212 | $func? 213 | $fw->call($func,$_SERVER['PHP_AUTH_PW']): 214 | $_SERVER['PHP_AUTH_PW'], 215 | $realm 216 | )) 217 | return TRUE; 218 | if (PHP_SAPI!='cli') 219 | header('WWW-Authenticate: Basic realm="'.$realm.'"'); 220 | $fw->status(401); 221 | return FALSE; 222 | } 223 | 224 | /** 225 | * Instantiate class 226 | * @return object 227 | * @param $storage string|object 228 | * @param $args array 229 | **/ 230 | function __construct($storage,array $args=NULL) { 231 | if (is_object($storage) && is_a($storage,'DB\Cursor')) { 232 | $this->storage=$storage->dbtype(); 233 | $this->mapper=$storage; 234 | unset($ref); 235 | } 236 | else 237 | $this->storage=$storage; 238 | $this->args=$args; 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/basket.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Session-based pseudo-mapper 24 | class Basket extends Magic { 25 | 26 | //@{ Error messages 27 | const 28 | E_Field='Undefined field %s'; 29 | //@} 30 | 31 | protected 32 | //! Session key 33 | $key, 34 | //! Current item identifier 35 | $id, 36 | //! Current item contents 37 | $item=array(); 38 | 39 | /** 40 | * Return TRUE if field is defined 41 | * @return bool 42 | * @param $key string 43 | **/ 44 | function exists($key) { 45 | return array_key_exists($key,$this->item); 46 | } 47 | 48 | /** 49 | * Assign value to field 50 | * @return scalar|FALSE 51 | * @param $key string 52 | * @param $val scalar 53 | **/ 54 | function set($key,$val) { 55 | return ($key=='_id')?FALSE:($this->item[$key]=$val); 56 | } 57 | 58 | /** 59 | * Retrieve value of field 60 | * @return scalar|FALSE 61 | * @param $key string 62 | **/ 63 | function &get($key) { 64 | if ($key=='_id') 65 | return $this->id; 66 | if (array_key_exists($key,$this->item)) 67 | return $this->item[$key]; 68 | user_error(sprintf(self::E_Field,$key),E_USER_ERROR); 69 | return FALSE; 70 | } 71 | 72 | /** 73 | * Delete field 74 | * @return NULL 75 | * @param $key string 76 | **/ 77 | function clear($key) { 78 | unset($this->item[$key]); 79 | } 80 | 81 | /** 82 | * Return items that match key/value pair; 83 | * If no key/value pair specified, return all items 84 | * @return array 85 | * @param $key string 86 | * @param $val mixed 87 | **/ 88 | function find($key=NULL,$val=NULL) { 89 | $out=array(); 90 | if (isset($_SESSION[$this->key])) { 91 | foreach ($_SESSION[$this->key] as $id=>$item) 92 | if (!isset($key) || 93 | array_key_exists($key,$item) && $item[$key]==$val) { 94 | $obj=clone($this); 95 | $obj->id=$id; 96 | $obj->item=$item; 97 | $out[]=$obj; 98 | } 99 | } 100 | return $out; 101 | } 102 | 103 | /** 104 | * Return first item that matches key/value pair 105 | * @return object|FALSE 106 | * @param $key string 107 | * @param $val mixed 108 | **/ 109 | function findone($key,$val) { 110 | return ($data=$this->find($key,$val))?$data[0]:FALSE; 111 | } 112 | 113 | /** 114 | * Map current item to matching key/value pair 115 | * @return array 116 | * @param $key string 117 | * @param $val mixed 118 | **/ 119 | function load($key,$val) { 120 | if ($found=$this->find($key,$val)) { 121 | $this->id=$found[0]->id; 122 | return $this->item=$found[0]->item; 123 | } 124 | $this->reset(); 125 | return array(); 126 | } 127 | 128 | /** 129 | * Return TRUE if current item is empty/undefined 130 | * @return bool 131 | **/ 132 | function dry() { 133 | return !$this->item; 134 | } 135 | 136 | /** 137 | * Return number of items in basket 138 | * @return int 139 | **/ 140 | function count() { 141 | return isset($_SESSION[$this->key])?count($_SESSION[$this->key]):0; 142 | } 143 | 144 | /** 145 | * Save current item 146 | * @return array 147 | **/ 148 | function save() { 149 | if (!$this->id) 150 | $this->id=uniqid(NULL,TRUE); 151 | $_SESSION[$this->key][$this->id]=$this->item; 152 | return $this->item; 153 | } 154 | 155 | /** 156 | * Erase item matching key/value pair 157 | * @return bool 158 | * @param $key string 159 | * @param $val mixed 160 | **/ 161 | function erase($key,$val) { 162 | $found=$this->find($key,$val); 163 | if ($found && $id=$found[0]->id) { 164 | unset($_SESSION[$this->key][$id]); 165 | if ($id==$this->id) 166 | $this->reset(); 167 | return TRUE; 168 | } 169 | return FALSE; 170 | } 171 | 172 | /** 173 | * Reset cursor 174 | * @return NULL 175 | **/ 176 | function reset() { 177 | $this->id=NULL; 178 | $this->item=array(); 179 | } 180 | 181 | /** 182 | * Empty basket 183 | * @return NULL 184 | **/ 185 | function drop() { 186 | unset($_SESSION[$this->key]); 187 | } 188 | 189 | /** 190 | * Hydrate item using hive array variable 191 | * @return NULL 192 | * @param $var array|string 193 | **/ 194 | function copyfrom($var) { 195 | if (is_string($var)) 196 | $var=\Base::instance()->get($var); 197 | foreach ($var as $key=>$val) 198 | $this->item[$key]=$val; 199 | } 200 | 201 | /** 202 | * Populate hive array variable with item contents 203 | * @return NULL 204 | * @param $key string 205 | **/ 206 | function copyto($key) { 207 | $var=&\Base::instance()->ref($key); 208 | foreach ($this->item as $key=>$field) 209 | $var[$key]=$field; 210 | } 211 | 212 | /** 213 | * Check out basket contents 214 | * @return array 215 | **/ 216 | function checkout() { 217 | if (isset($_SESSION[$this->key])) { 218 | $out=$_SESSION[$this->key]; 219 | unset($_SESSION[$this->key]); 220 | return $out; 221 | } 222 | return array(); 223 | } 224 | 225 | /** 226 | * Instantiate class 227 | * @return void 228 | * @param $key string 229 | **/ 230 | function __construct($key='basket') { 231 | $this->key=$key; 232 | @session_start(); 233 | Base::instance()->sync('SESSION'); 234 | $this->reset(); 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/bcrypt.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | //! Lightweight password hashing library 24 | class Bcrypt extends Prefab { 25 | 26 | //@{ Error messages 27 | const 28 | E_CostArg='Invalid cost parameter', 29 | E_SaltArg='Salt must be at least 22 alphanumeric characters'; 30 | //@} 31 | 32 | //! Default cost 33 | const 34 | COST=10; 35 | 36 | /** 37 | * Generate bcrypt hash of string 38 | * @return string|FALSE 39 | * @param $pw string 40 | * @param $salt string 41 | * @param $cost int 42 | **/ 43 | function hash($pw,$salt=NULL,$cost=self::COST) { 44 | if ($cost<4 || $cost>31) 45 | user_error(self::E_CostArg,E_USER_ERROR); 46 | $len=22; 47 | if ($salt) { 48 | if (!preg_match('/^[[:alnum:]\.\/]{'.$len.',}$/',$salt)) 49 | user_error(self::E_SaltArg,E_USER_ERROR); 50 | } 51 | else { 52 | $raw=16; 53 | $iv=''; 54 | if (extension_loaded('mcrypt')) 55 | $iv=mcrypt_create_iv($raw,MCRYPT_DEV_URANDOM); 56 | if (!$iv && extension_loaded('openssl')) 57 | $iv=openssl_random_pseudo_bytes($raw); 58 | if (!$iv) 59 | for ($i=0;$i<$raw;$i++) 60 | $iv.=chr(mt_rand(0,255)); 61 | $salt=str_replace('+','.',base64_encode($iv)); 62 | } 63 | $salt=substr($salt,0,$len); 64 | $hash=crypt($pw,sprintf('$2y$%02d$',$cost).$salt); 65 | return strlen($hash)>13?$hash:FALSE; 66 | } 67 | 68 | /** 69 | * Check if password is still strong enough 70 | * @return bool 71 | * @param $hash string 72 | * @param $cost int 73 | **/ 74 | function needs_rehash($hash,$cost=self::COST) { 75 | list($pwcost)=sscanf($hash,"$2y$%d$"); 76 | return $pwcost<$cost; 77 | } 78 | 79 | /** 80 | * Verify password against hash using timing attack resistant approach 81 | * @return bool 82 | * @param $pw string 83 | * @param $hash string 84 | **/ 85 | function verify($pw,$hash) { 86 | $val=crypt($pw,$hash); 87 | $len=strlen($val); 88 | if ($len!=strlen($hash) || $len<14) 89 | return FALSE; 90 | $out=0; 91 | for ($i=0;$i<$len;$i++) 92 | $out|=(ord($val[$i])^ord($hash[$i])); 93 | return $out===0; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/code.css: -------------------------------------------------------------------------------- 1 | code{word-wrap:break-word;color:black}.comment,.doc_comment,.ml_comment{color:dimgray;font-style:italic}.variable{color:blueviolet}.const,.constant_encapsed_string,.class_c,.dir,.file,.func_c,.halt_compiler,.line,.method_c,.lnumber,.dnumber{color:crimson}.string,.and_equal,.boolean_and,.boolean_or,.concat_equal,.dec,.div_equal,.inc,.is_equal,.is_greater_or_equal,.is_identical,.is_not_equal,.is_not_identical,.is_smaller_or_equal,.logical_and,.logical_or,.logical_xor,.minus_equal,.mod_equal,.mul_equal,.ns_c,.ns_separator,.or_equal,.plus_equal,.sl,.sl_equal,.sr,.sr_equal,.xor_equal,.start_heredoc,.end_heredoc,.object_operator,.paamayim_nekudotayim{color:black}.abstract,.array,.array_cast,.as,.break,.case,.catch,.class,.clone,.continue,.declare,.default,.do,.echo,.else,.elseif,.empty.enddeclare,.endfor,.endforach,.endif,.endswitch,.endwhile,.eval,.exit,.extends,.final,.for,.foreach,.function,.global,.goto,.if,.implements,.include,.include_once,.instanceof,.interface,.isset,.list,.namespace,.new,.print,.private,.public,.protected,.require,.require_once,.return,.static,.switch,.throw,.try,.unset,.use,.var,.while{color:royalblue}.open_tag,.open_tag_with_echo,.close_tag{color:orange}.ini_section{color:black}.ini_key{color:royalblue}.ini_value{color:crimson}.xml_tag{color:dodgerblue}.xml_attr{color:blueviolet}.xml_data{color:red}.section{color:black}.directive{color:blue}.data{color:dimgray} 2 | -------------------------------------------------------------------------------- /vendor/bcosca/fatfree/lib/db/cursor.php: -------------------------------------------------------------------------------- 1 | . 20 | 21 | */ 22 | 23 | namespace DB; 24 | 25 | //! Simple cursor implementation 26 | abstract class Cursor extends \Magic implements \IteratorAggregate { 27 | 28 | //@{ Error messages 29 | const 30 | E_Field='Undefined field %s'; 31 | //@} 32 | 33 | protected 34 | //! Query results 35 | $query=array(), 36 | //! Current position 37 | $ptr=0, 38 | //! Event listeners 39 | $trigger=array(); 40 | 41 | /** 42 | * Return database type 43 | * @return string 44 | **/ 45 | abstract function dbtype(); 46 | 47 | /** 48 | * Return field names 49 | * @return array 50 | **/ 51 | abstract function fields(); 52 | 53 | /** 54 | * Return fields of mapper object as an associative array 55 | * @return array 56 | * @param $obj object 57 | **/ 58 | abstract function cast($obj=NULL); 59 | 60 | /** 61 | * Return records (array of mapper objects) that match criteria 62 | * @return array 63 | * @param $filter string|array 64 | * @param $options array 65 | * @param $ttl int 66 | **/ 67 | abstract function find($filter=NULL,array $options=NULL,$ttl=0); 68 | 69 | /** 70 | * Count records that match criteria 71 | * @return int 72 | * @param $filter array 73 | * @param $ttl int 74 | **/ 75 | abstract function count($filter=NULL,$ttl=0); 76 | 77 | /** 78 | * Insert new record 79 | * @return array 80 | **/ 81 | abstract function insert(); 82 | 83 | /** 84 | * Update current record 85 | * @return array 86 | **/ 87 | abstract function update(); 88 | 89 | /** 90 | * Hydrate mapper object using hive array variable 91 | * @return NULL 92 | * @param $var array|string 93 | * @param $func callback 94 | **/ 95 | abstract function copyfrom($var,$func=NULL); 96 | 97 | /** 98 | * Populate hive array variable with mapper fields 99 | * @return NULL 100 | * @param $key string 101 | **/ 102 | abstract function copyto($key); 103 | 104 | /** 105 | * Get cursor's equivalent external iterator 106 | * Causes a fatal error in PHP 5.3.5if uncommented 107 | * return ArrayIterator 108 | **/ 109 | abstract function getiterator(); 110 | 111 | 112 | /** 113 | * Return TRUE if current cursor position is not mapped to any record 114 | * @return bool 115 | **/ 116 | function dry() { 117 | return empty($this->query[$this->ptr]); 118 | } 119 | 120 | /** 121 | * Return first record (mapper object) that matches criteria 122 | * @return \DB\Cursor|FALSE 123 | * @param $filter string|array 124 | * @param $options array 125 | * @param $ttl int 126 | **/ 127 | function findone($filter=NULL,array $options=NULL,$ttl=0) { 128 | if (!$options) 129 | $options=array(); 130 | // Override limit 131 | $options['limit']=1; 132 | return ($data=$this->find($filter,$options,$ttl))?$data[0]:FALSE; 133 | } 134 | 135 | /** 136 | * Return array containing subset of records matching criteria, 137 | * total number of records in superset, specified limit, number of 138 | * subsets available, and actual subset position 139 | * @return array 140 | * @param $pos int 141 | * @param $size int 142 | * @param $filter string|array 143 | * @param $options array 144 | * @param $ttl int 145 | **/ 146 | function paginate( 147 | $pos=0,$size=10,$filter=NULL,array $options=NULL,$ttl=0) { 148 | $total=$this->count($filter,$ttl); 149 | $count=ceil($total/$size); 150 | $pos=max(0,min($pos,$count-1)); 151 | return array( 152 | 'subset'=>$this->find($filter, 153 | array_merge( 154 | $options?:array(), 155 | array('limit'=>$size,'offset'=>$pos*$size) 156 | ), 157 | $ttl 158 | ), 159 | 'total'=>$total, 160 | 'limit'=>$size, 161 | 'count'=>$count, 162 | 'pos'=>$pos<$count?$pos:0 163 | ); 164 | } 165 | 166 | /** 167 | * Map to first record that matches criteria 168 | * @return array|FALSE 169 | * @param $filter string|array 170 | * @param $options array 171 | * @param $ttl int 172 | **/ 173 | function load($filter=NULL,array $options=NULL,$ttl=0) { 174 | return ($this->query=$this->find($filter,$options,$ttl)) && 175 | $this->skip(0)?$this->query[$this->ptr=0]:FALSE; 176 | } 177 | 178 | /** 179 | * Return the count of records loaded 180 | * @return int 181 | **/ 182 | function loaded() { 183 | return count($this->query); 184 | } 185 | 186 | /** 187 | * Map to first record in cursor 188 | * @return mixed 189 | **/ 190 | function first() { 191 | return $this->skip(-$this->ptr); 192 | } 193 | 194 | /** 195 | * Map to last record in cursor 196 | * @return mixed 197 | **/ 198 | function last() { 199 | return $this->skip(($ofs=count($this->query)-$this->ptr)?$ofs-1:0); 200 | } 201 | 202 | /** 203 | * Map to nth record relative to current cursor position 204 | * @return mixed 205 | * @param $ofs int 206 | **/ 207 | function skip($ofs=1) { 208 | $this->ptr+=$ofs; 209 | return $this->ptr>-1 && $this->ptr'.$this->build($str).''."\n\n"):''; 41 | } 42 | 43 | /** 44 | * Process whitespace-prefixed code block 45 | * @return string 46 | * @param $str string 47 | **/ 48 | protected function _pre($str) { 49 | $str=preg_replace('/(?<=^|\n)(?: {4}|\t)(.+?(?:\n+|$))/','\1', 50 | $this->esc($str)); 51 | return strlen($str)? 52 | ('
'.
53 | $this->esc($this->snip($str)).
54 | '
'."\n\n"):
55 | '';
56 | }
57 |
58 | /**
59 | * Process fenced code block
60 | * @return string
61 | * @param $hint string
62 | * @param $str string
63 | **/
64 | protected function _fence($hint,$str) {
65 | $str=$this->snip($str);
66 | $fw=Base::instance();
67 | if ($fw->get('HIGHLIGHT')) {
68 | switch (strtolower($hint)) {
69 | case 'php':
70 | $str=$fw->highlight($str);
71 | break;
72 | case 'apache':
73 | preg_match_all('/(?<=^|\n)(\h*)'.
74 | '(?:(<\/?)(\w+)((?:\h+[^>]+)*)(>)|'.
75 | '(?:(\w+)(\h.+?)))(\h*(?:\n+|$))/',
76 | $str,$matches,PREG_SET_ORDER);
77 | $out='';
78 | foreach ($matches as $match)
79 | $out.=$match[1].
80 | ($match[3]?
81 | (''.
82 | $this->esc($match[2]).$match[3].
83 | ''.
84 | ($match[4]?
85 | (''.
86 | $this->esc($match[4]).
87 | ''):
88 | '').
89 | ''.
90 | $this->esc($match[5]).
91 | ''):
92 | (''.
93 | $match[6].
94 | ''.
95 | ''.
96 | $this->esc($match[7]).
97 | '')).
98 | $match[8];
99 | $str=''.$out.'
';
100 | break;
101 | case 'html':
102 | preg_match_all(
103 | '/(?:(?:<(\/?)(\w+)'.
104 | '((?:\h+(?:\w+\h*=\h*)?".+?"|[^>]+)*|'.
105 | '\h+.+?)(\h*\/?)>)|(.+?))/s',
106 | $str,$matches,PREG_SET_ORDER
107 | );
108 | $out='';
109 | foreach ($matches as $match) {
110 | if ($match[2]) {
111 | $out.='<'.
112 | $match[1].$match[2].'';
113 | if ($match[3]) {
114 | preg_match_all(
115 | '/(?:\h+(?:(?:(\w+)\h*=\h*)?'.
116 | '(".+?")|(.+)))/',
117 | $match[3],$parts,PREG_SET_ORDER
118 | );
119 | foreach ($parts as $part)
120 | $out.=' '.
121 | (empty($part[3])?
122 | ((empty($part[1])?
123 | '':
124 | (''.
125 | $part[1].'=')).
126 | ''.
127 | $part[2].''):
128 | (''.
129 | $part[3].''));
130 | }
131 | $out.=''.
132 | $match[4].'>';
133 | }
134 | else
135 | $out.=$this->esc($match[5]);
136 | }
137 | $str=''.$out.'
';
138 | break;
139 | case 'ini':
140 | preg_match_all(
141 | '/(?<=^|\n)(?:'.
142 | '(;[^\n]*)|(?:<\?php.+?\?>?)|'.
143 | '(?:\[(.+?)\])|'.
144 | '(.+?)\h*=\h*'.
145 | '((?:\\\\\h*\r?\n|.+?)*)'.
146 | ')((?:\r?\n)+|$)/',
147 | $str,$matches,PREG_SET_ORDER
148 | );
149 | $out='';
150 | foreach ($matches as $match) {
151 | if ($match[1])
152 | $out.=''.$match[1].
153 | '';
154 | elseif ($match[2])
155 | $out.='['.$match[2].']'.
156 | '';
157 | elseif ($match[3])
158 | $out.=''.$match[3].
159 | '='.
160 | ($match[4]?
161 | (''.
162 | $match[4].''):'');
163 | else
164 | $out.=$match[0];
165 | if (isset($match[5]))
166 | $out.=$match[5];
167 | }
168 | $str=''.$out.'
';
169 | break;
170 | default:
171 | $str=''.$this->esc($str).'
';
172 | break;
173 | }
174 | }
175 | else
176 | $str=''.$this->esc($str).'
';
177 | return ''.$str.''."\n\n"; 178 | } 179 | 180 | /** 181 | * Process horizontal rule 182 | * @return string 183 | **/ 184 | protected function _hr() { 185 | return '
'.$this->scan($str).'
'."\n\n"; 311 | } 312 | return ''; 313 | } 314 | 315 | /** 316 | * Process strong/em/strikethrough spans 317 | * @return string 318 | * @param $str string 319 | **/ 320 | protected function _text($str) { 321 | $tmp=''; 322 | while ($str!=$tmp) 323 | $str=preg_replace_callback( 324 | '/(?'.$expr[2].''; 329 | case 2: 330 | return ''.$expr[2].''; 331 | case 3: 332 | return ''.$expr[2].''; 333 | } 334 | }, 335 | preg_replace( 336 | '/(?\1', 338 | $tmp=$str 339 | ) 340 | ); 341 | return $str; 342 | } 343 | 344 | /** 345 | * Process image span 346 | * @return string 347 | * @param $str string 348 | **/ 349 | protected function _img($str) { 350 | $self=$this; 351 | return preg_replace_callback( 352 | '/!(?:\[(.+?)\])?\h*\((.*?)>?(?:\h*"(.*?)"\h*)?\)/', 353 | function($expr) use($self) { 354 | return 'The first thing you might want to do is visualize your directory structures. Fat-Free gives you total control over your Web site. Organize your folders in any way that pleases you (or your development team if you're part of a group). Decide where you want to store the following:
7 |For security reasons, consider relocating the lib/
folder to a path that's not Web-accessible. If you decide to move this folder, just change the line in index.php
containing require 'lib/base.php';
so it points to the new location. The lib/
folder also contains framework plug-ins that extend F3's capabilities. You can change the default location of all plug-ins by moving the files to your desired subdirectory. Then, it's just a matter of pointing the PLUGINS
global variable to the new location. You may delete the plug-ins that you don't need. You can reinstate them later as you find necessary.
F3 can autoload OOP classes for you. Just add the path to the AUTOLOAD
variable.
When you're ready to write your F3-enabled site, you can start editing the rest of the code contained in the index.php
file that displayed this Web page. Developing PHP applications will never be the same!
Some framework features in this version will not be available if PHP is not configured with the modules needed by your application.
21 |Class/Plug-in | 24 |PHP Module | 25 |
---|---|
29 | |
30 |
31 | onclick="return false"> 32 | 33 | |
34 |
Base
class requires all listed PHP modules enabled to function properly.Cache
class will use any available module in the list. If none can be found, it will use the filesystem as fallback.DB\SQL
class requires the pdo
module and a PDO driver relevant to your application.Bcrypt
class will use the mcrypt
or openssl
module for entropy generation. Otherwise, it employs a custom random function.Web
class will use the curl
module for HTTP requests to another server. If this is not detected, it will use other transports available, such as the HTTP stream wrapper or native sockets.geoip
module listed in the Web\Geo
class is optional; the class will use an alternative Web service for geo-location.If you have any questions regarding the framework, technical support is available at https://groups.google.com/forum/?fromgroups#!forum/f3-framework
Need live support? You can talk to the development team and the rest of the Fat-Free community via IRC. We're on the FreeNode (chat.freenode.net
) #fatfree
channel. If the channel appears quiet, the development team might just be busy with the next great release, or it's probably due to time zone differences. Just hang around.
The User Reference is designed to serve as a handbook and programming guide. However, the online documentation at https://github.com/bcosca/fatfree
provides the latest and most comprehensive information about the framework.
Take a close look at the Fat-Free API Documentation for in-depth information about the framework.
51 |Fat-Free Framework is free software covered by the terms of the GNU Public License (GPL v3). You may not use the software, documentation, and samples except in compliance with the license. If the terms and conditions of this license are too restrictive for your use, alternative licensing is available for a very reasonable fee.
53 |If you feel that this software is one great weapon to have in your programming arsenal, it saves you a lot of time and money, use it for commercial gain or in your business organization, please consider making a donation to the project. A significant amount of time, effort, and money has been spent on this project. Your donations help keep this project alive and the development team motivated. Donors and sponsors get priority support commensurate to your contribution (24-hour response time on business days).
54 |F3 is community-driven software. Support the development of the Fat-Free Framework. Your contributions help keep this project alive.
56 | 57 |