├── .gitignore ├── .htaccess ├── LICENSE.txt ├── README.md ├── SlimJim.png ├── admin ├── .htaccess ├── css │ ├── bootstrap.css │ └── slimjim.css ├── index.php └── templates │ ├── home.php │ ├── layouts │ ├── default.php │ └── login.php │ ├── loginForm.php │ ├── profile │ └── profile.php │ ├── projects │ ├── addProject.php │ └── projects.php │ └── settings │ ├── addSetting.php │ └── settings.php ├── config.sample.php ├── deploy.php ├── index.php ├── libs ├── Paris │ ├── idiorm.php │ └── paris.php ├── Slim │ ├── CustomView.php │ ├── Environment.php │ ├── Exception │ │ ├── Pass.php │ │ ├── RequestSlash.php │ │ └── Stop.php │ ├── Http │ │ ├── Headers.php │ │ ├── Request.php │ │ ├── Response.php │ │ └── Util.php │ ├── Log.php │ ├── LogFileWriter.php │ ├── Middleware.php │ ├── Middleware │ │ ├── ContentTypes.php │ │ ├── Flash.php │ │ ├── MethodOverride.php │ │ ├── PrettyExceptions.php │ │ └── SessionCookie.php │ ├── Route.php │ ├── Router.php │ ├── Slim.php │ └── View.php └── spyc.php ├── models ├── Admin.php ├── Project.php └── Setting.php ├── requests └── empty └── slimjim.sql /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *.rej 7 | *.swo 8 | *.swp 9 | *.vi 10 | *~ 11 | *.sass-cache 12 | 13 | # OS or Editor folders 14 | .DS_Store 15 | Thumbs.db 16 | .cache 17 | .project 18 | .settings 19 | .tmproj 20 | *.esproj 21 | nbproject 22 | 23 | # Dreamweaver added files 24 | _notes 25 | dwsync.xml 26 | 27 | # Komodo 28 | *.komodoproject 29 | .komodotools 30 | 31 | # Folders to ignore 32 | .hg 33 | .svn 34 | .CVS 35 | intermediate 36 | publish 37 | .idea 38 | requests/* 39 | 40 | # Custom configuration to ignore 41 | /config.php -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # Disable MultiViews, If this is not turned off it may cause 2 | # the redirection of /deploy to go to /deploy.php 3 | Options -MultiViews 4 | 5 | RewriteEngine On 6 | 7 | # Some hosts may require you to use the `RewriteBase` directive. 8 | # If you need to use the `RewriteBase` directive, it should be the 9 | # absolute physical path to the directory that contains this htaccess file. 10 | # 11 | # RewriteBase / 12 | 13 | RewriteCond %{REQUEST_FILENAME} !-f 14 | RewriteRule ^ index.php [QSA,L] 15 | 16 | # Deny access to config.php 17 | 18 | Order Allow,Deny 19 | Deny from all 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jesal Gadhia 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SlimJim 2 | ======= 3 | 4 | ### WHY? 5 | 6 | SlimJim was born out of a need for a simple auto update script which would update multiple development/test environments every time someone commits to their respective GitHub or BitBucket repositories. 7 | 8 | I know there are many deployment/build scripts out there like whiskey_disk, Vlad and Capistrano which can do this if coupled with a CI server like cijoe, Jenkins, etc. 9 | 10 | But I found them to be more complicated to setup just for a basic need i.e to simply update a development/test environment using a post-receive hook without any manual user interaction on behalf of the committer besides ``git push...`` 11 | 12 | ![How SlimJim Works](/SlimJim.png "How SlimJim Works") 13 | 14 | ### INSTALLATION 15 | 16 | To configure SlimJim on your server just follow these 4 steps: 17 | 18 | 1) **Setup site and DB** 19 | 20 | Basic LAMP website setup should suffice. Everything you need is in this repo. I'm using a PHP micro-framework called Slim (thus the name!) which requires PHP 5.3.0 or newer. 21 | 22 | Run `slimjim.sql` on your MySql server. 23 | 24 | Copy `config.sample.php` to `config.php` in the root folder and modify the following variables as needed: 25 | 26 | class CUSTOM_CONFIG { 27 | /* Paths */ 28 | public static $ROOT_PATH = '/srv/www/slimjim.yourcompany.com/public_html/'; 29 | 30 | /* MySQL */ 31 | public static $DB_NAME = 'slimjim'; 32 | public static $DB_HOST = 'localhost'; 33 | public static $DB_USER = 'root'; 34 | public static $DB_PASS = ''; 35 | } 36 | 37 | For all the projects that you want to auto-update, add the name of the github repo, branch and the physical path on your server to the projects table. 38 | 39 | Alternatively, you can also manage projects and other settings by going to the administrative interface located at /admin 40 | 41 | 2) **Install & setup [incron](http://inotify.aiken.cz/?section=incron&page=about&lang=en)** 42 | 43 | When the site receives a payload from the post-receive hook it will drop a request in the /requests folder. Incron is needed to listen for that event and trigger the deploy script. 44 | 45 | ``root@yourhost:/# apt-get install incron`` 46 | 47 | Add the root user to your allow list 48 | 49 | ``root@yourhost:/# vi /etc/incron.allow`` 50 | 51 | Add this, save and quit: 52 | 53 | ``root`` 54 | 55 | Now watch your requests directory for updates 56 | 57 | ``root@yourhost:/# incrontab -e`` 58 | 59 | Add this, save and quit: 60 | 61 | ``/srv/www/slimjim.yourcompany.com/public_html/requests/ IN_CLOSE_WRITE php /srv/www/slimjim.yourcompany.com/public_html/deploy.php $#`` 62 | 63 | 3) **Permissions** 64 | 65 | Give execute permissions to the deploy script 66 | 67 | ``root@yourhost:/# chmod +x deploy.php`` 68 | 69 | Allow writing to the requests folder 70 | 71 | ``root@yourhost:/# chmod 777 /srv/www/slimjim.yourcompany.com/public_html/requests`` 72 | 73 | Give permissions to pull from github to the root user (make sure to leave the password empty) 74 | 75 | ``root@yourhost:/# ssh-keygen -t rsa -C "root@yourhost"`` 76 | 77 | Copy the contents from ~/.ssh/id_rsa.pub and [add to GitHub][1] or [add to BitBucket][2] 78 | 79 | 4) **Add Post-Receive Webhook** 80 | 81 | Finally, add the appropriate one of these URLs as a webhook into your repository settings: 82 | 83 | For GitHub: ``http://slimjim.yourcompany.com/gh_hook`` 84 | 85 | For BitBucket: ``http://slimjim.yourcompany.com/bb_hook`` 86 | 87 | That's it! Now sit back and watch SlimJim do the tedious work! :) 88 | 89 | ### CONTRIBUTE! 90 | 91 | Now if you like what this does, feel free to improve upon code. Just follow these steps to contribute: 92 | 93 | 1. Fork it 94 | 2. Create your feature branch (``git checkout -b my-new-feature``) 95 | 3. Commit your changes (``git commit -am 'Add some feature'``) 96 | 4. Push to the branch (``git push origin my-new-feature``) 97 | 5. Issue a [pull request](https://help.github.com/articles/using-pull-requests) to my **develop** branch 98 | 6. I will test out your cool feature on develop and do a release to master soon thereafter! :) 99 | 100 | 101 | [1]: https://help.github.com/articles/generating-ssh-keys 102 | [2]: https://confluence.atlassian.com/display/BITBUCKET/Add+an+SSH+key+to+an+account -------------------------------------------------------------------------------- /SlimJim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesalg/SlimJim/5908cccf2b496496c1bb4a0fecca9e4f7d337458/SlimJim.png -------------------------------------------------------------------------------- /admin/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | # Some hosts may require you to use the `RewriteBase` directive. 4 | # If you need to use the `RewriteBase` directive, it should be the 5 | # absolute physical path to the directory that contains this htaccess file. 6 | # 7 | # RewriteBase / 8 | 9 | RewriteCond %{REQUEST_FILENAME} !-f 10 | RewriteRule ^ index.php [QSA,L] -------------------------------------------------------------------------------- /admin/css/slimjim.css: -------------------------------------------------------------------------------- 1 | /* 2 | Document : slimjim 3 | Created on : Sep 13, 2012, 3:11:48 PM 4 | Author : atorres 5 | Description: 6 | Purpose of the stylesheet follows. 7 | */ 8 | 9 | .header:after { 10 | bottom: 0; 11 | content: ""; 12 | display: block; 13 | left: 0; 14 | opacity: 0.4; 15 | position: absolute; 16 | right: 0; 17 | top: 0; 18 | } 19 | .masthead { 20 | color: #FFFFFF; 21 | margin-bottom: 0; 22 | padding: 70px 0 80px; 23 | } 24 | .header { 25 | background: -moz-linear-gradient(45deg, #020031 0%, #6D3353 100%) repeat scroll 0 0 transparent; background: -webkit-linear-gradient(45deg, #020031 0%, #6D3353 100%) repeat scroll 0 0 transparent; 26 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.2) inset, 0 -3px 7px rgba(0, 0, 0, 0.2) inset; 27 | color: #FFFFFF; 28 | padding: 40px 0; 29 | position: relative; 30 | text-align: center; 31 | text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 30px rgba(0, 0, 0, 0.075); 32 | } 33 | 34 | #data-content{ 35 | max-width: 950px; 36 | margin: 0px auto; 37 | margin-top: 100px; 38 | margin-bottom: 100px; 39 | } 40 | 41 | #footer { 42 | position:fixed; 43 | bottom:0; 44 | width:100%; 45 | background: -moz-linear-gradient(45deg, #020031 0%, #6D3353 100%) repeat scroll 0 0 transparent; background: -webkit-linear-gradient(45deg, #020031 0%, #6D3353 100%) repeat scroll 0 0 transparent; 46 | box-shadow: 0 3px 7px rgba(0, 0, 0, 0.2) inset, 0 -3px 7px rgba(0, 0, 0, 0.2) inset; 47 | color: #FFFFFF; 48 | padding: 10px; 49 | text-align: center; 50 | } 51 | 52 | #flash-message{ 53 | text-align: center; 54 | margin-top: 10px; 55 | margin-bottom: 10px; 56 | } 57 | 58 | #flash-message .success{ 59 | padding: 10px; 60 | background-color: #DFF0D8; 61 | } 62 | 63 | #flash-message .error{ 64 | padding: 10px; 65 | background-color: #F2DEDE; 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /admin/index.php: -------------------------------------------------------------------------------- 1 | new CustomView() 21 | )); 22 | 23 | $app->add(new Slim_Middleware_SessionCookie(array( 24 | 'expires' => '1440 minutes', 25 | 'name' => 'slim_session', 26 | 'secret' => 'slimjim' 27 | ))); 28 | 29 | $app->add(new Slim_Middleware_Flash()); 30 | 31 | //default layout 32 | CustomView::set_layout('/layouts/default.php'); 33 | 34 | //Set base URL 35 | $app->hook('slim.before', function () use ($app) { 36 | if(isset($_SERVER['HTTP_HOST'])){ 37 | $base_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; 38 | $base_url .= '://'. $_SERVER['HTTP_HOST']; 39 | $base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); 40 | }else{ 41 | $base_url = 'http://localhost'; 42 | } 43 | 44 | define('base_url', $base_url); 45 | }); 46 | 47 | // Auth Check. 48 | $authCheck = function() use ($app) { 49 | if (!isset($_SESSION['username'])) { 50 | CustomView::set_layout('/layouts/login.php'); 51 | $app->render('loginForm.php', array()); 52 | exit; 53 | } 54 | }; 55 | 56 | //Admin Home 57 | $app->get('/', $authCheck, function () use ($app) { 58 | $data['currNav'] = 'home'; 59 | 60 | $app->render('home.php', array('data' => $data)); 61 | }); 62 | 63 | //Validate the username and password 64 | $app->post('/login', function () use ($app) { 65 | if($app->request()->isPost()){ 66 | $req = $app->request(); 67 | $inputUsername = $req->post('username'); 68 | $inputpassword = $req->post('password'); 69 | 70 | $user = Model::factory('Admin') 71 | ->where_equal('username', $inputUsername) 72 | ->where_equal('password', md5($inputpassword)) 73 | ->find_one(); 74 | if(isset($user->username)){ 75 | if($user->username == $inputUsername){ 76 | $_SESSION['username'] = $inputUsername; 77 | $app->flash('success', 'Welcome ' . $inputUsername); 78 | } 79 | }else{ 80 | $app->flash('error', 'User does not exist!'); 81 | } 82 | }else{ 83 | $app->flash('error', 'you must insert your credentials!'); 84 | } 85 | 86 | $app->redirect('/admin'); 87 | }); 88 | 89 | //Logout 90 | $app->get('/logout', function () use ($app) { 91 | $_SESSION = array(); 92 | 93 | $data['currNav'] = 'home'; 94 | $app->flash('error', 'You are logged out!'); 95 | $app->redirect('/admin', array('data' => $data)); 96 | }); 97 | 98 | //Show Projects 99 | $app->get('/projects', $authCheck, function () use ($app) { 100 | $data['projects'] = Model::factory('Project')->find_many(); 101 | $data['currNav'] = 'projects'; 102 | $app->render('projects/projects.php', array('data' => $data)); 103 | }); 104 | 105 | //Add and edit project 106 | $app->get('/projects/add/:id', $authCheck, function ($id = 0) use ($app) { 107 | $data['currNav'] = 'projects'; 108 | 109 | //Edit 110 | if($id > 0){ 111 | $data['project'] = ORM::for_table('projects')->find_one($id); 112 | } 113 | 114 | $app->render('projects/addProject.php', array('data' => $data)); 115 | }); 116 | 117 | //Create new project or edit it 118 | $app->post('/projects/add', $authCheck, function () use ($app) { 119 | $data['currNav'] = 'projects'; 120 | $data['projects'] = Model::factory('Project')->find_many(); 121 | 122 | //Validate 123 | if($app->request()->post('clone_url')){ 124 | 125 | //Edit 126 | if($app->request()->post('id')){ 127 | $project = ORM::for_table('projects')->find_one($app->request()->post('id')); 128 | $app->flash('success', 'Project updated!'); 129 | 130 | }else{ //New Item 131 | $project = ORM::for_table('projects')->create(); 132 | $app->flash('success', 'Project created!'); 133 | } 134 | 135 | $project->clone_url = $app->request()->post('clone_url'); 136 | $project->name = $app->request()->post('name'); 137 | $project->branch = $app->request()->post('branch'); 138 | $project->path = $app->request()->post('path'); 139 | $project->save(); 140 | }else{ 141 | $app->flash('error', 'Project could not be created!'); 142 | } 143 | 144 | $app->redirect('/admin/projects', array('data' => $data)); 145 | }); 146 | 147 | //Remove the project 148 | $app->get('/projects/delete/:id', $authCheck, function ($id) use ($app){ 149 | $data['currNav'] = 'projects'; 150 | $data['projects'] = Model::factory('Project')->find_many(); 151 | 152 | $project = ORM::for_table('projects')->find_one($id); 153 | $project->delete(); 154 | 155 | $app->flash('error', 'Project Removed!'); 156 | 157 | $app->redirect('/admin/projects', array('data' => $data)); 158 | }); 159 | 160 | //Show settings 161 | $app->get('/settings', $authCheck, function () use ($app) { 162 | $data['currNav'] = 'settings'; 163 | $data['settings'] = Model::factory('Setting')->find_many(); 164 | 165 | $app->render('settings/settings.php', array('data' => $data)); 166 | }); 167 | 168 | //Add and edit settings form 169 | $app->get('/settings/add/:id', $authCheck, function ($id) use ($app) { 170 | $data['currNav'] = 'settings'; 171 | 172 | //Edit 173 | if($id > 0){ 174 | $data['setting'] = ORM::for_table('settings')->find_one($id); 175 | } 176 | 177 | $app->render('settings/addSetting.php', array('data' => $data)); 178 | }); 179 | 180 | //Create new setting or edit it 181 | $app->post('/settings/add', $authCheck, function () use ($app) { 182 | $data['currNav'] = 'settings'; 183 | $data['settings'] = Model::factory('Setting')->find_many(); 184 | 185 | //Validate 186 | if($app->request()->post('key') != ''){ 187 | 188 | //Edit 189 | if($app->request()->post('id')){ 190 | $setting = ORM::for_table('settings')->find_one($app->request()->post('id')); 191 | $app->flash('success', 'Setting updated!'); 192 | 193 | }else{ //New Item 194 | $setting = ORM::for_table('settings')->create(); 195 | $app->flash('success', 'Setting created!'); 196 | } 197 | 198 | $setting->key = $app->request()->post('key'); 199 | $setting->value = $app->request()->post('value'); 200 | $setting->save(); 201 | }else{ 202 | $app->flash('error', 'Setting could not be created!'); 203 | } 204 | 205 | $app->redirect('/admin/settings', array('data' => $data)); 206 | }); 207 | 208 | //Remove the setting 209 | $app->get('/settings/delete/:id', $authCheck, function ($id) use ($app){ 210 | $data['currNav'] = 'settings'; 211 | $data['settings'] = Model::factory('Setting')->find_many(); 212 | 213 | $setting = ORM::for_table('settings')->find_one($id); 214 | $setting->delete(); 215 | 216 | $app->flash('success', 'Setting Removed!'); 217 | 218 | $app->redirect('/admin/settings', array('data' => $data)); 219 | }); 220 | 221 | //Show change password form 222 | $app->get('/profile', $authCheck, function () use ($app) { 223 | $data['currNav'] = 'profile'; 224 | $app->render('profile/profile.php', array('data' => $data)); 225 | }); 226 | 227 | //Change the password 228 | $app->post('/profile', $authCheck, function () use ($app) { 229 | $data['currNav'] = 'profile'; 230 | if($app->request()->post('password') == '' || $app->request()->post('repassword') == ''){ 231 | $app->flashNow('error', 'Please inset a valid password!'); 232 | }elseif($app->request()->post('password') == $app->request()->post('repassword')){ 233 | $user = ORM::for_table('admins')->where('username', 'admin')->find_one(); 234 | $user->password = md5($app->request()->post('password')); 235 | 236 | $user->save(); 237 | $app->flashNow('success', 'Password Saved!'); 238 | }else{ 239 | $app->flashNow('error', 'Password did not match, Please try again!'); 240 | } 241 | 242 | $app->render('profile/profile.php', array('data' => $data)); 243 | }); 244 | 245 | 246 | $app->run(); 247 | 248 | ?> 249 | -------------------------------------------------------------------------------- /admin/templates/home.php: -------------------------------------------------------------------------------- 1 |
2 |

Welcome ! Add your project information and project settings and watch SlimJim do the work for you.

3 |

Please click Projects to manage your projects information, you can add, edit or delete information

4 |

Modify your Settings in this link.

5 |

Do not forget to change your default password here

6 |
-------------------------------------------------------------------------------- /admin/templates/layouts/default.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SlimJim CMS 6 | 7 | 8 | 9 | 10 | 11 | 12 | 40 | 41 |
42 |
43 |

SlimJim Admin

44 |

Manage your auto deploy settings.

45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 |
53 | 54 |
55 | 56 | 57 |
58 | 59 |
60 | 61 |
62 | 63 | 64 |
65 | 66 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /admin/templates/layouts/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SlimJim CMS 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

SlimJim Log In

15 |

Manage your auto deploy settings.

16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /admin/templates/loginForm.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Sign In 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 |
-------------------------------------------------------------------------------- /admin/templates/profile/profile.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Change Password 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 |
-------------------------------------------------------------------------------- /admin/templates/projects/addProject.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Add a project 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 | 20 |
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 | id)):?> 29 | 30 | 31 |
32 |
33 | 34 |
35 |
36 |
37 |
-------------------------------------------------------------------------------- /admin/templates/projects/projects.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Add New Project 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
clone_urlnamebranchpathactions
clone_url?>name?>branch?>path?>Edit Remove
27 |
-------------------------------------------------------------------------------- /admin/templates/settings/addSetting.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Add a setting 4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 |
16 | id)):?> 17 | 18 | 19 |
20 |
21 | 22 |
23 |
24 |
25 |
-------------------------------------------------------------------------------- /admin/templates/settings/settings.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | Add New Setting 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
keyvalueactions
key?>value?>Edit Remove
23 |
-------------------------------------------------------------------------------- /config.sample.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | &1")); 30 | } 31 | 32 | sleep(1); 33 | 34 | $hooks = @ Spyc::YAMLLoad($request_data['hook_path']) ?: array(); 35 | 36 | syslog(LOG_INFO, serialize($hooks)); 37 | 38 | if(isset($hooks['writable'])) { 39 | foreach($hooks['writable'] AS $make_writeable) { 40 | $cmd = "chmod 777 -R " . $make_writeable . " 2>&1"; 41 | syslog(LOG_INFO, $cmd); 42 | syslog(LOG_INFO, "===== " . shell_exec($cmd)); 43 | } 44 | } 45 | 46 | if(isset($hooks['after_deploy'])) { 47 | foreach($hooks['after_deploy'] AS $after_deploy) { 48 | $cmd = $after_deploy . " 2>&1"; 49 | syslog(LOG_INFO, $cmd); 50 | syslog(LOG_INFO, "===== " . shell_exec($cmd)); 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | find_many() ?: array()) AS $obj) { 16 | $settings[$obj->key] = $obj->value; 17 | } 18 | 19 | $app = new Slim(array( 20 | 'settings' => $settings 21 | )); 22 | 23 | function get_github_meta() { 24 | $curl_handle=curl_init(); 25 | curl_setopt($curl_handle, CURLOPT_URL,'https://api.github.com/meta'); 26 | curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2); 27 | curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); 28 | curl_setopt($curl_handle, CURLOPT_USERAGENT, 'SlimJim'); 29 | /* Curl SSL verification can be bypassed, e.g. for a server with self-signed certificates without ca-chain. */ 30 | $curl_ssl_verification = (isset(CUSTOM_CONFIG::$GITHUB_CURL_SSL_VERIFICATION)) ? (bool)CUSTOM_CONFIG::$GITHUB_CURL_SSL_VERIFICATION : true; 31 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, ($curl_ssl_verification ? 2 : false)); 32 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, $curl_ssl_verification); 33 | $response = curl_exec($curl_handle); 34 | $github_meta = json_decode($response); 35 | curl_close($curl_handle); 36 | return $github_meta; 37 | }; 38 | 39 | function cidr_match($ip, $cidrs) { 40 | $result = false; 41 | foreach($cidrs as $cidr) { 42 | list($subnet, $mask) = explode('/', $cidr); 43 | if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1) ) == ip2long($subnet)) { 44 | $result = true; 45 | } 46 | } 47 | return $result; 48 | }; 49 | 50 | function create_request($repo_name, $repo_branch, $after_sha) { 51 | global $app; 52 | $deploy_settings = $app->config('settings'); 53 | 54 | $arrProjects = Model::factory('Project') 55 | ->where_equal('name', $repo_name) 56 | ->where_equal('branch', $repo_branch) 57 | ->find_many(); 58 | 59 | foreach ($arrProjects as $project) { 60 | if($project) { 61 | file_put_contents('requests/' . $project->id . "_" . $after_sha . '.txt', serialize(array( 62 | 'name' => $project->name, 63 | 'clone_url' => $project->clone_url, 64 | 'path' => $project->path, 65 | 'branch' => $project->branch, 66 | 'hook_path' => $project->path . $deploy_settings['hook_file'] 67 | )), LOCK_EX); 68 | } 69 | } 70 | }; 71 | 72 | $app->get('/', function() use ($app) { 73 | echo "Silence is golden"; 74 | }); 75 | 76 | $app->post('/gh_hook', function() use ($app) { 77 | 78 | if (!isset(CUSTOM_CONFIG::$GITHUB_CIDR_VERIFICATION) || CUSTOM_CONFIG::$GITHUB_CIDR_VERIFICATION) { 79 | 80 | $github_meta = get_github_meta(); 81 | $cidrs = isset($github_meta->hooks) ? $github_meta->hooks : array(); 82 | 83 | if(!cidr_match($app->request()->getIp(), $cidrs)) { 84 | $app->halt(401); 85 | } 86 | 87 | } 88 | 89 | if(!($payload = $app->request()->params('payload'))) { 90 | $app->halt(403); 91 | } 92 | 93 | $payload = json_decode($payload); 94 | 95 | if(isset($payload->repository) && isset($payload->ref)) { 96 | $payload_branch = explode("/", $payload->ref); 97 | //Allow branches with slashes, such as implemented by git-flow (e.g. release/v1.1) 98 | $payload_branch = substr($payload->ref, strlen($payload_branch[0]."/".$payload_branch[1])+1); 99 | create_request($payload->repository->name, $payload_branch, $payload->after); 100 | } else { 101 | $app->halt(400); 102 | } 103 | }); 104 | 105 | $app->post('/bb_hook', function() use ($app) { 106 | $bitbucket_ips = array('131.103.20.165','131.103.20.166'); 107 | 108 | if(!in_array($app->request()->getIp(), $bitbucket_ips)) { 109 | $app->halt(401); 110 | } 111 | 112 | if(!($payload = $app->request()->params('payload'))) { 113 | $app->halt(403); 114 | } 115 | 116 | $payload = json_decode($payload); 117 | 118 | if(isset($payload->repository)) { 119 | $payload_branch = $payload->commits[0]->branch; 120 | $after_sha = $payload->commits[0]->parents[0]; 121 | create_request($payload->repository->slug, $payload_branch, $after_sha); 122 | } else { 123 | $app->halt(400); 124 | } 125 | }); 126 | 127 | $app->run(); -------------------------------------------------------------------------------- /libs/Paris/paris.php: -------------------------------------------------------------------------------- 1 | _class_name = $class_name; 66 | } 67 | 68 | /** 69 | * Add a custom filter to the method chain specified on the 70 | * model class. This allows custom queries to be added 71 | * to models. The filter should take an instance of the 72 | * ORM wrapper as its first argument and return an instance 73 | * of the ORM wrapper. Any arguments passed to this method 74 | * after the name of the filter will be passed to the called 75 | * filter function as arguments after the ORM class. 76 | */ 77 | public function filter() { 78 | $args = func_get_args(); 79 | $filter_function = array_shift($args); 80 | array_unshift($args, $this); 81 | if (method_exists($this->_class_name, $filter_function)) { 82 | return call_user_func_array(array($this->_class_name, $filter_function), $args); 83 | } 84 | } 85 | 86 | /** 87 | * Factory method, return an instance of this 88 | * class bound to the supplied table name. 89 | */ 90 | public static function for_table($table_name) { 91 | self::_setup_db(); 92 | return new self($table_name); 93 | } 94 | 95 | /** 96 | * Method to create an instance of the model class 97 | * associated with this wrapper and populate 98 | * it with the supplied Idiorm instance. 99 | */ 100 | protected function _create_model_instance($orm) { 101 | if ($orm === false) { 102 | return false; 103 | } 104 | $model = new $this->_class_name(); 105 | $model->set_orm($orm); 106 | return $model; 107 | } 108 | 109 | /** 110 | * Wrap Idiorm's find_one method to return 111 | * an instance of the class associated with 112 | * this wrapper instead of the raw ORM class. 113 | */ 114 | public function find_one($id=null) { 115 | return $this->_create_model_instance(parent::find_one($id)); 116 | } 117 | 118 | /** 119 | * Wrap Idiorm's find_many method to return 120 | * an array of instances of the class associated 121 | * with this wrapper instead of the raw ORM class. 122 | */ 123 | public function find_many() { 124 | return array_map(array($this, '_create_model_instance'), parent::find_many()); 125 | } 126 | 127 | /** 128 | * Wrap Idiorm's create method to return an 129 | * empty instance of the class associated with 130 | * this wrapper instead of the raw ORM class. 131 | */ 132 | public function create($data=null) { 133 | return $this->_create_model_instance(parent::create($data)); 134 | } 135 | } 136 | 137 | /** 138 | * Model base class. Your model objects should extend 139 | * this class. A minimal subclass would look like: 140 | * 141 | * class Widget extends Model { 142 | * } 143 | * 144 | */ 145 | class Model { 146 | 147 | // Default ID column for all models. Can be overridden by adding 148 | // a public static _id_column property to your model classes. 149 | const DEFAULT_ID_COLUMN = 'id'; 150 | 151 | // Default foreign key suffix used by relationship methods 152 | const DEFAULT_FOREIGN_KEY_SUFFIX = '_id'; 153 | 154 | /** 155 | * The ORM instance used by this model 156 | * instance to communicate with the database. 157 | */ 158 | public $orm; 159 | 160 | /** 161 | * Retrieve the value of a static property on a class. If the 162 | * class or the property does not exist, returns the default 163 | * value supplied as the third argument (which defaults to null). 164 | */ 165 | protected static function _get_static_property($class_name, $property, $default=null) { 166 | if (!class_exists($class_name) || !property_exists($class_name, $property)) { 167 | return $default; 168 | } 169 | $properties = get_class_vars($class_name); 170 | return $properties[$property]; 171 | } 172 | 173 | /** 174 | * Static method to get a table name given a class name. 175 | * If the supplied class has a public static property 176 | * named $_table, the value of this property will be 177 | * returned. If not, the class name will be converted using 178 | * the _class_name_to_table_name method method. 179 | */ 180 | protected static function _get_table_name($class_name) { 181 | $specified_table_name = self::_get_static_property($class_name, '_table'); 182 | if (is_null($specified_table_name)) { 183 | return self::_class_name_to_table_name($class_name); 184 | } 185 | return $specified_table_name; 186 | } 187 | 188 | /** 189 | * Static method to convert a class name in CapWords 190 | * to a table name in lowercase_with_underscores. 191 | * For example, CarTyre would be converted to car_tyre. 192 | */ 193 | protected static function _class_name_to_table_name($class_name) { 194 | return strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $class_name)); 195 | } 196 | 197 | /** 198 | * Return the ID column name to use for this class. If it is 199 | * not set on the class, returns null. 200 | */ 201 | protected static function _get_id_column_name($class_name) { 202 | return self::_get_static_property($class_name, '_id_column', self::DEFAULT_ID_COLUMN); 203 | } 204 | 205 | /** 206 | * Build a foreign key based on a table name. If the first argument 207 | * (the specified foreign key column name) is null, returns the second 208 | * argument (the name of the table) with the default foreign key column 209 | * suffix appended. 210 | */ 211 | protected static function _build_foreign_key_name($specified_foreign_key_name, $table_name) { 212 | if (!is_null($specified_foreign_key_name)) { 213 | return $specified_foreign_key_name; 214 | } 215 | return $table_name . self::DEFAULT_FOREIGN_KEY_SUFFIX; 216 | } 217 | 218 | /** 219 | * Factory method used to acquire instances of the given class. 220 | * The class name should be supplied as a string, and the class 221 | * should already have been loaded by PHP (or a suitable autoloader 222 | * should exist). This method actually returns a wrapped ORM object 223 | * which allows a database query to be built. The wrapped ORM object is 224 | * responsible for returning instances of the correct class when 225 | * its find_one or find_many methods are called. 226 | */ 227 | public static function factory($class_name) { 228 | $table_name = self::_get_table_name($class_name); 229 | $wrapper = ORMWrapper::for_table($table_name); 230 | $wrapper->set_class_name($class_name); 231 | $wrapper->use_id_column(self::_get_id_column_name($class_name)); 232 | return $wrapper; 233 | } 234 | 235 | /** 236 | * Internal method to construct the queries for both the has_one and 237 | * has_many methods. These two types of association are identical; the 238 | * only difference is whether find_one or find_many is used to complete 239 | * the method chain. 240 | */ 241 | protected function _has_one_or_many($associated_class_name, $foreign_key_name=null) { 242 | $base_table_name = self::_get_table_name(get_class($this)); 243 | $foreign_key_name = self::_build_foreign_key_name($foreign_key_name, $base_table_name); 244 | return self::factory($associated_class_name)->where($foreign_key_name, $this->id()); 245 | } 246 | 247 | /** 248 | * Helper method to manage one-to-one relations where the foreign 249 | * key is on the associated table. 250 | */ 251 | protected function has_one($associated_class_name, $foreign_key_name=null) { 252 | return $this->_has_one_or_many($associated_class_name, $foreign_key_name); 253 | } 254 | 255 | /** 256 | * Helper method to manage one-to-many relations where the foreign 257 | * key is on the associated table. 258 | */ 259 | protected function has_many($associated_class_name, $foreign_key_name=null) { 260 | return $this->_has_one_or_many($associated_class_name, $foreign_key_name); 261 | } 262 | 263 | /** 264 | * Helper method to manage one-to-one and one-to-many relations where 265 | * the foreign key is on the base table. 266 | */ 267 | protected function belongs_to($associated_class_name, $foreign_key_name=null) { 268 | $associated_table_name = self::_get_table_name($associated_class_name); 269 | $foreign_key_name = self::_build_foreign_key_name($foreign_key_name, $associated_table_name); 270 | $associated_object_id = $this->$foreign_key_name; 271 | return self::factory($associated_class_name)->where_id_is($associated_object_id); 272 | } 273 | 274 | /** 275 | * Helper method to manage many-to-many relationships via an intermediate model. See 276 | * README for a full explanation of the parameters. 277 | */ 278 | protected function has_many_through($associated_class_name, $join_class_name=null, $key_to_base_table=null, $key_to_associated_table=null) { 279 | $base_class_name = get_class($this); 280 | 281 | // The class name of the join model, if not supplied, is 282 | // formed by concatenating the names of the base class 283 | // and the associated class, in alphabetical order. 284 | if (is_null($join_class_name)) { 285 | $class_names = array($base_class_name, $associated_class_name); 286 | sort($class_names, SORT_STRING); 287 | $join_class_name = join("", $class_names); 288 | } 289 | 290 | // Get table names for each class 291 | $base_table_name = self::_get_table_name($base_class_name); 292 | $associated_table_name = self::_get_table_name($associated_class_name); 293 | $join_table_name = self::_get_table_name($join_class_name); 294 | 295 | // Get ID column names 296 | $base_table_id_column = self::_get_id_column_name($base_class_name); 297 | $associated_table_id_column = self::_get_id_column_name($associated_class_name); 298 | 299 | // Get the column names for each side of the join table 300 | $key_to_base_table = self::_build_foreign_key_name($key_to_base_table, $base_table_name); 301 | $key_to_associated_table = self::_build_foreign_key_name($key_to_associated_table, $associated_table_name); 302 | 303 | return self::factory($associated_class_name) 304 | ->select("{$associated_table_name}.*") 305 | ->join($join_table_name, array("{$associated_table_name}.{$associated_table_id_column}", '=', "{$join_table_name}.{$key_to_associated_table}")) 306 | ->where("{$join_table_name}.{$key_to_base_table}", $this->id()); 307 | } 308 | 309 | /** 310 | * Set the wrapped ORM instance associated with this Model instance. 311 | */ 312 | public function set_orm($orm) { 313 | $this->orm = $orm; 314 | } 315 | 316 | /** 317 | * Magic getter method, allows $model->property access to data. 318 | */ 319 | public function __get($property) { 320 | return $this->orm->get($property); 321 | } 322 | 323 | /** 324 | * Magic setter method, allows $model->property = 'value' access to data. 325 | */ 326 | public function __set($property, $value) { 327 | $this->orm->set($property, $value); 328 | } 329 | 330 | /** 331 | * Magic isset method, allows isset($model->property) to work correctly. 332 | */ 333 | public function __isset($property) { 334 | return $this->orm->__isset($property); 335 | } 336 | 337 | /** 338 | * Getter method, allows $model->get('property') access to data 339 | */ 340 | public function get($property) { 341 | return $this->orm->get($property); 342 | } 343 | 344 | /** 345 | * Setter method, allows $model->set('property', 'value') access to data. 346 | */ 347 | public function set($property, $value) { 348 | $this->orm->set($property, $value); 349 | } 350 | 351 | /** 352 | * Check whether the given field has changed since the object was created or saved 353 | */ 354 | public function is_dirty($property) { 355 | return $this->orm->is_dirty($property); 356 | } 357 | 358 | /** 359 | * Wrapper for Idiorm's as_array method. 360 | */ 361 | public function as_array() { 362 | $args = func_get_args(); 363 | return call_user_func_array(array($this->orm, 'as_array'), $args); 364 | } 365 | 366 | /** 367 | * Save the data associated with this model instance to the database. 368 | */ 369 | public function save() { 370 | return $this->orm->save(); 371 | } 372 | 373 | /** 374 | * Delete the database row associated with this model instance. 375 | */ 376 | public function delete() { 377 | return $this->orm->delete(); 378 | } 379 | 380 | /** 381 | * Get the database ID of this model instance. 382 | */ 383 | public function id() { 384 | return $this->orm->id(); 385 | } 386 | 387 | /** 388 | * Hydrate this model instance with an associative array of data. 389 | * WARNING: The keys in the array MUST match with columns in the 390 | * corresponding database table. If any keys are supplied which 391 | * do not match up with columns, the database will throw an error. 392 | */ 393 | public function hydrate($data) { 394 | $this->orm->hydrate($data)->force_all_dirty(); 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /libs/Slim/CustomView.php: -------------------------------------------------------------------------------- 1 | data); 15 | $templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/'); 16 | if ( !file_exists($templatePath) ) { 17 | throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.'); 18 | } 19 | ob_start(); 20 | require $templatePath; 21 | $html = ob_get_clean(); 22 | return $this->_render_layout($html); 23 | } 24 | 25 | public function _render_layout($_html) 26 | { 27 | extract($this->data); 28 | if(isset($_SERVER['HTTP_HOST'])){ 29 | $data['base_url'] = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; 30 | $data['base_url'] .= '://'. $_SERVER['HTTP_HOST']; 31 | $data['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); 32 | }else{ 33 | $data['base_url'] = 'http://localhost'; 34 | } 35 | 36 | if(self::$_layout !== NULL) 37 | { 38 | $layout_path = $this->getTemplatesDirectory() . '/' . ltrim(self::$_layout, '/'); 39 | if ( !file_exists($layout_path) ) { 40 | throw new RuntimeException('View cannot render layout `' . $layout_path . '`. Layout does not exist.'); 41 | } 42 | ob_start(); 43 | require $layout_path; 44 | $_html = ob_get_clean(); 45 | } 46 | return $_html; 47 | } 48 | } -------------------------------------------------------------------------------- /libs/Slim/Environment.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Environment 36 | * 37 | * This class creates and returns a key/value array of common 38 | * environment variables for the current HTTP request. 39 | * 40 | * This is a singleton class; derived environment variables will 41 | * be common across multiple Slim applications. 42 | * 43 | * This class matches the Rack (Ruby) specification as closely 44 | * as possible. More information available below. 45 | * 46 | * @package Slim 47 | * @author Josh Lockhart 48 | * @since 1.6.0 49 | */ 50 | class Slim_Environment implements ArrayAccess, IteratorAggregate { 51 | /** 52 | * @var array 53 | */ 54 | protected $properties; 55 | 56 | /** 57 | * @var Slim_Environment 58 | */ 59 | protected static $environment; 60 | 61 | /** 62 | * Get environment instance (singleton) 63 | * 64 | * This creates and/or returns an Environment instance (singleton) 65 | * derived from $_SERVER variables. You may override the global server 66 | * variables by using `Environment::mock()` instead. 67 | * 68 | * @param bool $refresh Refresh properties using global server variables? 69 | * @return Slim_Environment 70 | */ 71 | public static function getInstance( $refresh = false ) { 72 | if ( is_null(self::$environment) || $refresh ) { 73 | self::$environment = new self(); 74 | } 75 | return self::$environment; 76 | } 77 | 78 | /** 79 | * Get mock environment instance 80 | * 81 | * @param array $userSettings 82 | * @return Environment 83 | */ 84 | public static function mock( $userSettings = array() ) { 85 | self::$environment = new self(array_merge(array( 86 | 'REQUEST_METHOD' => 'GET', 87 | 'SCRIPT_NAME' => '', 88 | 'PATH_INFO' => '', 89 | 'QUERY_STRING' => '', 90 | 'SERVER_NAME' => 'localhost', 91 | 'SERVER_PORT' => 80, 92 | 'ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 93 | 'ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', 94 | 'ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 95 | 'USER_AGENT' => 'Slim Framework', 96 | 'REMOTE_ADDR' => '127.0.0.1', 97 | 'slim.url_scheme' => 'http', 98 | 'slim.input' => '', 99 | 'slim.errors' => @fopen('php://stderr', 'w') 100 | ), $userSettings)); 101 | return self::$environment; 102 | } 103 | 104 | /** 105 | * Constructor (private access) 106 | * 107 | * @param array|null $settings If present, these are used instead of global server variables 108 | * @return void 109 | */ 110 | private function __construct( $settings = null ) { 111 | if ( $settings ) { 112 | $this->properties = $settings; 113 | } else { 114 | $env = array(); 115 | 116 | //The HTTP request method 117 | $env['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD']; 118 | 119 | //The IP 120 | $env['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; 121 | 122 | /** 123 | * Application paths 124 | * 125 | * This derives two paths: SCRIPT_NAME and PATH_INFO. The SCRIPT_NAME 126 | * is the real, physical path to the application, be it in the root 127 | * directory or a subdirectory of the public document root. The PATH_INFO is the 128 | * virtual path to the requested resource within the application context. 129 | * 130 | * With htaccess, the SCRIPT_NAME will be an absolute path (without file name); 131 | * if not using htaccess, it will also include the file name. If it is "/", 132 | * it is set to an empty string (since it cannot have a trailing slash). 133 | * 134 | * The PATH_INFO will be an absolute path with a leading slash; this will be 135 | * used for application routing. 136 | */ 137 | if ( strpos($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']) === 0 ) { 138 | $env['SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME']; //Without URL rewrite 139 | } else { 140 | $env['SCRIPT_NAME'] = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']) ); //With URL rewrite 141 | } 142 | $env['PATH_INFO'] = substr_replace($_SERVER['REQUEST_URI'], '', 0, strlen($env['SCRIPT_NAME'])); 143 | if ( strpos($env['PATH_INFO'], '?') !== false ) { 144 | $env['PATH_INFO'] = substr_replace($env['PATH_INFO'], '', strpos($env['PATH_INFO'], '?')); //query string is not removed automatically 145 | } 146 | $env['SCRIPT_NAME'] = rtrim($env['SCRIPT_NAME'], '/'); 147 | $env['PATH_INFO'] = '/' . ltrim($env['PATH_INFO'], '/'); 148 | 149 | //The portion of the request URI following the '?' 150 | $env['QUERY_STRING'] = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; 151 | 152 | //Name of server host that is running the script 153 | $env['SERVER_NAME'] = $_SERVER['SERVER_NAME']; 154 | 155 | //Number of server port that is running the script 156 | $env['SERVER_PORT'] = $_SERVER['SERVER_PORT']; 157 | 158 | //HTTP request headers 159 | $specialHeaders = array('CONTENT_TYPE', 'CONTENT_LENGTH', 'PHP_AUTH_USER', 'PHP_AUTH_PW', 'PHP_AUTH_DIGEST', 'AUTH_TYPE'); 160 | foreach ( $_SERVER as $key => $value ) { 161 | $value = is_string($value) ? trim($value) : $value; 162 | if ( strpos($key, 'HTTP_') === 0 ) { 163 | $env[substr($key, 5)] = $value; 164 | } else if ( strpos($key, 'X_') === 0 || in_array($key, $specialHeaders) ) { 165 | $env[$key] = $value; 166 | } 167 | } 168 | 169 | //Is the application running under HTTPS or HTTP protocol? 170 | $env['slim.url_scheme'] = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https'; 171 | 172 | //Input stream (readable one time only; not available for mutipart/form-data requests) 173 | $rawInput = @file_get_contents('php://input'); 174 | if ( !$rawInput ) { 175 | $rawInput = ''; 176 | } 177 | $env['slim.input'] = $rawInput; 178 | 179 | //Error stream 180 | $env['slim.errors'] = fopen('php://stderr', 'w'); 181 | 182 | $this->properties = $env; 183 | } 184 | } 185 | 186 | /** 187 | * Array Access: Offset Exists 188 | */ 189 | public function offsetExists( $offset ) { 190 | return isset($this->properties[$offset]); 191 | } 192 | 193 | /** 194 | * Array Access: Offset Get 195 | */ 196 | public function offsetGet( $offset ) { 197 | if ( isset($this->properties[$offset]) ) { 198 | return $this->properties[$offset]; 199 | } else { 200 | return null; 201 | } 202 | } 203 | 204 | /** 205 | * Array Access: Offset Set 206 | */ 207 | public function offsetSet( $offset, $value ) { 208 | $this->properties[$offset] = $value; 209 | } 210 | 211 | /** 212 | * Array Access: Offset Unset 213 | */ 214 | public function offsetUnset( $offset ) { 215 | unset($this->properties[$offset]); 216 | } 217 | 218 | /** 219 | * IteratorAggregate 220 | * 221 | * @return ArrayIterator 222 | */ 223 | public function getIterator() { 224 | return new ArrayIterator($this->properties); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /libs/Slim/Exception/Pass.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Pass Exception 36 | * 37 | * This Exception will cause the Router::dispatch method 38 | * to skip the current matching route and continue to the next 39 | * matching route. If no subsequent routes are found, a 40 | * HTTP 404 Not Found response will be sent to the client. 41 | * 42 | * @package Slim 43 | * @author Josh Lockhart 44 | * @since 1.0.0 45 | */ 46 | class Slim_Exception_Pass extends Exception {} -------------------------------------------------------------------------------- /libs/Slim/Exception/RequestSlash.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Request Slash Exception 36 | * 37 | * This Exception is thrown when Slim detects a matching route 38 | * (defined with a trailing slash) and the HTTP request 39 | * matches the route but does not have a trailing slash. This 40 | * exception will be caught in `Slim::run` and trigger a 301 redirect 41 | * to the same resource URI with a trailing slash. 42 | * 43 | * @package Slim 44 | * @author Josh Lockhart 45 | * @since 1.0.0 46 | */ 47 | class Slim_Exception_RequestSlash extends Exception {} -------------------------------------------------------------------------------- /libs/Slim/Exception/Stop.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Stop Exception 36 | * 37 | * This Exception is thrown when the Slim application needs to abort 38 | * processing and return control flow to the outer PHP script. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Slim_Exception_Stop extends Exception {} -------------------------------------------------------------------------------- /libs/Slim/Http/Headers.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * HTTP Headers 36 | * 37 | * This class is an abstraction of the HTTP response headers and 38 | * provides array access to the header list while automatically 39 | * stores and retrieves headers with lowercase canonical keys regardless 40 | * of the input format. 41 | * 42 | * This class also implements the `Iterator` and `Countable` 43 | * interfaces for even more convenient usage. 44 | * 45 | * @package Slim 46 | * @author Josh Lockhart 47 | * @since 1.6.0 48 | */ 49 | class Slim_Http_Headers implements ArrayAccess, Iterator, Countable { 50 | /** 51 | * @var array HTTP headers 52 | */ 53 | protected $headers; 54 | 55 | /** 56 | * @var array Map canonical header name to original header name 57 | */ 58 | protected $map; 59 | 60 | /** 61 | * Constructor 62 | * @param array $headers 63 | * @return void 64 | */ 65 | public function __construct( $headers = array() ) { 66 | $this->merge($headers); 67 | } 68 | 69 | /** 70 | * Merge Headers 71 | * @param array $headers 72 | * @return void 73 | */ 74 | public function merge( $headers ) { 75 | foreach ( $headers as $name => $value ) { 76 | $this[$name] = $value; 77 | } 78 | } 79 | 80 | /** 81 | * Transform header name into canonical form 82 | * @param string $name 83 | * @return string 84 | */ 85 | protected function canonical( $name ) { 86 | return strtolower(trim($name)); 87 | } 88 | 89 | /** 90 | * Array Access: Offset Exists 91 | */ 92 | public function offsetExists( $offset ) { 93 | return isset($this->headers[$this->canonical($offset)]); 94 | } 95 | 96 | /** 97 | * Array Access: Offset Get 98 | */ 99 | public function offsetGet( $offset ) { 100 | $canonical = $this->canonical($offset); 101 | if ( isset($this->headers[$canonical]) ) { 102 | return $this->headers[$canonical]; 103 | } else { 104 | return null; 105 | } 106 | } 107 | 108 | /** 109 | * Array Access: Offset Set 110 | */ 111 | public function offsetSet( $offset, $value ) { 112 | $canonical = $this->canonical($offset); 113 | $this->headers[$canonical] = $value; 114 | $this->map[$canonical] = $offset; 115 | } 116 | 117 | /** 118 | * Array Access: Offset Unset 119 | */ 120 | public function offsetUnset( $offset ) { 121 | $canonical = $this->canonical($offset); 122 | unset($this->headers[$canonical], $this->map[$canonical]); 123 | } 124 | 125 | /** 126 | * Countable: Count 127 | */ 128 | public function count() { 129 | return count($this->headers); 130 | } 131 | 132 | /** 133 | * Iterator: Rewind 134 | */ 135 | public function rewind() { 136 | reset($this->headers); 137 | } 138 | 139 | /** 140 | * Iterator: Current 141 | */ 142 | public function current() { 143 | return current($this->headers); 144 | } 145 | 146 | /** 147 | * Iterator: Key 148 | */ 149 | public function key() { 150 | $key = key($this->headers); 151 | return $this->map[$key]; 152 | } 153 | 154 | /** 155 | * Iterator: Next 156 | */ 157 | public function next() { 158 | return next($this->headers); 159 | } 160 | 161 | /** 162 | * Iterator: Valid 163 | */ 164 | public function valid() { 165 | return current($this->headers) !== false; 166 | } 167 | } -------------------------------------------------------------------------------- /libs/Slim/Http/Request.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Slim HTTP Request 36 | * 37 | * This class provides a human-friendly interface to the Slim environment variables; 38 | * environment variables are passed by reference and will be modified directly. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Slim_Http_Request { 45 | const METHOD_HEAD = 'HEAD'; 46 | const METHOD_GET = 'GET'; 47 | const METHOD_POST = 'POST'; 48 | const METHOD_PUT = 'PUT'; 49 | const METHOD_DELETE = 'DELETE'; 50 | const METHOD_OPTIONS = 'OPTIONS'; 51 | const METHOD_OVERRIDE = '_METHOD'; 52 | 53 | /** 54 | * @var array 55 | */ 56 | protected static $formDataMediaTypes = array('application/x-www-form-urlencoded'); 57 | 58 | /** 59 | * @var array 60 | */ 61 | protected $env; 62 | 63 | /** 64 | * Constructor 65 | * @param array $env 66 | * @see Slim_Environment 67 | */ 68 | public function __construct( $env ) { 69 | $this->env = $env; 70 | } 71 | 72 | /** 73 | * Get HTTP method 74 | * @return string 75 | */ 76 | public function getMethod() { 77 | return $this->env['REQUEST_METHOD']; 78 | } 79 | 80 | /** 81 | * Is this a GET request? 82 | * @return bool 83 | */ 84 | public function isGet() { 85 | return $this->getMethod() === self::METHOD_GET; 86 | } 87 | 88 | /** 89 | * Is this a POST request? 90 | * @return bool 91 | */ 92 | public function isPost() { 93 | return $this->getMethod() === self::METHOD_POST; 94 | } 95 | 96 | /** 97 | * Is this a PUT request? 98 | * @return bool 99 | */ 100 | public function isPut() { 101 | return $this->getMethod() === self::METHOD_PUT; 102 | } 103 | 104 | /** 105 | * Is this a DELETE request? 106 | * @return bool 107 | */ 108 | public function isDelete() { 109 | return $this->getMethod() === self::METHOD_DELETE; 110 | } 111 | 112 | /** 113 | * Is this a HEAD request? 114 | * @return bool 115 | */ 116 | public function isHead() { 117 | return $this->getMethod() === self::METHOD_HEAD; 118 | } 119 | 120 | /** 121 | * Is this a OPTIONS request? 122 | * @return bool 123 | */ 124 | public function isOptions() { 125 | return $this->getMethod() === self::METHOD_OPTIONS; 126 | } 127 | 128 | /** 129 | * Is this an AJAX request? 130 | * @return bool 131 | */ 132 | public function isAjax() { 133 | if ( $this->params('isajax') ) { 134 | return true; 135 | } else if ( isset($this->env['X_REQUESTED_WITH']) && $this->env['X_REQUESTED_WITH'] === 'XMLHttpRequest' ) { 136 | return true; 137 | } else { 138 | return false; 139 | } 140 | } 141 | 142 | /** 143 | * Is this an XHR request? (alias of Slim_Http_Request::isAjax) 144 | * @return bool 145 | */ 146 | public function isXhr() { 147 | return $this->isAjax(); 148 | } 149 | 150 | /** 151 | * Fetch GET and POST data 152 | * 153 | * This method returns a union of GET and POST data as a key-value array, or the value 154 | * of the array key if requested; if the array key does not exist, NULL is returned. 155 | * 156 | * @param string $key 157 | * @return array|mixed|null 158 | */ 159 | public function params( $key = null ) { 160 | $union = array_merge($this->get(), $this->post()); 161 | if ( $key ) { 162 | if ( isset($union[$key]) ) { 163 | return $union[$key]; 164 | } else { 165 | return null; 166 | } 167 | } else { 168 | return $union; 169 | } 170 | } 171 | 172 | /** 173 | * Fetch GET data 174 | * 175 | * This method returns a key-value array of data sent in the HTTP request query string, or 176 | * the value of the array key if requested; if the array key does not exist, NULL is returned. 177 | * 178 | * @param string $key 179 | * @return array|mixed|null 180 | */ 181 | public function get( $key = null ) { 182 | if ( !isset($this->env['slim.request.query_hash']) ) { 183 | $output = array(); 184 | if ( function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte']) ) { 185 | mb_parse_str($this->env['QUERY_STRING'], $output); 186 | } else { 187 | parse_str($this->env['QUERY_STRING'], $output); 188 | } 189 | $this->env['slim.request.query_hash'] = Slim_Http_Util::stripSlashesIfMagicQuotes($output); 190 | } 191 | if ( $key ) { 192 | if ( isset($this->env['slim.request.query_hash'][$key]) ) { 193 | return $this->env['slim.request.query_hash'][$key]; 194 | } else { 195 | return null; 196 | } 197 | } else { 198 | return $this->env['slim.request.query_hash']; 199 | } 200 | } 201 | 202 | /** 203 | * Fetch POST data 204 | * 205 | * This method returns a key-value array of data sent in the HTTP request body, or 206 | * the value of a hash key if requested; if the array key does not exist, NULL is returned. 207 | * 208 | * @param string $key 209 | * @return array|mixed|null 210 | * @throws RuntimeException If environment input is not available 211 | */ 212 | public function post( $key = null ) { 213 | if ( !isset($this->env['slim.input']) ) { 214 | throw new RuntimeException('Missing slim.input in environment variables'); 215 | } 216 | if ( !isset($this->env['slim.request.form_hash']) ) { 217 | $this->env['slim.request.form_hash'] = array(); 218 | if ( $this->isFormData() ) { 219 | $output = array(); 220 | if ( function_exists('mb_parse_str') && !isset($this->env['slim.tests.ignore_multibyte']) ) { 221 | mb_parse_str($this->env['slim.input'], $output); 222 | } else { 223 | parse_str($this->env['slim.input'], $output); 224 | } 225 | $this->env['slim.request.form_hash'] = Slim_Http_Util::stripSlashesIfMagicQuotes($output); 226 | } else { 227 | $this->env['slim.request.form_hash'] = Slim_Http_Util::stripSlashesIfMagicQuotes($_POST); 228 | } 229 | } 230 | if ( $key ) { 231 | if ( isset($this->env['slim.request.form_hash'][$key]) ) { 232 | return $this->env['slim.request.form_hash'][$key]; 233 | } else { 234 | return null; 235 | } 236 | } else { 237 | return $this->env['slim.request.form_hash']; 238 | } 239 | } 240 | 241 | /** 242 | * Fetch PUT data (alias for Slim_Http_Request::post) 243 | * @param string $key 244 | * @return array|mixed|null 245 | */ 246 | public function put( $key = null ) { 247 | return $this->post($key); 248 | } 249 | 250 | /** 251 | * Fetch DELETE data (alias for Slim_Http_Request::post) 252 | * @param string $key 253 | * @return array|mixed|null 254 | */ 255 | public function delete( $key = null ) { 256 | return $this->post($key); 257 | } 258 | 259 | /** 260 | * Fetch COOKIE data 261 | * 262 | * This method returns a key-value array of Cookie data sent in the HTTP request, or 263 | * the value of a array key if requested; if the array key does not exist, NULL is returned. 264 | * 265 | * @param string $key 266 | * @return array|string|null 267 | */ 268 | public function cookies( $key = null ) { 269 | if ( !isset($this->env['slim.request.cookie_hash']) ) { 270 | $cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : ''; 271 | $this->env['slim.request.cookie_hash'] = Slim_Http_Util::parseCookieHeader($cookieHeader); 272 | } 273 | if ( $key ) { 274 | if ( isset($this->env['slim.request.cookie_hash'][$key]) ) { 275 | return $this->env['slim.request.cookie_hash'][$key]; 276 | } else { 277 | return null; 278 | } 279 | } else { 280 | return $this->env['slim.request.cookie_hash']; 281 | } 282 | } 283 | 284 | /** 285 | * Does the Request body contain parseable form data? 286 | * @return bool 287 | */ 288 | public function isFormData() { 289 | $method = isset($this->env['slim.method_override.original_method']) ? $this->env['slim.method_override.original_method'] : $this->getMethod(); 290 | return ( $method === self::METHOD_POST && is_null($this->getContentType()) ) || in_array($this->getMediaType(), self::$formDataMediaTypes); 291 | } 292 | 293 | /** 294 | * Get Headers 295 | * 296 | * This method returns a key-value array of headers sent in the HTTP request, or 297 | * the value of a hash key if requested; if the array key does not exist, NULL is returned. 298 | * 299 | * @param string $key 300 | * @param mixed $default The default value returned if the requested header is not available 301 | * @return mixed 302 | */ 303 | public function headers( $key = null, $default = null ) { 304 | if ( $key ) { 305 | $key = strtoupper($key); 306 | $key = str_replace('-', '_', $key); 307 | $key = preg_replace('@^HTTP_@', '', $key); 308 | if ( isset($this->env[$key]) ) { 309 | return $this->env[$key]; 310 | } else { 311 | return $default; 312 | } 313 | } else { 314 | $headers = array(); 315 | foreach ( $this->env as $key => $value ) { 316 | if ( strpos($key, 'slim.') !== 0 ) { 317 | $headers[$key] = $value; 318 | } 319 | } 320 | return $headers; 321 | } 322 | } 323 | 324 | /** 325 | * Get Body 326 | * @return string 327 | */ 328 | public function getBody() { 329 | return $this->env['slim.input']; 330 | } 331 | 332 | /** 333 | * Get Content Type 334 | * @return string 335 | */ 336 | public function getContentType() { 337 | if ( isset($this->env['CONTENT_TYPE']) ) { 338 | return $this->env['CONTENT_TYPE']; 339 | } else { 340 | return null; 341 | } 342 | } 343 | 344 | /** 345 | * Get Media Type (type/subtype within Content Type header) 346 | * @return string|null 347 | */ 348 | public function getMediaType() { 349 | $contentType = $this->getContentType(); 350 | if ( $contentType ) { 351 | $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 352 | return strtolower($contentTypeParts[0]); 353 | } else { 354 | return null; 355 | } 356 | } 357 | 358 | /** 359 | * Get Media Type Params 360 | * @return array 361 | */ 362 | public function getMediaTypeParams() { 363 | $contentType = $this->getContentType(); 364 | $contentTypeParams = array(); 365 | if ( $contentType ) { 366 | $contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType); 367 | $contentTypePartsLength = count($contentTypeParts); 368 | for ( $i = 1; $i < $contentTypePartsLength; $i++ ) { 369 | $paramParts = explode('=', $contentTypeParts[$i]); 370 | $contentTypeParams[strtolower($paramParts[0])] = $paramParts[1]; 371 | } 372 | } 373 | return $contentTypeParams; 374 | } 375 | 376 | /** 377 | * Get Content Charset 378 | * @return string|null 379 | */ 380 | public function getContentCharset() { 381 | $mediaTypeParams = $this->getMediaTypeParams(); 382 | if ( isset($mediaTypeParams['charset']) ) { 383 | return $mediaTypeParams['charset']; 384 | } else { 385 | return null; 386 | } 387 | } 388 | 389 | /** 390 | * Get Content-Length 391 | * @return int 392 | */ 393 | public function getContentLength() { 394 | if ( isset($this->env['CONTENT_LENGTH']) ) { 395 | return (int)$this->env['CONTENT_LENGTH']; 396 | } else { 397 | return 0; 398 | } 399 | } 400 | 401 | /** 402 | * Get Host 403 | * @return string 404 | */ 405 | public function getHost() { 406 | if ( isset($this->env['HOST']) ) { 407 | if ( strpos($this->env['HOST'], ':') !== false ) { 408 | $hostParts = explode(':', $this->env['HOST']); 409 | return $hostParts[0]; 410 | } 411 | return $this->env['HOST']; 412 | } else { 413 | return $this->env['SERVER_NAME']; 414 | } 415 | } 416 | 417 | /** 418 | * Get Host with Port 419 | * @return string 420 | */ 421 | public function getHostWithPort() { 422 | return sprintf('%s:%s', $this->getHost(), $this->getPort()); 423 | } 424 | 425 | /** 426 | * Get Port 427 | * @return int 428 | */ 429 | public function getPort() { 430 | return (int)$this->env['SERVER_PORT']; 431 | } 432 | 433 | /** 434 | * Get Scheme (https or http) 435 | * @return string 436 | */ 437 | public function getScheme() { 438 | return $this->env['slim.url_scheme']; 439 | } 440 | 441 | /** 442 | * Get Script Name (physical path) 443 | * @return string 444 | */ 445 | public function getScriptName() { 446 | return $this->env['SCRIPT_NAME']; 447 | } 448 | 449 | /** 450 | * LEGACY: Get Root URI (alias for Slim_Http_Request::getScriptName) 451 | * @return string 452 | */ 453 | public function getRootUri() { 454 | return $this->getScriptName(); 455 | } 456 | 457 | /** 458 | * Get Path (physical path + virtual path) 459 | * @return string 460 | */ 461 | public function getPath() { 462 | return $this->getScriptName() . $this->getPathInfo(); 463 | } 464 | 465 | /** 466 | * Get Path Info (virtual path) 467 | * @return string 468 | */ 469 | public function getPathInfo() { 470 | return $this->env['PATH_INFO']; 471 | } 472 | 473 | /** 474 | * LEGACY: Get Resource URI (alias for Slim_Http_Request::getPathInfo) 475 | * @return string 476 | */ 477 | public function getResourceUri() { 478 | return $this->getPathInfo(); 479 | } 480 | 481 | /** 482 | * Get URL (scheme + host [ + port if non-standard ]) 483 | * @return string 484 | */ 485 | public function getUrl() { 486 | $url = $this->getScheme() . '://' . $this->getHost(); 487 | if ( ( $this->getScheme() === 'https' && $this->getPort() !== 443 ) || ( $this->getScheme() === 'http' && $this->getPort() !== 80 ) ) { 488 | $url .= sprintf(':%s', $this->getPort()); 489 | } 490 | return $url; 491 | } 492 | 493 | /** 494 | * Get IP 495 | * @return string 496 | */ 497 | public function getIp() { 498 | if ( isset($this->env['X_FORWARDED_FOR']) ) { 499 | return $this->env['X_FORWARDED_FOR']; 500 | } else if ( isset($this->env['CLIENT_IP']) ) { 501 | return $this->env['CLIENT_IP']; 502 | } 503 | return $this->env['REMOTE_ADDR']; 504 | } 505 | 506 | /** 507 | * Get Referrer 508 | * @return string|null 509 | */ 510 | public function getReferrer() { 511 | if ( isset($this->env['REFERER']) ) { 512 | return $this->env['REFERER']; 513 | } else { 514 | return null; 515 | } 516 | } 517 | 518 | /** 519 | * Get Referer (for those who can't spell) 520 | * @return string|null 521 | */ 522 | public function getReferer() { 523 | return $this->getReferrer(); 524 | } 525 | 526 | /** 527 | * Get User Agent 528 | * @return string|null 529 | */ 530 | public function getUserAgent() { 531 | if ( isset($this->env['USER_AGENT']) ) { 532 | return $this->env['USER_AGENT']; 533 | } else { 534 | return null; 535 | } 536 | } 537 | } 538 | -------------------------------------------------------------------------------- /libs/Slim/Http/Response.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Response 36 | * 37 | * This is a simple abstraction over top an HTTP response. This 38 | * provides methods to set the HTTP status, the HTTP headers, 39 | * and the HTTP body. 40 | * 41 | * @package Slim 42 | * @author Josh Lockhart 43 | * @since 1.0.0 44 | */ 45 | class Slim_Http_Response implements ArrayAccess, Countable, IteratorAggregate { 46 | /** 47 | * @var int HTTP status code 48 | */ 49 | protected $status; 50 | 51 | /** 52 | * @var Slim_Http_Headers List of HTTP response headers 53 | * @see Slim_Http_Headers 54 | */ 55 | protected $header; 56 | 57 | /** 58 | * @var string HTTP response body 59 | */ 60 | protected $body; 61 | 62 | /** 63 | * @var int Length of HTTP response body 64 | */ 65 | protected $length; 66 | 67 | /** 68 | * @var array HTTP response codes and messages 69 | */ 70 | protected static $messages = array( 71 | //Informational 1xx 72 | 100 => '100 Continue', 73 | 101 => '101 Switching Protocols', 74 | //Successful 2xx 75 | 200 => '200 OK', 76 | 201 => '201 Created', 77 | 202 => '202 Accepted', 78 | 203 => '203 Non-Authoritative Information', 79 | 204 => '204 No Content', 80 | 205 => '205 Reset Content', 81 | 206 => '206 Partial Content', 82 | //Redirection 3xx 83 | 300 => '300 Multiple Choices', 84 | 301 => '301 Moved Permanently', 85 | 302 => '302 Found', 86 | 303 => '303 See Other', 87 | 304 => '304 Not Modified', 88 | 305 => '305 Use Proxy', 89 | 306 => '306 (Unused)', 90 | 307 => '307 Temporary Redirect', 91 | //Client Error 4xx 92 | 400 => '400 Bad Request', 93 | 401 => '401 Unauthorized', 94 | 402 => '402 Payment Required', 95 | 403 => '403 Forbidden', 96 | 404 => '404 Not Found', 97 | 405 => '405 Method Not Allowed', 98 | 406 => '406 Not Acceptable', 99 | 407 => '407 Proxy Authentication Required', 100 | 408 => '408 Request Timeout', 101 | 409 => '409 Conflict', 102 | 410 => '410 Gone', 103 | 411 => '411 Length Required', 104 | 412 => '412 Precondition Failed', 105 | 413 => '413 Request Entity Too Large', 106 | 414 => '414 Request-URI Too Long', 107 | 415 => '415 Unsupported Media Type', 108 | 416 => '416 Requested Range Not Satisfiable', 109 | 417 => '417 Expectation Failed', 110 | 422 => '422 Unprocessable Entity', 111 | 423 => '423 Locked', 112 | //Server Error 5xx 113 | 500 => '500 Internal Server Error', 114 | 501 => '501 Not Implemented', 115 | 502 => '502 Bad Gateway', 116 | 503 => '503 Service Unavailable', 117 | 504 => '504 Gateway Timeout', 118 | 505 => '505 HTTP Version Not Supported' 119 | ); 120 | 121 | /** 122 | * Constructor 123 | * @param string $body The HTTP response body 124 | * @param int $status The HTTP response status 125 | * @param Slim_Http_Headers|array $header The HTTP response headers 126 | */ 127 | public function __construct( $body = '', $status = 200, $header = array() ) { 128 | $this->status = (int)$status; 129 | $headers = array(); 130 | foreach ( $header as $key => $value ) { 131 | $headers[$key] = $value; 132 | } 133 | $this->header = new Slim_Http_Headers(array_merge(array('Content-Type' => 'text/html'), $headers)); 134 | $this->body = ''; 135 | $this->write($body); 136 | } 137 | 138 | /** 139 | * Get and set status 140 | * @param int|null $status 141 | * @return int 142 | */ 143 | public function status( $status = null ) { 144 | if ( !is_null($status) ) { 145 | $this->status = (int)$status; 146 | } 147 | return $this->status; 148 | } 149 | 150 | /** 151 | * Get and set header 152 | * @param string $name Header name 153 | * @param string|null $value Header value 154 | * @return string Header value 155 | */ 156 | public function header( $name, $value = null ) { 157 | if ( !is_null($value) ) { 158 | $this[$name] = $value; 159 | } 160 | return $this[$name]; 161 | } 162 | 163 | /** 164 | * Get headers 165 | * @return Slim_Http_Headers 166 | */ 167 | public function headers() { 168 | return $this->header; 169 | } 170 | 171 | /** 172 | * Get and set body 173 | * @param string|null $body Content of HTTP response body 174 | * @return string 175 | */ 176 | public function body( $body = null ) { 177 | if ( !is_null($body) ) { 178 | $this->write($body, true); 179 | } 180 | return $this->body; 181 | } 182 | 183 | /** 184 | * Get and set length 185 | * @param int|null $length 186 | * @return int 187 | */ 188 | public function length( $length = null ) { 189 | if ( !is_null($length) ) { 190 | $this->length = (int)$length; 191 | } 192 | return $this->length; 193 | } 194 | 195 | /** 196 | * Append HTTP response body 197 | * @param string $body Content to append to the current HTTP response body 198 | * @param bool $replace Overwrite existing response body? 199 | * @return string The updated HTTP response body 200 | */ 201 | public function write( $body, $replace = false ) { 202 | if ( $replace ) { 203 | $this->body = $body; 204 | } else { 205 | $this->body .= (string)$body; 206 | } 207 | $this->length = strlen($this->body); 208 | return $this->body; 209 | } 210 | 211 | /** 212 | * Finalize 213 | * 214 | * This prepares this response and returns an array 215 | * of [status, headers, body]. This array is passed to outer middleware 216 | * if available or directly to the Slim run method. 217 | * 218 | * @return array[int status, array headers, string body] 219 | */ 220 | public function finalize() { 221 | if ( in_array($this->status, array(204, 304)) ) { 222 | unset($this['Content-Type'], $this['Content-Length']); 223 | return array($this->status, $this->header, ''); 224 | } else { 225 | return array($this->status, $this->header, $this->body); 226 | } 227 | } 228 | 229 | /** 230 | * Set cookie 231 | * 232 | * Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie` 233 | * header on its own and delegates this responsibility to the `Slim_Http_Util` class. This 234 | * response's header is passed by reference to the utility class and is directly modified. By not 235 | * relying on PHP's native implementation, Slim allows middleware the opportunity to massage or 236 | * analyze the raw header before the response is ultimately delivered to the HTTP client. 237 | * 238 | * @param string $name The name of the cookie 239 | * @param string|array $value If string, the value of cookie; if array, properties for 240 | * cookie including: value, expire, path, domain, secure, httponly 241 | */ 242 | public function setCookie( $name, $value ) { 243 | Slim_Http_Util::setCookieHeader($this->header, $name, $value); 244 | } 245 | 246 | /** 247 | * Delete cookie 248 | * 249 | * Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie` 250 | * header on its own and delegates this responsibility to the `Slim_Http_Util` class. This 251 | * response's header is passed by reference to the utility class and is directly modified. By not 252 | * relying on PHP's native implementation, Slim allows middleware the opportunity to massage or 253 | * analyze the raw header before the response is ultimately delivered to the HTTP client. 254 | * 255 | * This method will set a cookie with the given name that has an expiration time in the past; this will 256 | * prompt the HTTP client to invalidate and remove the client-side cookie. Optionally, you may 257 | * also pass a key/value array as the second argument. If the "domain" key is present in this 258 | * array, only the Cookie with the given name AND domain will be removed. The invalidating cookie 259 | * sent with this response will adopt all properties of the second argument. 260 | * 261 | * @param string $name The name of the cookie 262 | * @param array $value Properties for cookie including: value, expire, path, domain, secure, httponly 263 | */ 264 | public function deleteCookie( $name, $value = array() ) { 265 | Slim_Http_Util::deleteCookieHeader($this->header, $name, $value); 266 | } 267 | 268 | /** 269 | * Redirect 270 | * 271 | * This method prepares this response to return an HTTP Redirect response 272 | * to the HTTP client. 273 | * 274 | * @param string $url The redirect destination 275 | * @param int $status The redirect HTTP status code 276 | */ 277 | public function redirect ( $url, $status = 302 ) { 278 | $this->status = $status; 279 | $this['Location'] = $url; 280 | } 281 | 282 | /** 283 | * Helpers: Empty? 284 | * @return bool 285 | */ 286 | public function isEmpty() { 287 | return in_array($this->status, array(201, 204, 304)); 288 | } 289 | 290 | /** 291 | * Helpers: Informational? 292 | * @return bool 293 | */ 294 | public function isInformational() { 295 | return $this->status >= 100 && $this->status < 200; 296 | } 297 | 298 | /** 299 | * Helpers: OK? 300 | * @return bool 301 | */ 302 | public function isOk() { 303 | return $this->status === 200; 304 | } 305 | 306 | /** 307 | * Helpers: Successful? 308 | * @return bool 309 | */ 310 | public function isSuccessful() { 311 | return $this->status >= 200 && $this->status < 300; 312 | } 313 | 314 | /** 315 | * Helpers: Redirect? 316 | * @return bool 317 | */ 318 | public function isRedirect() { 319 | return in_array($this->status, array(301, 302, 303, 307)); 320 | } 321 | 322 | /** 323 | * Helpers: Redirection? 324 | * @return bool 325 | */ 326 | public function isRedirection() { 327 | return $this->status >= 300 && $this->status < 400; 328 | } 329 | 330 | /** 331 | * Helpers: Forbidden? 332 | * @return bool 333 | */ 334 | public function isForbidden() { 335 | return $this->status === 403; 336 | } 337 | 338 | /** 339 | * Helpers: Not Found? 340 | * @return bool 341 | */ 342 | public function isNotFound() { 343 | return $this->status === 404; 344 | } 345 | 346 | /** 347 | * Helpers: Client error? 348 | * @return bool 349 | */ 350 | public function isClientError() { 351 | return $this->status >= 400 && $this->status < 500; 352 | } 353 | 354 | /** 355 | * Helpers: Server Error? 356 | * @return bool 357 | */ 358 | public function isServerError() { 359 | return $this->status >= 500 && $this->status < 600; 360 | } 361 | 362 | /** 363 | * Array Access: Offset Exists 364 | */ 365 | public function offsetExists( $offset ) { 366 | return isset($this->header[$offset]); 367 | } 368 | 369 | /** 370 | * Array Access: Offset Get 371 | */ 372 | public function offsetGet( $offset ) { 373 | if ( isset($this->header[$offset]) ) { 374 | return $this->header[$offset]; 375 | } else { 376 | return null; 377 | } 378 | } 379 | 380 | /** 381 | * Array Access: Offset Set 382 | */ 383 | public function offsetSet( $offset, $value ) { 384 | $this->header[$offset] = $value; 385 | } 386 | 387 | /** 388 | * Array Access: Offset Unset 389 | */ 390 | public function offsetUnset( $offset ) { 391 | unset($this->header[$offset]); 392 | } 393 | 394 | /** 395 | * Countable: Count 396 | */ 397 | public function count() { 398 | return count($this->header); 399 | } 400 | 401 | /** 402 | * Get Iterator 403 | * 404 | * This returns the contained `Slim_Http_Headers` instance which 405 | * is itself iterable. 406 | * 407 | * @return Slim_Http_Headers 408 | */ 409 | public function getIterator() { 410 | return $this->header; 411 | } 412 | 413 | /** 414 | * Get message for HTTP status code 415 | * @return string|null 416 | */ 417 | public static function getMessageForCode( $status ) { 418 | if ( isset(self::$messages[$status]) ) { 419 | return self::$messages[$status]; 420 | } else { 421 | return null; 422 | } 423 | } 424 | } -------------------------------------------------------------------------------- /libs/Slim/Http/Util.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Slim HTTP Utilities 36 | * 37 | * This class provides useful methods for handling HTTP requests. 38 | * 39 | * @package Slim 40 | * @author Josh Lockhart 41 | * @since 1.0.0 42 | */ 43 | class Slim_Http_Util { 44 | /** 45 | * Strip slashes from string or array 46 | * 47 | * This method strips slashes from its input. By default, this method will only 48 | * strip slashes from its input if magic quotes are enabled. Otherwise, you may 49 | * override the magic quotes setting with either TRUE or FALSE as the send argument 50 | * to force this method to strip or not strip slashes from its input. 51 | * 52 | * @var array|string $rawData 53 | * @return array|string 54 | */ 55 | public static function stripSlashesIfMagicQuotes( $rawData, $overrideStripSlashes = null ) { 56 | $strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes; 57 | if ( $strip ) { 58 | return self::_stripSlashes($rawData); 59 | } else { 60 | return $rawData; 61 | } 62 | } 63 | 64 | /** 65 | * Strip slashes from string or array 66 | * @param array|string $rawData 67 | * @return array|string 68 | */ 69 | protected static function _stripSlashes( $rawData ) { 70 | return is_array($rawData) ? array_map(array('self', '_stripSlashes'), $rawData) : stripslashes($rawData); 71 | } 72 | 73 | /** 74 | * Encrypt data 75 | * 76 | * This method will encrypt data using a given key, vector, and cipher. 77 | * By default, this will encrypt data using the RIJNDAEL/AES 256 bit cipher. You 78 | * may override the default cipher and cipher mode by passing your own desired 79 | * cipher and cipher mode as the final key-value array argument. 80 | * 81 | * @param string $data The unencrypted data 82 | * @param string $key The encryption key 83 | * @param string $iv The encryption initialization vector 84 | * @param array $settings Optional key-value array with custom algorithm and mode 85 | * @return string 86 | */ 87 | public static function encrypt( $data, $key, $iv, $settings = array() ) { 88 | if ( $data === '' || !extension_loaded('mcrypt') ) { 89 | return $data; 90 | } 91 | 92 | //Merge settings with defaults 93 | $settings = array_merge(array( 94 | 'algorithm' => MCRYPT_RIJNDAEL_256, 95 | 'mode' => MCRYPT_MODE_CBC 96 | ), $settings); 97 | 98 | //Get module 99 | $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], ''); 100 | 101 | //Validate IV 102 | $ivSize = mcrypt_enc_get_iv_size($module); 103 | if ( strlen($iv) > $ivSize ) { 104 | $iv = substr($iv, 0, $ivSize); 105 | } 106 | 107 | //Validate key 108 | $keySize = mcrypt_enc_get_key_size($module); 109 | if ( strlen($key) > $keySize ) { 110 | $key = substr($key, 0, $keySize); 111 | } 112 | 113 | //Encrypt value 114 | mcrypt_generic_init($module, $key, $iv); 115 | $res = @mcrypt_generic($module, $data); 116 | mcrypt_generic_deinit($module); 117 | 118 | return $res; 119 | } 120 | 121 | /** 122 | * Decrypt data 123 | * 124 | * This method will decrypt data using a given key, vector, and cipher. 125 | * By default, this will decrypt data using the RIJNDAEL/AES 256 bit cipher. You 126 | * may override the default cipher and cipher mode by passing your own desired 127 | * cipher and cipher mode as the final key-value array argument. 128 | * 129 | * @param string $data The encrypted data 130 | * @param string $key The encryption key 131 | * @param string $iv The encryption initialization vector 132 | * @param array $settings Optional key-value array with custom algorithm and mode 133 | * @return string 134 | */ 135 | public static function decrypt( $data, $key, $iv, $settings = array() ) { 136 | if ( $data === '' || !extension_loaded('mcrypt') ) { 137 | return $data; 138 | } 139 | 140 | //Merge settings with defaults 141 | $settings = array_merge(array( 142 | 'algorithm' => MCRYPT_RIJNDAEL_256, 143 | 'mode' => MCRYPT_MODE_CBC 144 | ), $settings); 145 | 146 | //Get module 147 | $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], ''); 148 | 149 | //Validate IV 150 | $ivSize = mcrypt_enc_get_iv_size($module); 151 | if ( strlen($iv) > $ivSize ) { 152 | $iv = substr($iv, 0, $ivSize); 153 | } 154 | 155 | //Validate key 156 | $keySize = mcrypt_enc_get_key_size($module); 157 | if ( strlen($key) > $keySize ) { 158 | $key = substr($key, 0, $keySize); 159 | } 160 | 161 | //Decrypt value 162 | mcrypt_generic_init($module, $key, $iv); 163 | $decryptedData = @mdecrypt_generic($module, $data); 164 | $res = str_replace("\x0", '', $decryptedData); 165 | mcrypt_generic_deinit($module); 166 | 167 | return $res; 168 | } 169 | 170 | /** 171 | * Encode secure cookie value 172 | * 173 | * This method will create the secure value of an HTTP cookie. The 174 | * cookie value is encrypted and hashed so that its value is 175 | * secure and checked for integrity when read in subsequent requests. 176 | * 177 | * @param string $value The unsecure HTTP cookie value 178 | * @param int $expires The UNIX timestamp at which this cookie will expire 179 | * @param string $secret The secret key used to hash the cookie value 180 | * @param int $algorithm The algorithm to use for encryption 181 | * @param int $mode The algorithm mode to use for encryption 182 | * @param string 183 | */ 184 | public static function encodeSecureCookie( $value, $expires, $secret, $algorithm, $mode ) { 185 | $key = hash_hmac('sha1', $expires, $secret); 186 | $iv = self::get_iv($expires, $secret); 187 | $secureString = base64_encode(self::encrypt($value, $key, $iv, array( 188 | 'algorithm' => $algorithm, 189 | 'mode' => $mode 190 | ))); 191 | $verificationString = hash_hmac('sha1', $expires . $value, $key); 192 | return implode('|', array($expires, $secureString, $verificationString)); 193 | } 194 | 195 | /** 196 | * Decode secure cookie value 197 | * 198 | * This method will decode the secure value of an HTTP cookie. The 199 | * cookie value is encrypted and hashed so that its value is 200 | * secure and checked for integrity when read in subsequent requests. 201 | * 202 | * @param string $value The secure HTTP cookie value 203 | * @param int $expires The UNIX timestamp at which this cookie will expire 204 | * @param string $secret The secret key used to hash the cookie value 205 | * @param int $algorithm The algorithm to use for encryption 206 | * @param int $mode The algorithm mode to use for encryption 207 | * @param string 208 | */ 209 | public static function decodeSecureCookie( $value, $secret, $algorithm, $mode ) { 210 | if ( $value ) { 211 | $value = explode('|', $value); 212 | if ( count($value) === 3 && ( (int)$value[0] === 0 || (int)$value[0] > time() ) ) { 213 | $key = hash_hmac('sha1', $value[0], $secret); 214 | $iv = self::get_iv($value[0], $secret); 215 | $data = self::decrypt(base64_decode($value[1]), $key, $iv, array( 216 | 'algorithm' => $algorithm, 217 | 'mode' => $mode 218 | )); 219 | $verificationString = hash_hmac('sha1', $value[0] . $data, $key); 220 | if ( $verificationString === $value[2] ) { 221 | return $data; 222 | } 223 | } 224 | } 225 | return false; 226 | } 227 | 228 | /** 229 | * Set HTTP cookie header 230 | * 231 | * This method will construct and set the HTTP `Set-Cookie` header. Slim 232 | * uses this method instead of PHP's native `setcookie` method. This allows 233 | * more control of the HTTP header irrespective of the native implementation's 234 | * dependency on PHP versions. 235 | * 236 | * This method accepts the Slim_Http_Headers object by reference as its 237 | * first argument; this method directly modifies this object instead of 238 | * returning a value. 239 | * 240 | * @param array $header 241 | * @param string $name 242 | * @param string $value 243 | * @return void 244 | */ 245 | public static function setCookieHeader( &$header, $name, $value ) { 246 | //Build cookie header 247 | if ( is_array($value) ) { 248 | $domain = ''; 249 | $path = ''; 250 | $expires = ''; 251 | $secure = ''; 252 | $httponly = ''; 253 | if ( isset($value['domain']) && $value['domain'] ) { 254 | $domain = '; domain=' . $value['domain']; 255 | } 256 | if ( isset($value['path']) && $value['path'] ) { 257 | $path = '; path=' . $value['path']; 258 | } 259 | if ( isset($value['expires']) ) { 260 | if ( is_string($value['expires']) ) { 261 | $timestamp = strtotime($value['expires']); 262 | } else { 263 | $timestamp = (int)$value['expires']; 264 | } 265 | if ( $timestamp !== 0 ) { 266 | $expires = '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp); 267 | } 268 | } 269 | if ( isset($value['secure']) && $value['secure'] ) { 270 | $secure = '; secure'; 271 | } 272 | if ( isset($value['httponly']) && $value['httponly'] ) { 273 | $httponly = '; HttpOnly'; 274 | } 275 | $cookie = sprintf('%s=%s%s', urlencode($name), urlencode((string)$value['value']), $domain . $path . $expires . $secure . $httponly); 276 | } else { 277 | $cookie = sprintf('%s=%s', urlencode($name), urlencode((string)$value)); 278 | } 279 | 280 | //Set cookie header 281 | if ( !isset($header['Set-Cookie']) || $header['Set-Cookie'] === '' ) { 282 | $header['Set-Cookie'] = $cookie; 283 | } else { 284 | $header['Set-Cookie'] = implode("\n", array($header['Set-Cookie'], $cookie)); 285 | } 286 | } 287 | 288 | /** 289 | * Delete HTTP cookie header 290 | * 291 | * This method will construct and set the HTTP `Set-Cookie` header to invalidate 292 | * a client-side HTTP cookie. If a cookie with the same name (and, optionally, domain) 293 | * is already set in the HTTP response, it will also be removed. Slim uses this method 294 | * instead of PHP's native `setcookie` method. This allows more control of the HTTP header 295 | * irrespective of PHP's native implementation's dependency on PHP versions. 296 | * 297 | * This method accepts the Slim_Http_Headers object by reference as its 298 | * first argument; this method directly modifies this object instead of 299 | * returning a value. 300 | * 301 | * @param array $header 302 | * @param string $name 303 | * @param string $value 304 | * @return void 305 | */ 306 | public static function deleteCookieHeader( &$header, $name, $value = array() ) { 307 | //Remove affected cookies from current response header 308 | $cookiesOld = array(); 309 | $cookiesNew = array(); 310 | if ( isset($header['Set-Cookie']) ) { 311 | $cookiesOld = explode("\n", $header['Set-Cookie']); 312 | } 313 | foreach ( $cookiesOld as $c ) { 314 | if ( isset($value['domain']) && $value['domain'] ) { 315 | $regex = sprintf('@%s=.*domain=%s@', urlencode($name), preg_quote($value['domain'])); 316 | } else { 317 | $regex = sprintf('@%s=@', urlencode($name)); 318 | } 319 | if ( preg_match($regex, $c) === 0 ) { 320 | $cookiesNew[] = $c; 321 | } 322 | } 323 | if ( $cookiesNew ) { 324 | $header['Set-Cookie'] = implode("\n", $cookiesNew); 325 | } else { 326 | unset($header['Set-Cookie']); 327 | } 328 | 329 | //Set invalidating cookie to clear client-side cookie 330 | self::setCookieHeader($header, $name, array_merge(array('value' => '', 'path' => null, 'domain' => null, 'expires' => time() - 100), $value)); 331 | } 332 | 333 | /** 334 | * Parse cookie header 335 | * 336 | * This method will parse the HTTP requst's `Cookie` header 337 | * and extract cookies into an associative array. 338 | * 339 | * @param string 340 | * @return array 341 | */ 342 | public static function parseCookieHeader( $header ) { 343 | $cookies = array(); 344 | $header = rtrim($header, "\r\n"); 345 | $headerPieces = preg_split('@\s*;\s*@', $header); 346 | foreach ( $headerPieces as $c ) { 347 | $cParts = explode('=', $c); 348 | if ( count($cParts) === 2 ) { 349 | $key = urldecode($cParts[0]); 350 | $value = urldecode($cParts[1]); 351 | if ( isset($cookies[$key]) ) { 352 | if ( is_array($cookies[$key]) ) { 353 | $cookies[$key][] = $value; 354 | } else { 355 | $cookies[$key] = array($cookies[$key], $value); 356 | } 357 | } else { 358 | $cookies[$key] = $value; 359 | } 360 | } 361 | } 362 | return $cookies; 363 | } 364 | 365 | /** 366 | * Generate a random IV 367 | * 368 | * This method will generate a non-predictable IV for use with 369 | * the cookie encryption 370 | * 371 | * @param int $expires The UNIX timestamp at which this cookie will expire 372 | * @param string $secret The secret key used to hash the cookie value 373 | * @return binary string with length 40 374 | */ 375 | private static function get_iv($expires, $secret) { 376 | $data1 = hash_hmac('sha1', 'a'.$expires.'b', $secret); 377 | $data2 = hash_hmac('sha1', 'z'.$expires.'y', $secret); 378 | return pack("h*", $data1.$data2); 379 | } 380 | 381 | } -------------------------------------------------------------------------------- /libs/Slim/Log.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Log 36 | * 37 | * This is the primary logger for a Slim application. You may provide 38 | * a Log Writer in conjunction with this Log to write to various output 39 | * destinations (e.g. a file). This class provides this interface: 40 | * 41 | * debug( mixed $object ) 42 | * info( mixed $object ) 43 | * warn( mixed $object ) 44 | * error( mixed $object ) 45 | * fatal( mixed $object ) 46 | * 47 | * This class assumes only that your Log Writer has a public `write()` method 48 | * that accepts any object as its one and only argument. The Log Writer 49 | * class may write or send its argument anywhere: a file, STDERR, 50 | * a remote web API, etc. The possibilities are endless. 51 | * 52 | * @package Slim 53 | * @author Josh Lockhart 54 | * @since 1.0.0 55 | */ 56 | class Slim_Log { 57 | /** 58 | * @var array 59 | */ 60 | static protected $levels = array( 61 | 0 => 'FATAL', 62 | 1 => 'ERROR', 63 | 2 => 'WARN', 64 | 3 => 'INFO', 65 | 4 => 'DEBUG' 66 | ); 67 | 68 | /** 69 | * @var mixed 70 | */ 71 | protected $writer; 72 | 73 | /** 74 | * @var bool 75 | */ 76 | protected $enabled; 77 | 78 | /** 79 | * @var int 80 | */ 81 | protected $level; 82 | 83 | /** 84 | * Constructor 85 | * @param mixed $writer 86 | * @return void 87 | */ 88 | public function __construct( $writer ) { 89 | $this->writer = $writer; 90 | $this->enabled = true; 91 | $this->level = 4; 92 | } 93 | 94 | /** 95 | * Is logging enabled? 96 | * @return bool 97 | */ 98 | public function getEnabled() { 99 | return $this->enabled; 100 | } 101 | 102 | /** 103 | * Enable or disable logging 104 | * @param bool $enabled 105 | * @return void 106 | */ 107 | public function setEnabled( $enabled ) { 108 | if ( $enabled ) { 109 | $this->enabled = true; 110 | } else { 111 | $this->enabled = false; 112 | } 113 | } 114 | 115 | /** 116 | * Set level 117 | * @param int $level 118 | * @return void 119 | * @throws InvalidArgumentException 120 | */ 121 | public function setLevel( $level ) { 122 | if ( !isset(self::$levels[$level]) ) { 123 | throw new InvalidArgumentException('Invalid log level'); 124 | } 125 | $this->level = $level; 126 | } 127 | 128 | /** 129 | * Get level 130 | * @return int 131 | */ 132 | public function getLevel() { 133 | return $this->level; 134 | } 135 | 136 | /** 137 | * Set writer 138 | * @param mixed $writer 139 | * @return void 140 | */ 141 | public function setWriter( $writer ) { 142 | $this->writer = $writer; 143 | } 144 | 145 | /** 146 | * Get writer 147 | * @return mixed 148 | */ 149 | public function getWriter() { 150 | return $this->writer; 151 | } 152 | 153 | /** 154 | * Is logging enabled? 155 | * @return bool 156 | */ 157 | public function isEnabled() { 158 | return $this->enabled; 159 | } 160 | 161 | /** 162 | * Log debug message 163 | * @param mixed $object 164 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled 165 | */ 166 | public function debug( $object ) { 167 | return $this->log($object, 4); 168 | } 169 | 170 | /** 171 | * Log info message 172 | * @param mixed $object 173 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled 174 | */ 175 | public function info( $object ) { 176 | return $this->log($object, 3); 177 | } 178 | 179 | /** 180 | * Log warn message 181 | * @param mixed $object 182 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled 183 | */ 184 | public function warn( $object ) { 185 | return $this->log($object, 2); 186 | } 187 | 188 | /** 189 | * Log error message 190 | * @param mixed $object 191 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled 192 | */ 193 | public function error( $object ) { 194 | return $this->log($object, 1); 195 | } 196 | 197 | /** 198 | * Log fatal message 199 | * @param mixed $object 200 | * @return mixed|false What the Logger returns, or false if Logger not set or not enabled 201 | */ 202 | public function fatal( $object ) { 203 | return $this->log($object, 0); 204 | } 205 | 206 | /** 207 | * Log message 208 | * @param mixed The object to log 209 | * @param int The message level 210 | * @return int|false 211 | */ 212 | protected function log( $object, $level ) { 213 | if ( $this->enabled && $this->writer && $level <= $this->level ) { 214 | return $this->writer->write($object, $level); 215 | } else { 216 | return false; 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /libs/Slim/LogFileWriter.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Log File Writer 36 | * 37 | * This class is used by Slim_Log to write log messages to a valid, writable 38 | * resource handle (e.g. a file or STDERR). 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.5.2 43 | */ 44 | class Slim_LogFileWriter { 45 | /** 46 | * @var resource 47 | */ 48 | protected $resource; 49 | 50 | /** 51 | * Constructor 52 | * @param resource $resource 53 | * @return void 54 | * @throws InvalidArgumentException 55 | */ 56 | public function __construct( $resource ) { 57 | if ( !is_resource($resource) ) { 58 | throw new InvalidArgumentException('Cannot create LogFileWriter. Invalid resource handle.'); 59 | } 60 | $this->resource = $resource; 61 | } 62 | 63 | /** 64 | * Write message 65 | * @param mixed $message 66 | * @param int $level 67 | * @return int|false 68 | */ 69 | public function write( $message, $level = null ) { 70 | return fwrite($this->resource, (string)$message . PHP_EOL); 71 | } 72 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Middleware 36 | * 37 | * @package Slim 38 | * @author Josh Lockhart 39 | * @since 1.6.0 40 | */ 41 | abstract class Slim_Middleware { 42 | /** 43 | * @var Slim Reference to the primary Slim application instance 44 | */ 45 | protected $app; 46 | 47 | /** 48 | * @var mixed Reference to the next downstream middleware 49 | */ 50 | protected $next; 51 | 52 | /** 53 | * Set application 54 | * 55 | * This method injects the primary Slim application instance into 56 | * this middleware. 57 | * 58 | * @param Slim $application 59 | * @return void 60 | */ 61 | final public function setApplication( $application ) { 62 | $this->app = $application; 63 | } 64 | 65 | /** 66 | * Get application 67 | * 68 | * This method retrieves the application previously injected 69 | * into this middleware. 70 | * 71 | * @return Slim 72 | */ 73 | final public function getApplication() { 74 | return $this->app; 75 | } 76 | 77 | /** 78 | * Set next middleware 79 | * 80 | * This method injects the next downstream middleware into 81 | * this middleware so that it may optionally be called 82 | * when appropriate. 83 | * 84 | * @param Slim|Slim_Middleware 85 | * @return void 86 | */ 87 | final public function setNextMiddleware( $nextMiddleware ) { 88 | $this->next = $nextMiddleware; 89 | } 90 | 91 | /** 92 | * Get next middleware 93 | * 94 | * This method retrieves the next downstream middleware 95 | * previously injected into this middleware. 96 | * 97 | * @return Slim|Slim_Middleware 98 | */ 99 | final public function getNextMiddleware() { 100 | return $this->next; 101 | } 102 | 103 | /** 104 | * Call 105 | * 106 | * Perform actions specific to this middleware and optionally 107 | * call the next downstream middleware. 108 | * 109 | * @return void 110 | */ 111 | abstract public function call(); 112 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware/ContentTypes.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Content Types 36 | * 37 | * This is middleware for a Slim application that intercepts 38 | * the HTTP request body and parses it into the appropriate 39 | * PHP data structure if possible; else it returns the HTTP 40 | * request body unchanged. This is particularly useful 41 | * for preparing the HTTP request body for an XML or JSON API. 42 | * 43 | * @package Slim 44 | * @author Josh Lockhart 45 | * @since 1.5.2 46 | */ 47 | class Slim_Middleware_ContentTypes extends Slim_Middleware { 48 | /** 49 | * @var array 50 | */ 51 | protected $contentTypes; 52 | 53 | /** 54 | * Constructor 55 | * @param array $settings 56 | */ 57 | public function __construct( $settings = array() ) { 58 | $this->contentTypes = array_merge(array( 59 | 'application/json' => array($this, 'parseJson'), 60 | 'application/xml' => array($this, 'parseXml'), 61 | 'text/xml' => array($this, 'parseXml'), 62 | 'text/csv' => array($this, 'parseCsv') 63 | ), $settings); 64 | } 65 | 66 | /** 67 | * Call 68 | * @return void 69 | */ 70 | public function call() { 71 | $mediaType = $this->app->request()->getMediaType(); 72 | if ( $mediaType ) { 73 | $env = $this->app->environment(); 74 | $env['slim.input_original'] = $env['slim.input']; 75 | $env['slim.input'] = $this->parse($env['slim.input'], $mediaType); 76 | } 77 | $this->next->call(); 78 | } 79 | 80 | /** 81 | * Parse input 82 | * 83 | * This method will attempt to parse the request body 84 | * based on its content type if available. 85 | * 86 | * @param string $input 87 | * @param string $contentType 88 | * @return mixed 89 | */ 90 | protected function parse ( $input, $contentType ) { 91 | if ( isset($this->contentTypes[$contentType]) && is_callable($this->contentTypes[$contentType]) ) { 92 | $result = call_user_func($this->contentTypes[$contentType], $input); 93 | if ( $result ) { 94 | return $result; 95 | } 96 | } 97 | return $input; 98 | } 99 | 100 | /** 101 | * Parse JSON 102 | * 103 | * This method converts the raw JSON input 104 | * into an associative array. 105 | * 106 | * @param string $input 107 | * @return array|string 108 | */ 109 | protected function parseJson( $input ) { 110 | if ( function_exists('json_decode') ) { 111 | $result = json_decode($input, true); 112 | if ( $result ) { 113 | return $result; 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * Parse XML 120 | * 121 | * This method creates a SimpleXMLElement 122 | * based upon the XML input. If the SimpleXML 123 | * extension is not available, the raw input 124 | * will be returned unchanged. 125 | * 126 | * @param string $input 127 | * @return SimpleXMLElement|string 128 | */ 129 | protected function parseXml( $input ) { 130 | if ( class_exists('SimpleXMLElement') ) { 131 | try { 132 | return new SimpleXMLElement($input); 133 | } catch ( Exception $e ) {} 134 | } 135 | return $input; 136 | } 137 | 138 | /** 139 | * Parse CSV 140 | * 141 | * This method parses CSV content into a numeric array 142 | * containing an array of data for each CSV line. 143 | * 144 | * @param string $input 145 | * @return array 146 | */ 147 | protected function parseCsv( $input ) { 148 | $temp = fopen('php://memory', 'rw'); 149 | fwrite($temp, $input); 150 | fseek($temp, 0); 151 | $res = array(); 152 | while ( ($data = fgetcsv($temp)) !== false ) { 153 | $res[] = $data; 154 | } 155 | fclose($temp); 156 | return $res; 157 | } 158 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware/Flash.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Flash 36 | * 37 | * This is middleware for a Slim application that enables 38 | * Flash messaging between HTTP requests. This allows you 39 | * set Flash messages for the current request, for the next request, 40 | * or to retain messages from the previous request through to 41 | * the next request. 42 | * 43 | * @package Slim 44 | * @author Josh Lockhart 45 | * @since 1.5.2 46 | */ 47 | class Slim_Middleware_Flash extends Slim_Middleware implements ArrayAccess { 48 | /** 49 | * @var array 50 | */ 51 | protected $settings; 52 | 53 | /** 54 | * @var array 55 | */ 56 | protected $messages; 57 | 58 | /** 59 | * Constructor 60 | * @param Slim $app 61 | * @param array $settings 62 | * @return void 63 | */ 64 | public function __construct( $settings = array() ) { 65 | $this->settings = array_merge(array('key' => 'slim.flash'), $settings); 66 | $this->messages = array( 67 | 'prev' => array(), //flash messages from prev request (loaded when middleware called) 68 | 'next' => array(), //flash messages for next request 69 | 'now' => array() //flash messages for current request 70 | ); 71 | } 72 | 73 | /** 74 | * Call 75 | * @return void 76 | */ 77 | public function call() { 78 | //Read flash messaging from previous request if available 79 | $this->loadMessages(); 80 | 81 | //Prepare flash messaging for current request 82 | $env = $this->app->environment(); 83 | $env['slim.flash'] = $this; 84 | $this->next->call(); 85 | $this->save(); 86 | } 87 | 88 | /** 89 | * Now 90 | * 91 | * Specify a flash message for a given key to be shown for the current request 92 | * 93 | * @param string $key 94 | * @param string $value 95 | * @return void 96 | */ 97 | public function now( $key, $value ) { 98 | $this->messages['now'][(string)$key] = $value; 99 | } 100 | 101 | /** 102 | * Set 103 | * 104 | * Specify a flash message for a given key to be shown for the next request 105 | * 106 | * @param string $key 107 | * @param string $value 108 | * @return void 109 | */ 110 | public function set( $key, $value ) { 111 | $this->messages['next'][(string)$key] = $value; 112 | } 113 | 114 | /** 115 | * Keep 116 | * 117 | * Retain flash messages from the previous request for the next request 118 | * 119 | * @return void 120 | */ 121 | public function keep() { 122 | foreach ( $this->messages['prev'] as $key => $val ) { 123 | $this->messages['next'][$key] = $val; 124 | } 125 | } 126 | 127 | /** 128 | * Save 129 | */ 130 | public function save() { 131 | $_SESSION[$this->settings['key']] = $this->messages['next']; 132 | } 133 | 134 | /** 135 | * Load messages 136 | * 137 | * Load messages from previous request if available 138 | */ 139 | public function loadMessages() { 140 | if ( isset($_SESSION[$this->settings['key']]) ) { 141 | $this->messages['prev'] = $_SESSION[$this->settings['key']]; 142 | } 143 | } 144 | 145 | /** 146 | * Get messages 147 | * 148 | * Return array of flash messages to be shown for the current request 149 | * 150 | * @return array 151 | */ 152 | public function getMessages() { 153 | return array_merge($this->messages['prev'], $this->messages['now']); 154 | } 155 | 156 | /** 157 | * Array Access: Offset Exists 158 | */ 159 | public function offsetExists( $offset ) { 160 | $messages = $this->getMessages(); 161 | return isset($messages[$offset]); 162 | } 163 | 164 | /** 165 | * Array Access: Offset Get 166 | */ 167 | public function offsetGet( $offset ) { 168 | $messages = $this->getMessages(); 169 | return isset($messages[$offset]) ? $messages[$offset] : null; 170 | } 171 | 172 | /** 173 | * Array Access: Offset Set 174 | */ 175 | public function offsetSet( $offset, $value ) { 176 | $this->now($offset, $value); 177 | } 178 | 179 | /** 180 | * Array Access: Offset Unset 181 | */ 182 | public function offsetUnset( $offset ) { 183 | unset($this->messages['prev'][$offset], $this->messages['now'][$offset]); 184 | } 185 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware/MethodOverride.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * HTTP Method Override 36 | * 37 | * This is middleware for a Slim application that allows traditional 38 | * desktop browsers to submit psuedo PUT and DELETE requests by relying 39 | * on a pre-determined request parameter. Without this middleware, 40 | * desktop browsers are only able to submit GET and POST requests. 41 | * 42 | * This middleware is included automatically! 43 | * 44 | * @package Slim 45 | * @author Josh Lockhart 46 | * @since 1.5.2 47 | */ 48 | class Slim_Middleware_MethodOverride extends Slim_Middleware { 49 | /** 50 | * @var array 51 | */ 52 | protected $settings; 53 | 54 | /** 55 | * Constructor 56 | * @param Slim $app 57 | * @param array $settings 58 | * @return void 59 | */ 60 | public function __construct( $settings = array() ) { 61 | $this->settings = array_merge(array('key' => '_METHOD'), $settings); 62 | } 63 | 64 | /** 65 | * Call 66 | * 67 | * Implements Slim middleware interface. This method is invoked and passed 68 | * an array of environemnt variables. This middleware inspects the environment 69 | * variables for the HTTP method override parameter; if found, this middleware 70 | * modifies the environment settings so downstream middleware and/or the Slim 71 | * application will treat the request with the desired HTTP method. 72 | * 73 | * @param array $env 74 | * @return array[status, header, body] 75 | */ 76 | public function call() { 77 | $env = $this->app->environment(); 78 | if ( isset($env['X_HTTP_METHOD_OVERRIDE']) ) { 79 | // Header commonly used by Backbone.js and others 80 | $env['slim.method_override.original_method'] = $env['REQUEST_METHOD']; 81 | $env['REQUEST_METHOD'] = strtoupper($env['X_HTTP_METHOD_OVERRIDE']); 82 | } else if ( isset($env['REQUEST_METHOD']) && $env['REQUEST_METHOD'] === 'POST' ) { 83 | // HTML Form Override 84 | $req = new Slim_Http_Request($env); 85 | $method = $req->post($this->settings['key']); 86 | if ( $method ) { 87 | $env['slim.method_override.original_method'] = $env['REQUEST_METHOD']; 88 | $env['REQUEST_METHOD'] = strtoupper($method); 89 | } 90 | } 91 | $this->next->call(); 92 | } 93 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware/PrettyExceptions.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Pretty Exceptions 36 | * 37 | * This middleware catches any Exception thrown by the surrounded 38 | * application and displays a developer-friendly diagnostic screen. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Slim_Middleware_PrettyExceptions extends Slim_Middleware { 45 | /** 46 | * @var array 47 | */ 48 | protected $settings; 49 | 50 | /** 51 | * Constructor 52 | * @param Slim|middleware $app 53 | * @param array $settings 54 | */ 55 | public function __construct( $settings = array() ) { 56 | $this->settings = $settings; 57 | } 58 | 59 | /** 60 | * Call 61 | * @return void 62 | */ 63 | public function call() { 64 | try { 65 | $this->next->call(); 66 | } catch ( Exception $e ) { 67 | $env = $this->app->environment(); 68 | $env['slim.log']->error($e); 69 | $this->app->response()->status(500); 70 | $this->app->response()->body($this->renderBody($env, $e)); 71 | } 72 | } 73 | 74 | /** 75 | * Render response body 76 | * @param array $env 77 | * @param Exception $exception 78 | * @return string 79 | */ 80 | protected function renderBody( &$env, $exception ) { 81 | $title = 'Slim Application Error'; 82 | $code = $exception->getCode(); 83 | $message = $exception->getMessage(); 84 | $file = $exception->getFile(); 85 | $line = $exception->getLine(); 86 | $trace = $exception->getTraceAsString(); 87 | $html = sprintf('

%s

', $title); 88 | $html .= '

The application could not run because of the following error:

'; 89 | $html .= '

Details

'; 90 | if ( $code ) { 91 | $html .= sprintf('
Code: %s
', $code); 92 | } 93 | if ( $message ) { 94 | $html .= sprintf('
Message: %s
', $message); 95 | } 96 | if ( $file ) { 97 | $html .= sprintf('
File: %s
', $file); 98 | } 99 | if ( $line ) { 100 | $html .= sprintf('
Line: %s
', $line); 101 | } 102 | if ( $trace ) { 103 | $html .= '

Trace

'; 104 | $html .= sprintf('
%s
', $trace); 105 | } 106 | return sprintf("%s%s", $title, $html); 107 | } 108 | } -------------------------------------------------------------------------------- /libs/Slim/Middleware/SessionCookie.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Session Cookie 36 | * 37 | * This class provides an HTTP cookie storage mechanism 38 | * for session data. This class avoids using a PHP session 39 | * and instead serializes/unserializes the $_SESSION global 40 | * variable to/from an HTTP cookie. 41 | * 42 | * If a secret key is provided with this middleware, the HTTP 43 | * cookie will be checked for integrity to ensure the client-side 44 | * cookie is not changed. 45 | * 46 | * You should NEVER store sensitive data in a client-side cookie 47 | * in any format, encrypted or not. If you need to store sensitive 48 | * user information in a session, you should rely on PHP's native 49 | * session implementation, or use other middleware to store 50 | * session data in a database or alternative server-side cache. 51 | * 52 | * Because this class stores serialized session data in an HTTP cookie, 53 | * you are inherently limtied to 4 Kb. If you attempt to store 54 | * more than this amount, serialization will fail. 55 | * 56 | * @package Slim 57 | * @author Josh Lockhart 58 | * @since 1.5.2 59 | */ 60 | class Slim_Middleware_SessionCookie extends Slim_Middleware { 61 | /** 62 | * @var array 63 | */ 64 | protected $settings; 65 | 66 | /** 67 | * Constructor 68 | * 69 | * @param array $settings 70 | * @return void 71 | */ 72 | public function __construct( $settings = array() ) { 73 | $this->settings = array_merge(array( 74 | 'expires' => '20 minutes', 75 | 'path' => '/', 76 | 'domain' => null, 77 | 'secure' => false, 78 | 'httponly' => false, 79 | 'name' => 'slim_session', 80 | 'secret' => 'CHANGE_ME', 81 | 'cipher' => MCRYPT_RIJNDAEL_256, 82 | 'cipher_mode' => MCRYPT_MODE_CBC 83 | ), $settings); 84 | if ( is_string($this->settings['expires']) ) { 85 | $this->settings['expires'] = strtotime($this->settings['expires']); 86 | } 87 | } 88 | 89 | /** 90 | * Call 91 | * @return void 92 | */ 93 | public function call() { 94 | $this->loadSession(); 95 | $this->next->call(); 96 | $this->saveSession(); 97 | } 98 | 99 | /** 100 | * Load session 101 | * @param array $env 102 | * @return void 103 | */ 104 | protected function loadSession() { 105 | session_start(); 106 | $value = Slim_Http_Util::decodeSecureCookie( 107 | $this->app->request()->cookies($this->settings['name']), 108 | $this->settings['secret'], 109 | $this->settings['cipher'], 110 | $this->settings['cipher_mode'] 111 | ); 112 | if ( $value ) { 113 | $_SESSION = unserialize($value); 114 | } else { 115 | $_SESSION = array(); 116 | } 117 | } 118 | 119 | /** 120 | * Save session 121 | * @return void 122 | */ 123 | protected function saveSession() { 124 | $value = Slim_Http_Util::encodeSecureCookie( 125 | serialize($_SESSION), 126 | $this->settings['expires'], 127 | $this->settings['secret'], 128 | $this->settings['cipher'], 129 | $this->settings['cipher_mode'] 130 | ); 131 | if ( strlen($value) > 4096 ) { 132 | $this->app->getLog()->error('WARNING! Slim_Middleware_SessionCookie data size is larger than 4KB. Content save failed.'); 133 | } else { 134 | $this->app->response()->setCookie($this->settings['name'], array( 135 | 'value' => $value, 136 | 'domain' => $this->settings['domain'], 137 | 'path' => $this->settings['path'], 138 | 'expires' => $this->settings['expires'], 139 | 'secure' => $this->settings['secure'], 140 | 'httponly' => $this->settings['httponly'] 141 | )); 142 | } 143 | session_destroy(); 144 | } 145 | } -------------------------------------------------------------------------------- /libs/Slim/Route.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Route 36 | * @package Slim 37 | * @author Josh Lockhart 38 | * @since 1.0.0 39 | */ 40 | class Slim_Route { 41 | /** 42 | * @var string The route pattern (ie. "/books/:id") 43 | */ 44 | protected $pattern; 45 | 46 | /** 47 | * @var mixed The callable associated with this route 48 | */ 49 | protected $callable; 50 | 51 | /** 52 | * @var array Conditions for this route's URL parameters 53 | */ 54 | protected $conditions = array(); 55 | 56 | /** 57 | * @var array Default conditions applied to all Route instances 58 | */ 59 | protected static $defaultConditions = array(); 60 | 61 | /** 62 | * @var string The name of this route (optional) 63 | */ 64 | protected $name; 65 | 66 | /** 67 | * @var array Key-value array of URL parameters 68 | */ 69 | protected $params = array(); 70 | 71 | /** 72 | * @var array HTTP methods supported by this Route 73 | */ 74 | protected $methods = array(); 75 | 76 | /** 77 | * @var Slim_Router The Router to which this Route belongs 78 | */ 79 | protected $router; 80 | 81 | /** 82 | * @var array[Callable] Middleware 83 | */ 84 | protected $middleware = array(); 85 | 86 | /** 87 | * Constructor 88 | * @param string $pattern The URL pattern (ie. "/books/:id") 89 | * @param mixed $callable Anything that returns TRUE for is_callable() 90 | */ 91 | public function __construct( $pattern, $callable ) { 92 | $this->setPattern($pattern); 93 | $this->setCallable($callable); 94 | $this->setConditions(self::getDefaultConditions()); 95 | } 96 | 97 | /** 98 | * Set default route conditions for all instances 99 | * @param array $defaultConditions 100 | * @return void 101 | */ 102 | public static function setDefaultConditions( array $defaultConditions ) { 103 | self::$defaultConditions = $defaultConditions; 104 | } 105 | 106 | /** 107 | * Get default route conditions for all instances 108 | * @return array 109 | */ 110 | public static function getDefaultConditions() { 111 | return self::$defaultConditions; 112 | } 113 | 114 | /** 115 | * Get route pattern 116 | * @return string 117 | */ 118 | public function getPattern() { 119 | return $this->pattern; 120 | } 121 | 122 | /** 123 | * Set route pattern 124 | * @param string $pattern 125 | * @return void 126 | */ 127 | public function setPattern( $pattern ) { 128 | $this->pattern = str_replace(')', ')?', (string)$pattern); 129 | } 130 | 131 | /** 132 | * Get route callable 133 | * @return mixed 134 | */ 135 | public function getCallable() { 136 | return $this->callable; 137 | } 138 | 139 | /** 140 | * Set route callable 141 | * @param mixed $callable 142 | * @return void 143 | */ 144 | public function setCallable($callable) { 145 | $this->callable = $callable; 146 | } 147 | 148 | /** 149 | * Get route conditions 150 | * @return array 151 | */ 152 | public function getConditions() { 153 | return $this->conditions; 154 | } 155 | 156 | /** 157 | * Set route conditions 158 | * @param array $conditions 159 | * @return void 160 | */ 161 | public function setConditions( array $conditions ) { 162 | $this->conditions = $conditions; 163 | } 164 | 165 | /** 166 | * Get route name 167 | * @return string|null 168 | */ 169 | public function getName() { 170 | return $this->name; 171 | } 172 | 173 | /** 174 | * Set route name 175 | * @param string $name 176 | * @return void 177 | */ 178 | public function setName( $name ) { 179 | $this->name = (string)$name; 180 | $this->router->addNamedRoute($this->name, $this); 181 | } 182 | 183 | /** 184 | * Get route parameters 185 | * @return array 186 | */ 187 | public function getParams() { 188 | return $this->params; 189 | } 190 | 191 | /** 192 | * Add supported HTTP method(s) 193 | * @return void 194 | */ 195 | public function setHttpMethods() { 196 | $args = func_get_args(); 197 | $this->methods = $args; 198 | } 199 | 200 | /** 201 | * Get supported HTTP methods 202 | * @return array 203 | */ 204 | public function getHttpMethods() { 205 | return $this->methods; 206 | } 207 | 208 | /** 209 | * Append supported HTTP methods 210 | * @return void 211 | */ 212 | public function appendHttpMethods() { 213 | $args = func_get_args(); 214 | $this->methods = array_merge($this->methods, $args); 215 | } 216 | 217 | /** 218 | * Append supported HTTP methods (alias for Route::appendHttpMethods) 219 | * @return Slim_Route 220 | */ 221 | public function via() { 222 | $args = func_get_args(); 223 | $this->methods = array_merge($this->methods, $args); 224 | return $this; 225 | } 226 | 227 | /** 228 | * Detect support for an HTTP method 229 | * @return bool 230 | */ 231 | public function supportsHttpMethod( $method ) { 232 | return in_array($method, $this->methods); 233 | } 234 | 235 | /** 236 | * Get router 237 | * @return Slim_Router 238 | */ 239 | public function getRouter() { 240 | return $this->router; 241 | } 242 | 243 | /** 244 | * Set router 245 | * @param Slim_Router $router 246 | * @return void 247 | */ 248 | public function setRouter( Slim_Router $router ) { 249 | $this->router = $router; 250 | } 251 | 252 | /** 253 | * Get middleware 254 | * @return array[Callable] 255 | */ 256 | public function getMiddleware() { 257 | return $this->middleware; 258 | } 259 | 260 | /** 261 | * Set middleware 262 | * 263 | * This method allows middleware to be assigned to a specific Route. 264 | * If the method argument `is_callable` (including callable arrays!), 265 | * we directly append the argument to `$this->middleware`. Else, we 266 | * assume the argument is an array of callables and merge the array 267 | * with `$this->middleware`. Even if non-callables are included in the 268 | * argument array, we still merge them; we lazily check each item 269 | * against `is_callable` during Route::dispatch(). 270 | * 271 | * @param Callable|array[Callable] 272 | * @return Slim_Route 273 | * @throws InvalidArgumentException If argument is not callable or not an array 274 | */ 275 | public function setMiddleware( $middleware ) { 276 | if ( is_callable($middleware) ) { 277 | $this->middleware[] = $middleware; 278 | } else if ( is_array($middleware) ) { 279 | $this->middleware = array_merge($this->middleware, $middleware); 280 | } else { 281 | throw new InvalidArgumentException('Route middleware must be callable or an array of callables'); 282 | } 283 | return $this; 284 | } 285 | 286 | /** 287 | * Matches URI? 288 | * 289 | * Parse this route's pattern, and then compare it to an HTTP resource URI 290 | * This method was modeled after the techniques demonstrated by Dan Sosedoff at: 291 | * 292 | * http://blog.sosedoff.com/2009/09/20/rails-like-php-url-router/ 293 | * 294 | * @param string $resourceUri A Request URI 295 | * @return bool 296 | */ 297 | public function matches( $resourceUri ) { 298 | //Extract URL params 299 | preg_match_all('@:([\w]+)@', $this->pattern, $paramNames, PREG_PATTERN_ORDER); 300 | $paramNames = $paramNames[0]; 301 | 302 | //Convert URL params into regex patterns, construct a regex for this route 303 | $patternAsRegex = preg_replace_callback('@:[\w]+@', array($this, 'convertPatternToRegex'), $this->pattern); 304 | if ( substr($this->pattern, -1) === '/' ) { 305 | $patternAsRegex = $patternAsRegex . '?'; 306 | } 307 | $patternAsRegex = '@^' . $patternAsRegex . '$@'; 308 | 309 | //Cache URL params' names and values if this route matches the current HTTP request 310 | if ( preg_match($patternAsRegex, $resourceUri, $paramValues) ) { 311 | array_shift($paramValues); 312 | foreach ( $paramNames as $index => $value ) { 313 | $val = substr($value, 1); 314 | if ( isset($paramValues[$val]) ) { 315 | $this->params[$val] = urldecode($paramValues[$val]); 316 | } 317 | } 318 | return true; 319 | } else { 320 | return false; 321 | } 322 | } 323 | 324 | /** 325 | * Convert a URL parameter (ie. ":id") into a regular expression 326 | * @param array URL parameters 327 | * @return string Regular expression for URL parameter 328 | */ 329 | protected function convertPatternToRegex( $matches ) { 330 | $key = str_replace(':', '', $matches[0]); 331 | if ( array_key_exists($key, $this->conditions) ) { 332 | return '(?P<' . $key . '>' . $this->conditions[$key] . ')'; 333 | } else { 334 | return '(?P<' . $key . '>[a-zA-Z0-9_\-\.\!\~\*\\\'\(\)\:\@\&\=\$\+,%]+)'; 335 | } 336 | } 337 | 338 | /** 339 | * Set route name 340 | * @param string $name The name of the route 341 | * @return Slim_Route 342 | */ 343 | public function name( $name ) { 344 | $this->setName($name); 345 | return $this; 346 | } 347 | 348 | /** 349 | * Merge route conditions 350 | * @param array $conditions Key-value array of URL parameter conditions 351 | * @return Slim_Route 352 | */ 353 | public function conditions( array $conditions ) { 354 | $this->conditions = array_merge($this->conditions, $conditions); 355 | return $this; 356 | } 357 | 358 | /** 359 | * Dispatch route 360 | * 361 | * This method invokes this route's callable. If middleware is 362 | * registered for this route, each callable middleware is invoked in 363 | * the order specified. 364 | * 365 | * This method is smart about trailing slashes on the route pattern. 366 | * If this route's pattern is defined with a trailing slash, and if the 367 | * current request URI does not have a trailing slash but otherwise 368 | * matches this route's pattern, a Slim_Exception_RequestSlash 369 | * will be thrown triggering an HTTP 301 Permanent Redirect to the same 370 | * URI _with_ a trailing slash. This Exception is caught in the 371 | * `Slim::run` loop. If this route's pattern is defined without a 372 | * trailing slash, and if the current request URI does have a trailing 373 | * slash, this route will not be matched and a 404 Not Found 374 | * response will be sent if no subsequent matching routes are found. 375 | * 376 | * @return bool Was route callable invoked successfully? 377 | * @throws Slim_Exception_RequestSlash 378 | */ 379 | public function dispatch() { 380 | if ( substr($this->pattern, -1) === '/' && substr($this->router->getRequest()->getResourceUri(), -1) !== '/' ) { 381 | throw new Slim_Exception_RequestSlash(); 382 | } 383 | 384 | //Invoke middleware 385 | $req = $this->router->getRequest(); 386 | $res = $this->router->getResponse(); 387 | foreach ( $this->middleware as $mw ) { 388 | if ( is_callable($mw) ) { 389 | call_user_func_array($mw, array($req, $res, $this)); 390 | } 391 | } 392 | 393 | //Invoke callable 394 | if ( is_callable($this->getCallable()) ) { 395 | call_user_func_array($this->callable, array_values($this->params)); 396 | return true; 397 | } 398 | return false; 399 | } 400 | } -------------------------------------------------------------------------------- /libs/Slim/Router.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Router 36 | * 37 | * This class organizes Route objects and, upon request, will 38 | * return an iterator for routes that match the HTTP request URI. 39 | * 40 | * @package Slim 41 | * @author Josh Lockhart 42 | * @since 1.0.0 43 | */ 44 | class Slim_Router implements IteratorAggregate { 45 | /** 46 | * @var Slim_Http_Request 47 | */ 48 | protected $request; 49 | 50 | /** 51 | * @var Slim_Http_Response 52 | */ 53 | protected $response; 54 | 55 | /** 56 | * @var array Lookup hash of all routes 57 | */ 58 | protected $routes; 59 | 60 | /** 61 | * @var array Lookup hash of named routes, keyed by route name 62 | */ 63 | protected $namedRoutes; 64 | 65 | /** 66 | * @var array Array of routes that match the Request URI (lazy-loaded) 67 | */ 68 | protected $matchedRoutes; 69 | 70 | /** 71 | * @var mixed Callable to be invoked if no matching routes are found 72 | */ 73 | protected $notFound; 74 | 75 | /** 76 | * @var mixed Callable to be invoked if application error 77 | */ 78 | protected $error; 79 | 80 | /** 81 | * Constructor 82 | * @param Slim_Http_Request $request The HTTP request object 83 | * @param Slim_Http_Response $response The HTTP response object 84 | */ 85 | public function __construct( Slim_Http_Request $request, Slim_Http_Response $response ) { 86 | $this->request = $request; 87 | $this->response = $response; 88 | $this->routes = array(); 89 | $this->namedRoutes = array(); 90 | } 91 | 92 | /** 93 | * Get Iterator 94 | * @return ArrayIterator 95 | */ 96 | public function getIterator() { 97 | return new ArrayIterator($this->getMatchedRoutes()); 98 | } 99 | 100 | /** 101 | * Get Request 102 | * @return Slim_Http_Request 103 | */ 104 | public function getRequest() { 105 | return $this->request; 106 | } 107 | 108 | /** 109 | * Get Response 110 | * @return Slim_Http_Response 111 | */ 112 | public function getResponse() { 113 | return $this->response; 114 | } 115 | 116 | /** 117 | * Return routes that match the current request 118 | * @return array[Slim_Route] 119 | */ 120 | public function getMatchedRoutes( $reload = false ) { 121 | if ( $reload || is_null($this->matchedRoutes) ) { 122 | $this->matchedRoutes = array(); 123 | foreach ( $this->routes as $route ) { 124 | if ( $route->matches($this->request->getResourceUri()) ) { 125 | $this->matchedRoutes[] = $route; 126 | } 127 | } 128 | } 129 | return $this->matchedRoutes; 130 | } 131 | 132 | /** 133 | * Map a route to a callback function 134 | * @param string $pattern The URL pattern (ie. "/books/:id") 135 | * @param mixed $callable Anything that returns TRUE for is_callable() 136 | * @return Slim_Route 137 | */ 138 | public function map( $pattern, $callable ) { 139 | $route = new Slim_Route($pattern, $callable); 140 | $route->setRouter($this); 141 | $this->routes[] = $route; 142 | return $route; 143 | } 144 | 145 | /** 146 | * Get URL for named route 147 | * @param string $name The name of the route 148 | * @param array Associative array of URL parameter names and values 149 | * @throws RuntimeException If named route not found 150 | * @return string The URL for the given route populated with the given parameters 151 | */ 152 | public function urlFor( $name, $params = array() ) { 153 | if ( !$this->hasNamedRoute($name) ) { 154 | throw new RuntimeException('Named route not found for name: ' . $name); 155 | } 156 | $pattern = $this->getNamedRoute($name)->getPattern(); 157 | $search = $replace = array(); 158 | foreach ( $params as $key => $value ) { 159 | $search[] = ':' . $key; 160 | $replace[] = $value; 161 | } 162 | $pattern = str_replace($search, $replace, $pattern); 163 | //Remove remnants of unpopulated, trailing optional pattern segments 164 | return preg_replace(array( 165 | '@\(\/?:.+\/??\)\??@', 166 | '@\?|\(|\)@' 167 | ), '', $this->request->getRootUri() . $pattern); 168 | } 169 | 170 | /** 171 | * Add named route 172 | * @param string $name The route name 173 | * @param Slim_Route $route The route object 174 | * @throws RuntimeException If a named route already exists with the same name 175 | * @return void 176 | */ 177 | public function addNamedRoute( $name, Slim_Route $route ) { 178 | if ( $this->hasNamedRoute($name) ) { 179 | throw new RuntimeException('Named route already exists with name: ' . $name); 180 | } 181 | $this->namedRoutes[(string)$name] = $route; 182 | } 183 | 184 | /** 185 | * Has named route 186 | * @param string $name The route name 187 | * @return bool 188 | */ 189 | public function hasNamedRoute( $name ) { 190 | return isset($this->namedRoutes[(string)$name]); 191 | } 192 | 193 | /** 194 | * Get named route 195 | * @param string $name 196 | * @return Slim_Route|null 197 | */ 198 | public function getNamedRoute( $name ) { 199 | if ( $this->hasNamedRoute($name) ) { 200 | return $this->namedRoutes[(string)$name]; 201 | } else { 202 | return null; 203 | } 204 | } 205 | 206 | /** 207 | * Get named routes 208 | * @return ArrayIterator 209 | */ 210 | public function getNamedRoutes() { 211 | return new ArrayIterator($this->namedRoutes); 212 | } 213 | 214 | /** 215 | * Register a 404 Not Found callback 216 | * @param mixed $callable Anything that returns TRUE for is_callable() 217 | * @return mixed 218 | */ 219 | public function notFound( $callable = null ) { 220 | if ( is_callable($callable) ) { 221 | $this->notFound = $callable; 222 | } 223 | return $this->notFound; 224 | } 225 | 226 | /** 227 | * Register a 500 Error callback 228 | * @param mixed $callable Anything that returns TRUE for is_callable() 229 | * @return mixed 230 | */ 231 | public function error( $callable = null ) { 232 | if ( is_callable($callable) ) { 233 | $this->error = $callable; 234 | } 235 | return $this->error; 236 | } 237 | } -------------------------------------------------------------------------------- /libs/Slim/View.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2011 Josh Lockhart 7 | * @link http://www.slimframework.com 8 | * @license http://www.slimframework.com/license 9 | * @version 1.6.0 10 | * @package Slim 11 | * 12 | * MIT LICENSE 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining 15 | * a copy of this software and associated documentation files (the 16 | * "Software"), to deal in the Software without restriction, including 17 | * without limitation the rights to use, copy, modify, merge, publish, 18 | * distribute, sublicense, and/or sell copies of the Software, and to 19 | * permit persons to whom the Software is furnished to do so, subject to 20 | * the following conditions: 21 | * 22 | * The above copyright notice and this permission notice shall be 23 | * included in all copies or substantial portions of the Software. 24 | * 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | /** 35 | * Slim View 36 | * 37 | * The View is responsible for rendering and/or displaying a template. 38 | * It is recommended that you subclass View and re-implement the 39 | * `View::render` method to use a custom templating engine such as 40 | * Smarty, Twig, Mustache, etc. It is important that `View::render` 41 | * `return` the final template output. Do not `echo` the output. 42 | * 43 | * @package Slim 44 | * @author Josh Lockhart 45 | * @since 1.0.0 46 | */ 47 | class Slim_View { 48 | /** 49 | * @var array Key-value array of data available to the template 50 | */ 51 | protected $data = array(); 52 | 53 | /** 54 | * @var string Absolute or relative path to the templates directory 55 | */ 56 | protected $templatesDirectory; 57 | 58 | /** 59 | * Constructor 60 | * 61 | * This is empty but may be overridden in a subclass 62 | */ 63 | public function __construct() {} 64 | 65 | /** 66 | * Get data 67 | * @param string $key 68 | * @return array|mixed|null All View data if no $key, value of datum 69 | * if $key, or NULL if $key but datum 70 | * does not exist. 71 | */ 72 | public function getData( $key = null ) { 73 | if ( !is_null($key) ) { 74 | return isset($this->data[$key]) ? $this->data[$key] : null; 75 | } else { 76 | return $this->data; 77 | } 78 | } 79 | 80 | /** 81 | * Set data 82 | * 83 | * This method is overloaded to accept two different method signatures. 84 | * You may use this to set a specific key with a specfic value, 85 | * or you may use this to set all data to a specific array. 86 | * 87 | * USAGE: 88 | * 89 | * View::setData('color', 'red'); 90 | * View::setData(array('color' => 'red', 'number' => 1)); 91 | * 92 | * @param string|array 93 | * @param mixed Optional. Only use if first argument is a string. 94 | * @return void 95 | * @throws InvalidArgumentException If incorrect method signature 96 | */ 97 | public function setData() { 98 | $args = func_get_args(); 99 | if ( count($args) === 1 && is_array($args[0]) ) { 100 | $this->data = $args[0]; 101 | } else if ( count($args) === 2 ) { 102 | $this->data[(string)$args[0]] = $args[1]; 103 | } else { 104 | throw new InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`'); 105 | } 106 | } 107 | 108 | /** 109 | * Append data to existing View data 110 | * @param array $data 111 | * @return void 112 | */ 113 | public function appendData( array $data ) { 114 | $this->data = array_merge($this->data, $data); 115 | } 116 | 117 | /** 118 | * Get templates directory 119 | * @return string|null Path to templates directory without trailing slash 120 | */ 121 | public function getTemplatesDirectory() { 122 | return $this->templatesDirectory; 123 | } 124 | 125 | /** 126 | * Set templates directory 127 | * @param string $dir 128 | * @return void 129 | * @throws RuntimeException If directory is not a directory or does not exist 130 | */ 131 | public function setTemplatesDirectory( $dir ) { 132 | $this->templatesDirectory = rtrim($dir, '/'); 133 | } 134 | 135 | /** 136 | * Display template 137 | * 138 | * This method echoes the rendered template to the current output buffer 139 | * 140 | * @param string $template Path to template file relative to templates directoy 141 | * @return void 142 | */ 143 | public function display( $template ) { 144 | echo $this->render($template); 145 | } 146 | 147 | /** 148 | * Render template 149 | * @param string $template Path to template file relative to templates directory 150 | * @return string Rendered template 151 | * @throws RuntimeException If template does not exist 152 | */ 153 | public function render( $template ) { 154 | extract($this->data); 155 | $templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/'); 156 | if ( !file_exists($templatePath) ) { 157 | throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.'); 158 | } 159 | ob_start(); 160 | require $templatePath; 161 | return ob_get_clean(); 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /libs/spyc.php: -------------------------------------------------------------------------------- 1 | 6 | * @author Chris Wanstrath 7 | * @link http://code.google.com/p/spyc/ 8 | * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen 9 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 10 | * @package Spyc 11 | */ 12 | 13 | if (!function_exists('spyc_load')) { 14 | /** 15 | * Parses YAML to array. 16 | * @param string $string YAML string. 17 | * @return array 18 | */ 19 | function spyc_load ($string) { 20 | return Spyc::YAMLLoadString($string); 21 | } 22 | } 23 | 24 | if (!function_exists('spyc_load_file')) { 25 | /** 26 | * Parses YAML to array. 27 | * @param string $file Path to YAML file. 28 | * @return array 29 | */ 30 | function spyc_load_file ($file) { 31 | return Spyc::YAMLLoad($file); 32 | } 33 | } 34 | 35 | /** 36 | * The Simple PHP YAML Class. 37 | * 38 | * This class can be used to read a YAML file and convert its contents 39 | * into a PHP array. It currently supports a very limited subsection of 40 | * the YAML spec. 41 | * 42 | * Usage: 43 | * 44 | * $Spyc = new Spyc; 45 | * $array = $Spyc->load($file); 46 | * 47 | * or: 48 | * 49 | * $array = Spyc::YAMLLoad($file); 50 | * 51 | * or: 52 | * 53 | * $array = spyc_load_file($file); 54 | * 55 | * @package Spyc 56 | */ 57 | class Spyc { 58 | 59 | // SETTINGS 60 | 61 | const REMPTY = "\0\0\0\0\0"; 62 | 63 | /** 64 | * Setting this to true will force YAMLDump to enclose any string value in 65 | * quotes. False by default. 66 | * 67 | * @var bool 68 | */ 69 | public $setting_dump_force_quotes = false; 70 | 71 | /** 72 | * Setting this to true will forse YAMLLoad to use syck_load function when 73 | * possible. False by default. 74 | * @var bool 75 | */ 76 | public $setting_use_syck_is_possible = false; 77 | 78 | 79 | 80 | /**#@+ 81 | * @access private 82 | * @var mixed 83 | */ 84 | private $_dumpIndent; 85 | private $_dumpWordWrap; 86 | private $_containsGroupAnchor = false; 87 | private $_containsGroupAlias = false; 88 | private $path; 89 | private $result; 90 | private $LiteralPlaceHolder = '___YAML_Literal_Block___'; 91 | private $SavedGroups = array(); 92 | private $indent; 93 | /** 94 | * Path modifier that should be applied after adding current element. 95 | * @var array 96 | */ 97 | private $delayedPath = array(); 98 | 99 | /**#@+ 100 | * @access public 101 | * @var mixed 102 | */ 103 | public $_nodeId; 104 | 105 | /** 106 | * Load a valid YAML string to Spyc. 107 | * @param string $input 108 | * @return array 109 | */ 110 | public function load ($input) { 111 | return $this->__loadString($input); 112 | } 113 | 114 | /** 115 | * Load a valid YAML file to Spyc. 116 | * @param string $file 117 | * @return array 118 | */ 119 | public function loadFile ($file) { 120 | return $this->__load($file); 121 | } 122 | 123 | /** 124 | * Load YAML into a PHP array statically 125 | * 126 | * The load method, when supplied with a YAML stream (string or file), 127 | * will do its best to convert YAML in a file into a PHP array. Pretty 128 | * simple. 129 | * Usage: 130 | * 131 | * $array = Spyc::YAMLLoad('lucky.yaml'); 132 | * print_r($array); 133 | * 134 | * @access public 135 | * @return array 136 | * @param string $input Path of YAML file or string containing YAML 137 | */ 138 | public static function YAMLLoad($input) { 139 | $Spyc = new Spyc; 140 | return $Spyc->__load($input); 141 | } 142 | 143 | /** 144 | * Load a string of YAML into a PHP array statically 145 | * 146 | * The load method, when supplied with a YAML string, will do its best 147 | * to convert YAML in a string into a PHP array. Pretty simple. 148 | * 149 | * Note: use this function if you don't want files from the file system 150 | * loaded and processed as YAML. This is of interest to people concerned 151 | * about security whose input is from a string. 152 | * 153 | * Usage: 154 | * 155 | * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); 156 | * print_r($array); 157 | * 158 | * @access public 159 | * @return array 160 | * @param string $input String containing YAML 161 | */ 162 | public static function YAMLLoadString($input) { 163 | $Spyc = new Spyc; 164 | return $Spyc->__loadString($input); 165 | } 166 | 167 | /** 168 | * Dump YAML from PHP array statically 169 | * 170 | * The dump method, when supplied with an array, will do its best 171 | * to convert the array into friendly YAML. Pretty simple. Feel free to 172 | * save the returned string as nothing.yaml and pass it around. 173 | * 174 | * Oh, and you can decide how big the indent is and what the wordwrap 175 | * for folding is. Pretty cool -- just pass in 'false' for either if 176 | * you want to use the default. 177 | * 178 | * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 179 | * you can turn off wordwrap by passing in 0. 180 | * 181 | * @access public 182 | * @return string 183 | * @param array $array PHP array 184 | * @param int $indent Pass in false to use the default, which is 2 185 | * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 186 | */ 187 | public static function YAMLDump($array,$indent = false,$wordwrap = false) { 188 | $spyc = new Spyc; 189 | return $spyc->dump($array,$indent,$wordwrap); 190 | } 191 | 192 | 193 | /** 194 | * Dump PHP array to YAML 195 | * 196 | * The dump method, when supplied with an array, will do its best 197 | * to convert the array into friendly YAML. Pretty simple. Feel free to 198 | * save the returned string as tasteful.yaml and pass it around. 199 | * 200 | * Oh, and you can decide how big the indent is and what the wordwrap 201 | * for folding is. Pretty cool -- just pass in 'false' for either if 202 | * you want to use the default. 203 | * 204 | * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 205 | * you can turn off wordwrap by passing in 0. 206 | * 207 | * @access public 208 | * @return string 209 | * @param array $array PHP array 210 | * @param int $indent Pass in false to use the default, which is 2 211 | * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 212 | */ 213 | public function dump($array,$indent = false,$wordwrap = false) { 214 | // Dumps to some very clean YAML. We'll have to add some more features 215 | // and options soon. And better support for folding. 216 | 217 | // New features and options. 218 | if ($indent === false or !is_numeric($indent)) { 219 | $this->_dumpIndent = 2; 220 | } else { 221 | $this->_dumpIndent = $indent; 222 | } 223 | 224 | if ($wordwrap === false or !is_numeric($wordwrap)) { 225 | $this->_dumpWordWrap = 40; 226 | } else { 227 | $this->_dumpWordWrap = $wordwrap; 228 | } 229 | 230 | // New YAML document 231 | $string = "---\n"; 232 | 233 | // Start at the base of the array and move through it. 234 | if ($array) { 235 | $array = (array)$array; 236 | $previous_key = -1; 237 | foreach ($array as $key => $value) { 238 | if (!isset($first_key)) $first_key = $key; 239 | $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array); 240 | $previous_key = $key; 241 | } 242 | } 243 | return $string; 244 | } 245 | 246 | /** 247 | * Attempts to convert a key / value array item to YAML 248 | * @access private 249 | * @return string 250 | * @param $key The name of the key 251 | * @param $value The value of the item 252 | * @param $indent The indent of the current node 253 | */ 254 | private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) { 255 | if (is_array($value)) { 256 | if (empty ($value)) 257 | return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); 258 | // It has children. What to do? 259 | // Make it the right kind of item 260 | $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); 261 | // Add the indent 262 | $indent += $this->_dumpIndent; 263 | // Yamlize the array 264 | $string .= $this->_yamlizeArray($value,$indent); 265 | } elseif (!is_array($value)) { 266 | // It doesn't have children. Yip. 267 | $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); 268 | } 269 | return $string; 270 | } 271 | 272 | /** 273 | * Attempts to convert an array to YAML 274 | * @access private 275 | * @return string 276 | * @param $array The array you want to convert 277 | * @param $indent The indent of the current level 278 | */ 279 | private function _yamlizeArray($array,$indent) { 280 | if (is_array($array)) { 281 | $string = ''; 282 | $previous_key = -1; 283 | foreach ($array as $key => $value) { 284 | if (!isset($first_key)) $first_key = $key; 285 | $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array); 286 | $previous_key = $key; 287 | } 288 | return $string; 289 | } else { 290 | return false; 291 | } 292 | } 293 | 294 | /** 295 | * Returns YAML from a key and a value 296 | * @access private 297 | * @return string 298 | * @param $key The name of the key 299 | * @param $value The value of the item 300 | * @param $indent The indent of the current node 301 | */ 302 | private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { 303 | // do some folding here, for blocks 304 | if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || 305 | strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false || 306 | strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || 307 | substr ($value, -1, 1) == ':') 308 | ) { 309 | $value = $this->_doLiteralBlock($value,$indent); 310 | } else { 311 | $value = $this->_doFolding($value,$indent); 312 | } 313 | 314 | if ($value === array()) $value = '[ ]'; 315 | if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) { 316 | $value = $this->_doLiteralBlock($value,$indent); 317 | } 318 | if (trim ($value) != $value) 319 | $value = $this->_doLiteralBlock($value,$indent); 320 | 321 | if (is_bool($value)) { 322 | $value = ($value) ? "true" : "false"; 323 | } 324 | 325 | if ($value === null) $value = 'null'; 326 | if ($value === "'" . self::REMPTY . "'") $value = null; 327 | 328 | $spaces = str_repeat(' ',$indent); 329 | 330 | //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { 331 | if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { 332 | // It's a sequence 333 | $string = $spaces.'- '.$value."\n"; 334 | } else { 335 | // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); 336 | // It's mapped 337 | if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; } 338 | $string = rtrim ($spaces.$key.': '.$value)."\n"; 339 | } 340 | return $string; 341 | } 342 | 343 | /** 344 | * Creates a literal block for dumping 345 | * @access private 346 | * @return string 347 | * @param $value 348 | * @param $indent int The value of the indent 349 | */ 350 | private function _doLiteralBlock($value,$indent) { 351 | if ($value === "\n") return '\n'; 352 | if (strpos($value, "\n") === false && strpos($value, "'") === false) { 353 | return sprintf ("'%s'", $value); 354 | } 355 | if (strpos($value, "\n") === false && strpos($value, '"') === false) { 356 | return sprintf ('"%s"', $value); 357 | } 358 | $exploded = explode("\n",$value); 359 | $newValue = '|'; 360 | $indent += $this->_dumpIndent; 361 | $spaces = str_repeat(' ',$indent); 362 | foreach ($exploded as $line) { 363 | $newValue .= "\n" . $spaces . ($line); 364 | } 365 | return $newValue; 366 | } 367 | 368 | /** 369 | * Folds a string of text, if necessary 370 | * @access private 371 | * @return string 372 | * @param $value The string you wish to fold 373 | */ 374 | private function _doFolding($value,$indent) { 375 | // Don't do anything if wordwrap is set to 0 376 | 377 | if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { 378 | $indent += $this->_dumpIndent; 379 | $indent = str_repeat(' ',$indent); 380 | $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); 381 | $value = ">\n".$indent.$wrapped; 382 | } else { 383 | if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY) 384 | $value = '"' . $value . '"'; 385 | } 386 | 387 | 388 | return $value; 389 | } 390 | 391 | // LOADING FUNCTIONS 392 | 393 | private function __load($input) { 394 | $Source = $this->loadFromSource($input); 395 | return $this->loadWithSource($Source); 396 | } 397 | 398 | private function __loadString($input) { 399 | $Source = $this->loadFromString($input); 400 | return $this->loadWithSource($Source); 401 | } 402 | 403 | private function loadWithSource($Source) { 404 | if (empty ($Source)) return array(); 405 | if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { 406 | $array = syck_load (implode ('', $Source)); 407 | return is_array($array) ? $array : array(); 408 | } 409 | 410 | $this->path = array(); 411 | $this->result = array(); 412 | 413 | $cnt = count($Source); 414 | for ($i = 0; $i < $cnt; $i++) { 415 | $line = $Source[$i]; 416 | 417 | $this->indent = strlen($line) - strlen(ltrim($line)); 418 | $tempPath = $this->getParentPathByIndent($this->indent); 419 | $line = self::stripIndent($line, $this->indent); 420 | if (self::isComment($line)) continue; 421 | if (self::isEmpty($line)) continue; 422 | $this->path = $tempPath; 423 | 424 | $literalBlockStyle = self::startsLiteralBlock($line); 425 | if ($literalBlockStyle) { 426 | $line = rtrim ($line, $literalBlockStyle . " \n"); 427 | $literalBlock = ''; 428 | $line .= $this->LiteralPlaceHolder; 429 | $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1])); 430 | while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { 431 | $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); 432 | } 433 | $i--; 434 | } 435 | 436 | while (++$i < $cnt && self::greedilyNeedNextLine($line)) { 437 | $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); 438 | } 439 | $i--; 440 | 441 | 442 | 443 | if (strpos ($line, '#')) { 444 | if (strpos ($line, '"') === false && strpos ($line, "'") === false) 445 | $line = preg_replace('/\s+#(.+)$/','',$line); 446 | } 447 | 448 | $lineArray = $this->_parseLine($line); 449 | 450 | if ($literalBlockStyle) 451 | $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); 452 | 453 | $this->addArray($lineArray, $this->indent); 454 | 455 | foreach ($this->delayedPath as $indent => $delayedPath) 456 | $this->path[$indent] = $delayedPath; 457 | 458 | $this->delayedPath = array(); 459 | 460 | } 461 | return $this->result; 462 | } 463 | 464 | private function loadFromSource ($input) { 465 | if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) 466 | return file($input); 467 | 468 | return $this->loadFromString($input); 469 | } 470 | 471 | private function loadFromString ($input) { 472 | $lines = explode("\n",$input); 473 | foreach ($lines as $k => $_) { 474 | $lines[$k] = rtrim ($_, "\r"); 475 | } 476 | return $lines; 477 | } 478 | 479 | /** 480 | * Parses YAML code and returns an array for a node 481 | * @access private 482 | * @return array 483 | * @param string $line A line from the YAML file 484 | */ 485 | private function _parseLine($line) { 486 | if (!$line) return array(); 487 | $line = trim($line); 488 | if (!$line) return array(); 489 | 490 | $array = array(); 491 | 492 | $group = $this->nodeContainsGroup($line); 493 | if ($group) { 494 | $this->addGroup($line, $group); 495 | $line = $this->stripGroup ($line, $group); 496 | } 497 | 498 | if ($this->startsMappedSequence($line)) 499 | return $this->returnMappedSequence($line); 500 | 501 | if ($this->startsMappedValue($line)) 502 | return $this->returnMappedValue($line); 503 | 504 | if ($this->isArrayElement($line)) 505 | return $this->returnArrayElement($line); 506 | 507 | if ($this->isPlainArray($line)) 508 | return $this->returnPlainArray($line); 509 | 510 | 511 | return $this->returnKeyValuePair($line); 512 | 513 | } 514 | 515 | /** 516 | * Finds the type of the passed value, returns the value as the new type. 517 | * @access private 518 | * @param string $value 519 | * @return mixed 520 | */ 521 | private function _toType($value) { 522 | if ($value === '') return null; 523 | $first_character = $value[0]; 524 | $last_character = substr($value, -1, 1); 525 | 526 | $is_quoted = false; 527 | do { 528 | if (!$value) break; 529 | if ($first_character != '"' && $first_character != "'") break; 530 | if ($last_character != '"' && $last_character != "'") break; 531 | $is_quoted = true; 532 | } while (0); 533 | 534 | if ($is_quoted) 535 | return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); 536 | 537 | if (strpos($value, ' #') !== false && !$is_quoted) 538 | $value = preg_replace('/\s+#(.+)$/','',$value); 539 | 540 | if (!$is_quoted) $value = str_replace('\n', "\n", $value); 541 | 542 | if ($first_character == '[' && $last_character == ']') { 543 | // Take out strings sequences and mappings 544 | $innerValue = trim(substr ($value, 1, -1)); 545 | if ($innerValue === '') return array(); 546 | $explode = $this->_inlineEscape($innerValue); 547 | // Propagate value array 548 | $value = array(); 549 | foreach ($explode as $v) { 550 | $value[] = $this->_toType($v); 551 | } 552 | return $value; 553 | } 554 | 555 | if (strpos($value,': ')!==false && $first_character != '{') { 556 | $array = explode(': ',$value); 557 | $key = trim($array[0]); 558 | array_shift($array); 559 | $value = trim(implode(': ',$array)); 560 | $value = $this->_toType($value); 561 | return array($key => $value); 562 | } 563 | 564 | if ($first_character == '{' && $last_character == '}') { 565 | $innerValue = trim(substr ($value, 1, -1)); 566 | if ($innerValue === '') return array(); 567 | // Inline Mapping 568 | // Take out strings sequences and mappings 569 | $explode = $this->_inlineEscape($innerValue); 570 | // Propagate value array 571 | $array = array(); 572 | foreach ($explode as $v) { 573 | $SubArr = $this->_toType($v); 574 | if (empty($SubArr)) continue; 575 | if (is_array ($SubArr)) { 576 | $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; 577 | } 578 | $array[] = $SubArr; 579 | } 580 | return $array; 581 | } 582 | 583 | if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { 584 | return null; 585 | } 586 | 587 | if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){ 588 | $intvalue = (int)$value; 589 | if ($intvalue != PHP_INT_MAX) 590 | $value = $intvalue; 591 | return $value; 592 | } 593 | 594 | if (in_array($value, 595 | array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { 596 | return true; 597 | } 598 | 599 | if (in_array(strtolower($value), 600 | array('false', 'off', '-', 'no', 'n'))) { 601 | return false; 602 | } 603 | 604 | if (is_numeric($value)) { 605 | if ($value === '0') return 0; 606 | if (rtrim ($value, 0) === $value) 607 | $value = (float)$value; 608 | return $value; 609 | } 610 | 611 | return $value; 612 | } 613 | 614 | /** 615 | * Used in inlines to check for more inlines or quoted strings 616 | * @access private 617 | * @return array 618 | */ 619 | private function _inlineEscape($inline) { 620 | // There's gotta be a cleaner way to do this... 621 | // While pure sequences seem to be nesting just fine, 622 | // pure mappings and mappings with sequences inside can't go very 623 | // deep. This needs to be fixed. 624 | 625 | $seqs = array(); 626 | $maps = array(); 627 | $saved_strings = array(); 628 | 629 | // Check for strings 630 | $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; 631 | if (preg_match_all($regex,$inline,$strings)) { 632 | $saved_strings = $strings[0]; 633 | $inline = preg_replace($regex,'YAMLString',$inline); 634 | } 635 | unset($regex); 636 | 637 | $i = 0; 638 | do { 639 | 640 | // Check for sequences 641 | while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { 642 | $seqs[] = $matchseqs[0]; 643 | $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); 644 | } 645 | 646 | // Check for mappings 647 | while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { 648 | $maps[] = $matchmaps[0]; 649 | $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); 650 | } 651 | 652 | if ($i++ >= 10) break; 653 | 654 | } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); 655 | 656 | $explode = explode(', ',$inline); 657 | $stringi = 0; $i = 0; 658 | 659 | while (1) { 660 | 661 | // Re-add the sequences 662 | if (!empty($seqs)) { 663 | foreach ($explode as $key => $value) { 664 | if (strpos($value,'YAMLSeq') !== false) { 665 | foreach ($seqs as $seqk => $seq) { 666 | $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); 667 | $value = $explode[$key]; 668 | } 669 | } 670 | } 671 | } 672 | 673 | // Re-add the mappings 674 | if (!empty($maps)) { 675 | foreach ($explode as $key => $value) { 676 | if (strpos($value,'YAMLMap') !== false) { 677 | foreach ($maps as $mapk => $map) { 678 | $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); 679 | $value = $explode[$key]; 680 | } 681 | } 682 | } 683 | } 684 | 685 | 686 | // Re-add the strings 687 | if (!empty($saved_strings)) { 688 | foreach ($explode as $key => $value) { 689 | while (strpos($value,'YAMLString') !== false) { 690 | $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); 691 | unset($saved_strings[$stringi]); 692 | ++$stringi; 693 | $value = $explode[$key]; 694 | } 695 | } 696 | } 697 | 698 | $finished = true; 699 | foreach ($explode as $key => $value) { 700 | if (strpos($value,'YAMLSeq') !== false) { 701 | $finished = false; break; 702 | } 703 | if (strpos($value,'YAMLMap') !== false) { 704 | $finished = false; break; 705 | } 706 | if (strpos($value,'YAMLString') !== false) { 707 | $finished = false; break; 708 | } 709 | } 710 | if ($finished) break; 711 | 712 | $i++; 713 | if ($i > 10) 714 | break; // Prevent infinite loops. 715 | } 716 | 717 | return $explode; 718 | } 719 | 720 | private function literalBlockContinues ($line, $lineIndent) { 721 | if (!trim($line)) return true; 722 | if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; 723 | return false; 724 | } 725 | 726 | private function referenceContentsByAlias ($alias) { 727 | do { 728 | if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } 729 | $groupPath = $this->SavedGroups[$alias]; 730 | $value = $this->result; 731 | foreach ($groupPath as $k) { 732 | $value = $value[$k]; 733 | } 734 | } while (false); 735 | return $value; 736 | } 737 | 738 | private function addArrayInline ($array, $indent) { 739 | $CommonGroupPath = $this->path; 740 | if (empty ($array)) return false; 741 | 742 | foreach ($array as $k => $_) { 743 | $this->addArray(array($k => $_), $indent); 744 | $this->path = $CommonGroupPath; 745 | } 746 | return true; 747 | } 748 | 749 | private function addArray ($incoming_data, $incoming_indent) { 750 | 751 | // print_r ($incoming_data); 752 | 753 | if (count ($incoming_data) > 1) 754 | return $this->addArrayInline ($incoming_data, $incoming_indent); 755 | 756 | $key = key ($incoming_data); 757 | $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; 758 | if ($key === '__!YAMLZero') $key = '0'; 759 | 760 | if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. 761 | if ($key || $key === '' || $key === '0') { 762 | $this->result[$key] = $value; 763 | } else { 764 | $this->result[] = $value; end ($this->result); $key = key ($this->result); 765 | } 766 | $this->path[$incoming_indent] = $key; 767 | return; 768 | } 769 | 770 | 771 | 772 | $history = array(); 773 | // Unfolding inner array tree. 774 | $history[] = $_arr = $this->result; 775 | foreach ($this->path as $k) { 776 | $history[] = $_arr = $_arr[$k]; 777 | } 778 | 779 | if ($this->_containsGroupAlias) { 780 | $value = $this->referenceContentsByAlias($this->_containsGroupAlias); 781 | $this->_containsGroupAlias = false; 782 | } 783 | 784 | 785 | // Adding string or numeric key to the innermost level or $this->arr. 786 | if (is_string($key) && $key == '<<') { 787 | if (!is_array ($_arr)) { $_arr = array (); } 788 | 789 | $_arr = array_merge ($_arr, $value); 790 | } else if ($key || $key === '' || $key === '0') { 791 | if (!is_array ($_arr)) 792 | $_arr = array ($key=>$value); 793 | else 794 | $_arr[$key] = $value; 795 | } else { 796 | if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } 797 | else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } 798 | } 799 | 800 | $reverse_path = array_reverse($this->path); 801 | $reverse_history = array_reverse ($history); 802 | $reverse_history[0] = $_arr; 803 | $cnt = count($reverse_history) - 1; 804 | for ($i = 0; $i < $cnt; $i++) { 805 | $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; 806 | } 807 | $this->result = $reverse_history[$cnt]; 808 | 809 | $this->path[$incoming_indent] = $key; 810 | 811 | if ($this->_containsGroupAnchor) { 812 | $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; 813 | if (is_array ($value)) { 814 | $k = key ($value); 815 | if (!is_int ($k)) { 816 | $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; 817 | } 818 | } 819 | $this->_containsGroupAnchor = false; 820 | } 821 | 822 | } 823 | 824 | private static function startsLiteralBlock ($line) { 825 | $lastChar = substr (trim($line), -1); 826 | if ($lastChar != '>' && $lastChar != '|') return false; 827 | if ($lastChar == '|') return $lastChar; 828 | // HTML tags should not be counted as literal blocks. 829 | if (preg_match ('#<.*?>$#', $line)) return false; 830 | return $lastChar; 831 | } 832 | 833 | private static function greedilyNeedNextLine($line) { 834 | $line = trim ($line); 835 | if (!strlen($line)) return false; 836 | if (substr ($line, -1, 1) == ']') return false; 837 | if ($line[0] == '[') return true; 838 | if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; 839 | return false; 840 | } 841 | 842 | private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) { 843 | $line = self::stripIndent($line, $indent); 844 | if ($literalBlockStyle !== '|') { 845 | $line = self::stripIndent($line); 846 | } 847 | $line = rtrim ($line, "\r\n\t ") . "\n"; 848 | if ($literalBlockStyle == '|') { 849 | return $literalBlock . $line; 850 | } 851 | if (strlen($line) == 0) 852 | return rtrim($literalBlock, ' ') . "\n"; 853 | if ($line == "\n" && $literalBlockStyle == '>') { 854 | return rtrim ($literalBlock, " \t") . "\n"; 855 | } 856 | if ($line != "\n") 857 | $line = trim ($line, "\r\n ") . " "; 858 | return $literalBlock . $line; 859 | } 860 | 861 | function revertLiteralPlaceHolder ($lineArray, $literalBlock) { 862 | foreach ($lineArray as $k => $_) { 863 | if (is_array($_)) 864 | $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); 865 | else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) 866 | $lineArray[$k] = rtrim ($literalBlock, " \r\n"); 867 | } 868 | return $lineArray; 869 | } 870 | 871 | private static function stripIndent ($line, $indent = -1) { 872 | if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); 873 | return substr ($line, $indent); 874 | } 875 | 876 | private function getParentPathByIndent ($indent) { 877 | if ($indent == 0) return array(); 878 | $linePath = $this->path; 879 | do { 880 | end($linePath); $lastIndentInParentPath = key($linePath); 881 | if ($indent <= $lastIndentInParentPath) array_pop ($linePath); 882 | } while ($indent <= $lastIndentInParentPath); 883 | return $linePath; 884 | } 885 | 886 | 887 | private function clearBiggerPathValues ($indent) { 888 | 889 | 890 | if ($indent == 0) $this->path = array(); 891 | if (empty ($this->path)) return true; 892 | 893 | foreach ($this->path as $k => $_) { 894 | if ($k > $indent) unset ($this->path[$k]); 895 | } 896 | 897 | return true; 898 | } 899 | 900 | 901 | private static function isComment ($line) { 902 | if (!$line) return false; 903 | if ($line[0] == '#') return true; 904 | if (trim($line, " \r\n\t") == '---') return true; 905 | return false; 906 | } 907 | 908 | private static function isEmpty ($line) { 909 | return (trim ($line) === ''); 910 | } 911 | 912 | 913 | private function isArrayElement ($line) { 914 | if (!$line) return false; 915 | if ($line[0] != '-') return false; 916 | if (strlen ($line) > 3) 917 | if (substr($line,0,3) == '---') return false; 918 | 919 | return true; 920 | } 921 | 922 | private function isHashElement ($line) { 923 | return strpos($line, ':'); 924 | } 925 | 926 | private function isLiteral ($line) { 927 | if ($this->isArrayElement($line)) return false; 928 | if ($this->isHashElement($line)) return false; 929 | return true; 930 | } 931 | 932 | 933 | private static function unquote ($value) { 934 | if (!$value) return $value; 935 | if (!is_string($value)) return $value; 936 | if ($value[0] == '\'') return trim ($value, '\''); 937 | if ($value[0] == '"') return trim ($value, '"'); 938 | return $value; 939 | } 940 | 941 | private function startsMappedSequence ($line) { 942 | return ($line[0] == '-' && substr ($line, -1, 1) == ':'); 943 | } 944 | 945 | private function returnMappedSequence ($line) { 946 | $array = array(); 947 | $key = self::unquote(trim(substr($line,1,-1))); 948 | $array[$key] = array(); 949 | $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); 950 | return array($array); 951 | } 952 | 953 | private function returnMappedValue ($line) { 954 | $array = array(); 955 | $key = self::unquote (trim(substr($line,0,-1))); 956 | $array[$key] = ''; 957 | return $array; 958 | } 959 | 960 | private function startsMappedValue ($line) { 961 | return (substr ($line, -1, 1) == ':'); 962 | } 963 | 964 | private function isPlainArray ($line) { 965 | return ($line[0] == '[' && substr ($line, -1, 1) == ']'); 966 | } 967 | 968 | private function returnPlainArray ($line) { 969 | return $this->_toType($line); 970 | } 971 | 972 | private function returnKeyValuePair ($line) { 973 | $array = array(); 974 | $key = ''; 975 | if (strpos ($line, ':')) { 976 | // It's a key/value pair most likely 977 | // If the key is in double quotes pull it out 978 | if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { 979 | $value = trim(str_replace($matches[1],'',$line)); 980 | $key = $matches[2]; 981 | } else { 982 | // Do some guesswork as to the key and the value 983 | $explode = explode(':',$line); 984 | $key = trim($explode[0]); 985 | array_shift($explode); 986 | $value = trim(implode(':',$explode)); 987 | } 988 | // Set the type of the value. Int, string, etc 989 | $value = $this->_toType($value); 990 | if ($key === '0') $key = '__!YAMLZero'; 991 | $array[$key] = $value; 992 | } else { 993 | $array = array ($line); 994 | } 995 | return $array; 996 | 997 | } 998 | 999 | 1000 | private function returnArrayElement ($line) { 1001 | if (strlen($line) <= 1) return array(array()); // Weird %) 1002 | $array = array(); 1003 | $value = trim(substr($line,1)); 1004 | $value = $this->_toType($value); 1005 | $array[] = $value; 1006 | return $array; 1007 | } 1008 | 1009 | 1010 | private function nodeContainsGroup ($line) { 1011 | $symbolsForReference = 'A-z0-9_\-'; 1012 | if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) 1013 | if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; 1014 | if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; 1015 | if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; 1016 | if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; 1017 | if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; 1018 | return false; 1019 | 1020 | } 1021 | 1022 | private function addGroup ($line, $group) { 1023 | if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); 1024 | if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); 1025 | //print_r ($this->path); 1026 | } 1027 | 1028 | private function stripGroup ($line, $group) { 1029 | $line = trim(str_replace($group, '', $line)); 1030 | return $line; 1031 | } 1032 | } 1033 | 1034 | // Enable use of Spyc from command line 1035 | // The syntax is the following: php spyc.php spyc.yaml 1036 | 1037 | define ('SPYC_FROM_COMMAND_LINE', false); 1038 | 1039 | do { 1040 | if (!SPYC_FROM_COMMAND_LINE) break; 1041 | if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; 1042 | if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; 1043 | $file = $argv[1]; 1044 | printf ("Spyc loading file: %s\n", $file); 1045 | print_r (spyc_load_file ($file)); 1046 | } while (0); -------------------------------------------------------------------------------- /models/Admin.php: -------------------------------------------------------------------------------- 1 |