├── .gitignore ├── .htaccess ├── LICENSE ├── README.md ├── composer.json ├── docker ├── image-php-7.2 │ └── Dockerfile └── image-php-7.4.1 │ └── Dockerfile ├── include-example.php ├── index.php ├── src └── Steampixel │ └── Route.php └── web.config /.gitignore: -------------------------------------------------------------------------------- 1 | # OS files 2 | .DS_Store 3 | ._* 4 | 5 | # Compser files 6 | /vendor/ 7 | 8 | # local test environment 9 | /test/ 10 | docker-build.sh 11 | docker-bash.sh 12 | docker-run.sh 13 | docker-rm.sh 14 | release.sh 15 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | DirectoryIndex index.php 2 | 3 | # enable apache rewrite engine 4 | RewriteEngine on 5 | 6 | # set your rewrite base 7 | # Edit this in your init method too if you script lives in a subfolder 8 | RewriteBase / 9 | 10 | # Deliver the folder or file directly if it exists on the server 11 | RewriteCond %{REQUEST_FILENAME} !-f 12 | RewriteCond %{REQUEST_FILENAME} !-d 13 | 14 | # Push every request to index.php 15 | RewriteRule ^(.*)$ index.php [QSA] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 - 2020 SteamPixel and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple PHP Router ⇄ 2 | 3 | Hey! This is a simple and small single class PHP router that can handle the whole URL routing for your project. 4 | It utilizes RegExp and PHP's anonymous functions to create a lightweight and fast routing system. 5 | The router supports dynamic path parameters, special 404 and 405 routes as well as verification of request methods like GET, POST, PUT, DELETE, etc. 6 | The codebase is very small and very easy to understand. So you can use it as a boilerplate for a more complex router. 7 | 8 | Take a look at the index.php file. As you can see the `Route::add()` method is used to add new routes to your project. 9 | The first argument takes the path segment. You can also use RegExp in there to parse out variables. 10 | All matching variables will be pushed to the handler method defined in the second argument. 11 | The third argument will match the request method. The default method is 'get'. 12 | 13 | ## 📋 Simple example: 14 | ```php 15 | // Require the class 16 | include 'src\Steampixel\Route.php'; 17 | 18 | // Use this namespace 19 | use Steampixel\Route; 20 | 21 | // Add the first route 22 | Route::add('/user/([0-9]*)/edit', function($id) { 23 | echo 'Edit user with id '.$id.'
'; 24 | }, 'get'); 25 | 26 | // Run the router 27 | Route::run('/'); 28 | ``` 29 | 30 | You will find a more complex example with a build in navigation in the index.php file. 31 | 32 | ## 🎶 Installation using Composer 33 | Just run `composer require steampixel/simple-php-router` 34 | Than add the autoloader to your project like this: 35 | ```php 36 | // Autoload files using composer 37 | require_once __DIR__ . '/vendor/autoload.php'; 38 | 39 | // Use this namespace 40 | use Steampixel\Route; 41 | 42 | // Add your first route 43 | Route::add('/', function() { 44 | echo 'Welcome :-)'; 45 | }); 46 | 47 | // Run the router 48 | Route::run('/'); 49 | ``` 50 | 51 | ## ⛺ Use a different basepath 52 | If your script lives in a subfolder (e.g. /api/v1) set this basepath in your run method: 53 | 54 | ```php 55 | Route::run('/api/v1'); 56 | ``` 57 | 58 | Do not forget to edit the basepath in .htaccess too if you are on Apache2. 59 | 60 | ## ⏎ Use return instead of echo 61 | You don't have to use `echo` to output your content. You can also use the `return` statement. Everything that gets returned is echoed automatically. 62 | 63 | ```php 64 | // Add your first route 65 | Route::add('/', function() { 66 | return 'Welcome :-)'; 67 | }); 68 | ``` 69 | 70 | ## ⇒ Use arrow functions 71 | Since PHP 7.4 you can also use arrow functions to output your content. So you can easily use variables from outside and you can write shorter code. 72 | Please be aware that an Arrow function must always return a value. Therefore you cannot use `echo` directly in here. 73 | You can find an example in index.php. However, this is deactivated, as it only works from PHP 7.4. 74 | 75 | ```php 76 | Route::add('/arrow/([a-z-0-9-]*)', fn($foo) => 'This is a working arrow function example. Parameter: '.$foo ); 77 | ``` 78 | 79 | ## 📖 Return all known routes 80 | This is useful, for example, to automatically generate test routes or help pages. 81 | 82 | ```php 83 | $routes = Route::getAll(); 84 | foreach($routes as $route) { 85 | echo $route['expression'].' ('.$route['method'].')'; 86 | } 87 | ``` 88 | 89 | On top of that you could use a library like https://github.com/hoaproject/Regex to generate working example links for the different expressions. 90 | 91 | ## 🧰 Enable case sensitive routes, trailing slashes and multi match mode 92 | The second, third and fourth parameters of `Route::run('/', false, false, false);` are set to false by default. 93 | Using this parameters you can switch on and off several options: 94 | * Second parameter: You can enable case sensitive mode by setting the second parameter to true. 95 | * Third parameter: By default the router will ignore trailing slashes. Set this parameter to true to avoid this. 96 | * Fourth parameter: By default the router will only execute the first matching route. Set this parameter to true to enable multi match mode. 97 | 98 | ## ⁉ Something does not work? 99 | * Don't forget to set the correct basepath as the first argument in your `run()` method and in your .htaccess file. 100 | * Enable mod_rewrite in your Apache2 settings, in case you're using Apache2: `a2enmod apache2` 101 | * Does Apache2 even load the .htaccess file? Check whether the `AllowOverride All` option is set in the Apache2 configuration like in this example: 102 | ``` 103 | 104 | ServerName mysite.com 105 | DocumentRoot /var/www/html/mysite.com 106 | 107 | AllowOverride All 108 | 109 | 110 | ``` 111 | 112 | ## 🚀 Pages, Templates, Themes, Components 113 | This is a simple router. So there is no templating at all. But it works perfectly together with [simplePHPComponents](https://github.com/steampixel/simplePHPComponents) and [simplePHPPortals](https://github.com/steampixel/simplePHPPortals). There is a complete boilerplate project including these dependencies and this router called [simplePHPPages](https://github.com/steampixel/simplePHPPages). You can use it for you next project. 114 | 115 | ## 🎓 What skills do you need? 116 | Please be aware that for this router you need a basic understanding of PHP. Many problems stem from people lacking basic programming knowledge. You should therefore have the following skills: 117 | * Basic PHP Knowledge 118 | * Basic understanding of RegExp in PHP: https://www.guru99.com/php-regular-expressions.html 119 | * Basic understanding of anonymous functions and how to push data inside it: https://www.php.net/manual/en/functions.anonymous.php 120 | * Basic understanding of including and requiring files and how to push data to them: https://stackoverflow.com/questions/4315271/how-to-pass-arguments-to-an-included-file/5503326 121 | * Windows Only - Setup IIS and PHP: https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php. 122 | * Windows Only - Creating Websites in IIS: https://docs.microsoft.com/en-us/iis/get-started/getting-started-with-iis/create-a-web-site. 123 | 124 | Please note that we are happy to help you if you have problems with this router. Unfortunately, we don't have a lot of time, so we can't help you learn PHP basics. 125 | 126 | ## 🚢 Test setup with Docker 127 | I have created a little Docker test setup. 128 | 129 | 1. Build the image: `docker build -t simplephprouter docker/image-php-7.2` 130 | 131 | 2. Spin up a container 132 | * On Linux / Mac or Windows Powershell use: `docker run -d -p 80:80 -v $(pwd):/var/www/html --name simplephprouter simplephprouter` 133 | * On Windows CMD use `docker run -d -p 80:80 -v %cd%:/var/www/html --name simplephprouter simplephprouter` 134 | 135 | 3. Open your browser and navigate to http://localhost 136 | 137 | ## 🪟 Test Setup in Windows using IIS 138 | With IIS now fully supporting PHP, this example can be run using the included web.config. The web.config has a rewrite rule, similar to the .htaccess rewrite rule, but specifically for IIS. The rewrite rule will send all incoming requests to index.php in your root. The rest is done by the simple php router. 139 | ### Setup 140 | _This setup tutorial assumes you have the knowledge to create sites in IIS and set up bindings for http/https and custom DNS. If you need more information, this [article](https://docs.microsoft.com/en-us/iis/get-started/getting-started-with-iis/create-a-web-site) will help you with that part._ 141 | 1. If you haven't done so yet, install php on windows. This article [Install IIS and PHP | Microsoft Docs ](https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php) will guide you to install the required php dependencies on your windows machine. 142 | 2. In IIS Manager, create a site and point the physical location to root of the simplePHPRouter folder. It is recommended you connect to the the physical location with an account that has "Read/Write" rights to that folder. 143 | 3. (Optional) Create a DNS entry in your hosts file pointing 127.0.0.1 to the domain name you have used to set up the site. 144 | 4. Browse to the newly created website and the sample site should display now. 145 | 146 | ## ✅ Todo 147 | * Create demo configuration for nginx 148 | 149 | ## 📃 License 150 | This project is licensed under the MIT License. See LICENSE for further information. 151 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "steampixel/simple-php-router", 3 | "description": "This is a simple and small PHP router that can handle the whole url routing for your project.", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Steampixel", 9 | "email": "info@steampixel.de", 10 | "homepage": "https://steampixel.de/" 11 | }, 12 | { 13 | "name": "Maximilian Götz", 14 | "email": "contact@maxbits.net", 15 | "homepage": "https://www.maxbits.net/" 16 | } 17 | ], 18 | "minimum-stability": "dev", 19 | "require": {}, 20 | "autoload": { 21 | "psr-0": { 22 | "Steampixel": "src/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docker/image-php-7.2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.2-apache 2 | 3 | # Enable rewrite 4 | RUN a2enmod rewrite 5 | 6 | # Install composer 7 | # https://www.hostinger.com/tutorials/how-to-install-composer 8 | RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 9 | RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer 10 | RUN php -r "unlink('composer-setup.php');" 11 | 12 | # Update 13 | RUN apt-get update -y 14 | 15 | # Install git 16 | RUN apt-get install git -y 17 | 18 | # Install zip 19 | RUN apt-get install zip -y 20 | -------------------------------------------------------------------------------- /docker/image-php-7.4.1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4.1-apache 2 | 3 | RUN a2enmod rewrite 4 | 5 | # Install composer 6 | # https://www.hostinger.com/tutorials/how-to-install-composer 7 | RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 8 | RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer 9 | RUN php -r "unlink('composer-setup.php');" 10 | 11 | # Update 12 | RUN apt-get update -y 13 | 14 | # Install git 15 | RUN apt-get install git -y 16 | 17 | # Install zip 18 | RUN apt-get install zip -y 19 | -------------------------------------------------------------------------------- /include-example.php: -------------------------------------------------------------------------------- 1 | 2 |

Blog

3 | 4 |
5 | Hey! Read my new blog post with this cool slug: "" 6 |
7 | 8 |

9 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 10 |

11 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 'Article 1', 'article-2' => 'Article 2', 'article-3' => 'Article 3', 'article-4' => 'Article 4', 'article-5' => 'Article 5']; 19 | 20 | // This function just renders a simple navigation 21 | function navi() { 22 | global $slugs; 23 | $navi = ' 24 | Navigation: 25 | '; 55 | echo $navi; 56 | } 57 | 58 | // Add base route (startpage) 59 | Route::add('/', function() { 60 | navi(); 61 | echo 'Welcome :-)'; 62 | }); 63 | 64 | // Another base route example 65 | Route::add('/index.php', function() { 66 | navi(); 67 | echo 'You are not really on index.php ;-)'; 68 | }); 69 | 70 | // Simple test route that simulates static html file 71 | Route::add('/test.html', function() { 72 | navi(); 73 | echo 'Hello from test.html'; 74 | }); 75 | 76 | // This example shows how to include files and how to push data to them 77 | // Hint: If you want to use this router for building websites with different nice looking HTML pages please visit https://github.com/steampixel/simplePHPPages 78 | // There you will find a complete website example that bases on this router including themes, pages, layouts and content blocks. 79 | Route::add('/blog/([a-z-0-9-]*)', function($slug) { 80 | navi(); 81 | include('include-example.php'); 82 | }); 83 | 84 | // This route is for debugging only 85 | // It simply prints out some php infos 86 | // Do not use this route on production systems! 87 | Route::add('/phpinfo', function() { 88 | navi(); 89 | phpinfo(); 90 | }); 91 | 92 | // Get route example 93 | Route::add('/contact-form', function() { 94 | navi(); 95 | echo '
'; 96 | }, 'get'); 97 | 98 | // Post route example 99 | Route::add('/contact-form', function() { 100 | navi(); 101 | echo 'Hey! The form has been sent:
'; 102 | print_r($_POST); 103 | }, 'post'); 104 | 105 | // Get and Post route example 106 | Route::add('/get-post-sample', function() { 107 | navi(); 108 | echo 'You can GET this page and also POST this form back to it'; 109 | echo '
'; 110 | if (isset($_POST['input'])) { 111 | echo 'I also received a POST with this data:
'; 112 | print_r($_POST); 113 | } 114 | }, ['get','post']); 115 | 116 | // Route with regexp parameter 117 | // Be aware that (.*) will match / (slash) too. For example: /user/foo/bar/edit 118 | // Also users could inject SQL statements or other untrusted data if you use (.*) 119 | // You should better use a saver expression like /user/([0-9]*)/edit or /user/([A-Za-z]*)/edit 120 | Route::add('/user/(.*)/edit', function($id) { 121 | navi(); 122 | echo 'Edit user with id '.$id.'
'; 123 | }); 124 | 125 | // Accept only numbers as parameter. Other characters will result in a 404 error 126 | Route::add('/foo/([0-9]*)/bar', function($var1) { 127 | navi(); 128 | echo $var1.' is a great number!'; 129 | }); 130 | 131 | // Crazy route with parameters 132 | Route::add('/(.*)/(.*)/(.*)/(.*)', function($var1,$var2,$var3,$var4) { 133 | navi(); 134 | echo 'This is the first match: '.$var1.' / '.$var2.' / '.$var3.' / '.$var4.'
'; 135 | }); 136 | 137 | // Long route example 138 | // By default this route gets never triggered because the route before matches too 139 | Route::add('/foo/bar/foo/bar', function() { 140 | echo 'This is the second match (This route should only work in multi match mode)
'; 141 | }); 142 | 143 | // Route with non english letters: german example 144 | Route::add('/äöü', function() { 145 | navi(); 146 | echo 'German example. Non english letters should work too
'; 147 | }); 148 | 149 | // Route with non english letters: arabic example 150 | Route::add('/الرقص-العربي', function() { 151 | navi(); 152 | echo 'Arabic example. Non english letters should work too
'; 153 | }); 154 | 155 | // Auto generate dynamic routes from a database or from another source 156 | // For this example we will just use a predefined array 157 | foreach($slugs as $slug => $entry) { 158 | Route::add('/my-blog-articles/'.$slug, function() use($entry) { 159 | navi(); 160 | echo 'You are here: '.$entry; 161 | }); 162 | } 163 | 164 | // Use variables from global scope 165 | // You can use for example use() to inject variables to local scope 166 | // You can use global to register the variable in local scope 167 | $foo = 'foo'; 168 | $bar = 'bar'; 169 | Route::add('/global/([a-z-0-9-]*)', function($param) use($foo) { 170 | global $bar; 171 | navi(); 172 | echo 'The param is '.$param.'
'; 173 | echo 'Foo is '.$foo.'
'; 174 | echo 'Bar is '.$bar.'
'; 175 | }); 176 | 177 | // Return example 178 | // Returned data gets printed 179 | Route::add('/return', function() { 180 | navi(); 181 | return 'This text gets returned by the add method'; 182 | }); 183 | 184 | // Arrow function example 185 | // Note: You can use this example only if you are on PHP 7.4 or higher 186 | // $bar = 'bar'; 187 | // Route::add('/arrow/([a-z-0-9-]*)', fn($foo) => navi().'This is a working arrow function example.
Parameter: '.$foo. '
Variable from global scope: '.$bar ); 188 | 189 | // Trailing slash example 190 | Route::add('/aTrailingSlashDoesNotMatter', function() { 191 | navi(); 192 | echo 'a trailing slash does not matter
'; 193 | }); 194 | 195 | // Case example 196 | Route::add('/theCaseDoesNotMatter',function() { 197 | navi(); 198 | echo 'the case does not matter
'; 199 | }); 200 | 201 | // 405 test 202 | Route::add('/this-route-is-defined', function() { 203 | navi(); 204 | echo 'You need to patch this route to see this content'; 205 | }, 'patch'); 206 | 207 | // Add a 404 not found route 208 | Route::pathNotFound(function($path) { 209 | // Do not forget to send a status header back to the client 210 | // The router will not send any headers by default 211 | // So you will have the full flexibility to handle this case 212 | header('HTTP/1.0 404 Not Found'); 213 | navi(); 214 | echo 'Error 404 :-(
'; 215 | echo 'The requested path "'.$path.'" was not found!'; 216 | }); 217 | 218 | // Add a 405 method not allowed route 219 | Route::methodNotAllowed(function($path, $method) { 220 | // Do not forget to send a status header back to the client 221 | // The router will not send any headers by default 222 | // So you will have the full flexibility to handle this case 223 | header('HTTP/1.0 405 Method Not Allowed'); 224 | navi(); 225 | echo 'Error 405 :-(
'; 226 | echo 'The requested path "'.$path.'" exists. But the request method "'.$method.'" is not allowed on this path!'; 227 | }); 228 | 229 | // Return all known routes 230 | Route::add('/known-routes', function() { 231 | navi(); 232 | $routes = Route::getAll(); 233 | echo ''; 238 | }); 239 | 240 | // Run the Router with the given Basepath 241 | Route::run(BASEPATH); 242 | 243 | // Enable case sensitive mode, trailing slashes and multi match mode by setting the params to true 244 | // Route::run(BASEPATH, true, true, true); 245 | -------------------------------------------------------------------------------- /src/Steampixel/Route.php: -------------------------------------------------------------------------------- 1 | $expression, 21 | 'function' => $function, 22 | 'method' => $method 23 | )); 24 | } 25 | 26 | public static function getAll(){ 27 | return self::$routes; 28 | } 29 | 30 | public static function pathNotFound($function) { 31 | self::$pathNotFound = $function; 32 | } 33 | 34 | public static function methodNotAllowed($function) { 35 | self::$methodNotAllowed = $function; 36 | } 37 | 38 | public static function run($basepath = '', $case_matters = false, $trailing_slash_matters = false, $multimatch = false) { 39 | 40 | // The basepath never needs a trailing slash 41 | // Because the trailing slash will be added using the route expressions 42 | $basepath = rtrim($basepath, '/'); 43 | 44 | // Parse current URL 45 | $parsed_url = parse_url($_SERVER['REQUEST_URI']); 46 | 47 | $path = '/'; 48 | 49 | // If there is a path available 50 | if (isset($parsed_url['path'])) { 51 | // If the trailing slash matters 52 | if ($trailing_slash_matters) { 53 | $path = $parsed_url['path']; 54 | } else { 55 | // If the path is not equal to the base path (including a trailing slash) 56 | if($basepath.'/'!=$parsed_url['path']) { 57 | // Cut the trailing slash away because it does not matters 58 | $path = rtrim($parsed_url['path'], '/'); 59 | } else { 60 | $path = $parsed_url['path']; 61 | } 62 | } 63 | } 64 | 65 | $path = urldecode($path); 66 | 67 | // Get current request method 68 | $method = $_SERVER['REQUEST_METHOD']; 69 | 70 | $path_match_found = false; 71 | 72 | $route_match_found = false; 73 | 74 | foreach (self::$routes as $route) { 75 | 76 | // If the method matches check the path 77 | 78 | // Add basepath to matching string 79 | if ($basepath != '' && $basepath != '/') { 80 | $route['expression'] = '('.$basepath.')'.$route['expression']; 81 | } 82 | 83 | // Add 'find string start' automatically 84 | $route['expression'] = '^'.$route['expression']; 85 | 86 | // Add 'find string end' automatically 87 | $route['expression'] = $route['expression'].'$'; 88 | 89 | // Check path match 90 | if (preg_match('#'.$route['expression'].'#'.($case_matters ? '' : 'i').'u', $path, $matches)) { 91 | $path_match_found = true; 92 | 93 | // Cast allowed method to array if it's not one already, then run through all methods 94 | foreach ((array)$route['method'] as $allowedMethod) { 95 | // Check method match 96 | if (strtolower($method) == strtolower($allowedMethod)) { 97 | array_shift($matches); // Always remove first element. This contains the whole string 98 | 99 | if ($basepath != '' && $basepath != '/') { 100 | array_shift($matches); // Remove basepath 101 | } 102 | 103 | if($return_value = call_user_func_array($route['function'], $matches)) { 104 | echo $return_value; 105 | } 106 | 107 | $route_match_found = true; 108 | 109 | // Do not check other routes 110 | break; 111 | } 112 | } 113 | } 114 | 115 | // Break the loop if the first found route is a match 116 | if($route_match_found&&!$multimatch) { 117 | break; 118 | } 119 | 120 | } 121 | 122 | // No matching route was found 123 | if (!$route_match_found) { 124 | // But a matching path exists 125 | if ($path_match_found) { 126 | if (self::$methodNotAllowed) { 127 | if($return_value = call_user_func_array(self::$methodNotAllowed, Array($path,$method))){ 128 | echo $return_value; 129 | } 130 | } 131 | } else { 132 | if (self::$pathNotFound) { 133 | if($return_value = call_user_func_array(self::$pathNotFound, Array($path))){ 134 | echo $return_value; 135 | } 136 | } 137 | } 138 | 139 | } 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------