I want to add Middleware to my Slim project that checks the ip of the user before allowing them access.
My middleware class:
<?php
namespace App\Middleware;
Class IpFilter
{
protected $request_ip;
protected $allowed_ip;
public function __construct($allowedip = array('127.0.0.1'))
{
$this->request_ip = app()->request()->getIp();
$this->allowed_ip = $allowedip;
}
public function call()
{
$checkit = checkIp();
$this->next->call();
}
protected function checkIp()
{
if (!in_array($this->request_ip, $this->allowed_ip))
$app->halt(403);
}
}
My Bootstrap index.php:
<?php
// To help the built-in PHP dev server, check if the request was actually for
// something which should probably be served as a static file
if (PHP_SAPI === 'cli-server' && $_SERVER['SCRIPT_FILENAME'] !== __FILE__) {
return false;
}
require __DIR__ . '/../vendor/autoload.php';
require '../app/middleware/ipfilter.php';
// Instantiate the app
$settings = require __DIR__ . '/../app/settings.php';
$app = new \Slim\App($settings);
$app->get('/test', function() {
echo "You look like you're from around here";
});
// Set up dependencies
require __DIR__ . '/../app/dependencies.php';
// Register middleware
require __DIR__ . '/../app/middleware.php';
// Register routes
require __DIR__ . '/../app/routes.php';
$app->add(new IpFilter);
// Run
$app->run();
I am using a slim skeleton project for my project setup. I get the following error when I run this code.
Fatal error: Class 'IpFilter' not found in
/Applications/XAMPP/xamppfiles/htdocs/slimtest/my-app/public/index.php
on line 34
I still don't properly understand how to add custom classes for middleware in slim. I've seen several tutorials that just make the class and use $app->add('new class) to add the middleware but I can't figure it out. Is there a file I need to update and I am just missing it?
It's been a long weekend with slim and not a lot of resources out there so any help would be greatly appreciated.
UPDATE:
When I remove the namespace App\Middleware from ipfilter.php I don't get the same error. This time I get
Fatal error: Call to undefined method IpFilter::request() in /Applications/XAMPP/xamppfiles/htdocs/slimtest/my-app/app/middleware/ipfilter.php on line 15
Which I understand why but I thought it might help troubleshoot and get to the root of the problem.
Okay, Finally got it to work.
Index.php
<?php
// To help the built-in PHP dev server, check if the request was actually for
// something which should probably be served as a static file
if (PHP_SAPI === 'cli-server' && $_SERVER['SCRIPT_FILENAME'] !== __FILE__) {
return false;
}
use App\Middleware\IpFilter;
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../app/middleware/ipfilter.php';
// Instantiate the app
$settings = require __DIR__ . '/../app/settings.php';
$app = new \Slim\App($settings);
$app->get('/test', function() {
echo "You look like you're from around here";
});
// Set up dependencies
require __DIR__ . '/../app/dependencies.php';
// Register middleware
require __DIR__ . '/../app/middleware.php';
// Register routes
require __DIR__ . '/../app/routes.php';
$app->add(new IpFilter);
// Run
$app->run();
ipfilter.php
<?php
namespace App\Middleware;
Class IpFilter
{
private $whitelist = arrray('127.0.0.1')
protected $request_ip;
public function __invoke($request, $response, $next)
{
$request_ip = $request->getAttribute('ip_address');
return $next($request, $response);
}
public function call()
{
$checkit = checkIp();
$this->next->call();
}
protected function checkIp()
{
if (!in_array($this->request_ip, $this->whitelist)
$app->halt(403);
}
}
KEY: Using App\Middleware\Ipfilter in the index.php. I though using require to add the class would be enough but apparently no.
Shout out to codecourse.com, really helped.
Related
I'm working on a project whereby I have the following file structure:
index.php
|---lib
|--|lib|type|class_name.php
|--|lib|size|example_class.php
I'd like to auto load the classes, class_name and example_class (named the same as the PHP classes), so that in index.php the classes would already be instantiated so I could do:
$class_name->getPrivateParam('name');
I've had a look on the net but can't quite find the right answer - can anyone help me out?
EDIT
Thanks for the replies. Let me expand on my scenario. I'm trying to write a WordPress plugin that can be dropped into a project and additional functionality added by dropping a class into a folder 'functionality' for example, inside the plugin. There will never be 1000 classes, at a push maybe 10?
I could write a method to iterate through the folder structure of the 'lib' folder, including every class then assigning it to a variable (of the class name), but didn't think that was a very efficient way to do it but it perhaps seems that's the best way to achieve what I need?
Please, if you need to autoload classes - use the namespaces and class names conventions with SPL autoload, it will save your time for refactoring.
And of course, you will need to instantiate every class as an object.
Thank you.
Like in this thread:
PHP Autoloading in Namespaces
But if you want a complex workaround, please take a look at Symfony's autoload class:
https://github.com/symfony/ClassLoader/blob/master/ClassLoader.php
Or like this (I did it in one of my projects):
<?
spl_autoload_register(function($className)
{
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=CORE_PATH."/classes/".(empty($namespace)?"":$namespace."/")."{$className}.class.php";
include_once($class);
});
?>
and then you can instantiate your class like this:
<?
$example=new NS1\NS2\ExampleClass($exampleConstructParam);
?>
and this is your class (found in /NS1/NS2/ExampleClass.class.php):
<?
namespace NS1\NS2
{
class Symbols extends \DB\Table
{
public function __construct($param)
{
echo "hello!";
}
}
}
?>
If you have an access to the command line, you can try it with composer in the classMap section with something like this:
{
"autoload": {
"classmap": ["yourpath/", "anotherpath/"]
}
}
then you have a wordpress plugin to enable composer in the wordpress cli : http://wordpress.org/plugins/composer/
function __autoload($class_name) {
$class_name = strtolower($class_name);
$path = "{$class_name}.php";
if (file_exists($path)) {
require_once($path);
} else {
die("The file {$class_name}.php could not be found!");
}
}
UPDATE:
__autoload() is deprecated as of PHP 7.2
http://php.net/manual/de/function.spl-autoload-register.php
spl_autoload_register(function ($class) {
#require_once('lib/type/' . $class . '.php');
#require_once('lib/size/' . $class . '.php');
});
I have an example here that I use for autoloading and initiliazing.
Basically a better version of spl_autoload_register since it only tries to require the class file whenever you initializes the class.
Here it automatically gets every file inside your class folder, requires the files and initializes it. All you have to do, is name the class the same as the file.
index.php
<?php
require_once __DIR__ . '/app/autoload.php';
$loader = new Loader(false);
User::dump(['hello' => 'test']);
autoload.php
<?php
class Loader
{
public static $library;
protected static $classPath = __DIR__ . "/classes/";
protected static $interfacePath = __DIR__ . "/classes/interfaces/";
public function __construct($requireInterface = true)
{
if(!isset(static::$library)) {
// Get all files inside the class folder
foreach(array_map('basename', glob(static::$classPath . "*.php", GLOB_BRACE)) as $classExt) {
// Make sure the class is not already declared
if(!in_array($classExt, get_declared_classes())) {
// Get rid of php extension easily without pathinfo
$classNoExt = substr($classExt, 0, -4);
$file = static::$path . $classExt;
if($requireInterface) {
// Get interface file
$interface = static::$interfacePath . $classExt;
// Check if interface file exists
if(!file_exists($interface)) {
// Throw exception
die("Unable to load interface file: " . $interface);
}
// Require interface
require_once $interface;
//Check if interface is set
if(!interface_exists("Interface" . $classNoExt)) {
// Throw exception
die("Unable to find interface: " . $interface);
}
}
// Require class
require_once $file;
// Check if class file exists
if(class_exists($classNoExt)) {
// Set class // class.container.php
static::$library[$classNoExt] = new $classNoExt();
} else {
// Throw error
die("Unable to load class: " . $classNoExt);
}
}
}
}
}
/*public function get($class)
{
return (in_array($class, get_declared_classes()) ? static::$library[$class] : die("Class <b>{$class}</b> doesn't exist."));
}*/
}
You can easily manage with a bit of coding, to require classes in different folders too. Hopefully this can be of some use to you.
You can specify a namespaces-friendly autoloading using this autoloader.
<?php
spl_autoload_register(function($className) {
$file = __DIR__ . '\\' . $className . '.php';
$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
if (file_exists($file)) {
include $file;
}
});
Make sure that you specify the class file's location corretly.
Source
spl_autoload_register(function ($class_name) {
$iterator = new DirectoryIterator(dirname(__FILE__));
$files = $iterator->getPath()."/classes/".$class_name.".class.php";
if (file_exists($files)) {
include($files);
} else {
die("Warning:The file {$files}.class.php could not be found!");
}
});
do this in a file and called it anything like (mr_load.php)
this were u put all your classes
spl_autoload_register(function($class){
$path = '\Applicaton/classes/';
$extension = '.php';
$fileName = $path.$class.$extension;
include $_SERVER['DOCUMENT_ROOT'].$fileName;
})
;
then create another file and include mr_load.php; $load_class = new BusStop(); $load_class->method()
When I use require_once or include_once to include a file it does not work, while when I use require or include it works fine.
public function ParseURL() {
require_once (APP_PATH . "config/config.php");
$this->url_as_parts = explode('/', $this->url);
$class = isset($this->url_as_parts[0]) ? $this->url_as_parts[0] : $config['default_controller'];
$method = isset($this->url_as_parts[1]) ? $this->url_as_parts[1] : "index";
$parms = isset($this->url_as_parts[2]) ? $this->url_as_parts[2] : "";
if (!class_exists($class)) {
trigger_error("The class {$class} not exists <br/>");
exit;
}
$controller = Object::get($class);
if (!method_exists($controller, $method)) {
header('HTTP/1.0 404 Not Found');
include(SYSTEM_PATH . "languages/" . $config['system_language'] . "/errors/404_not_found.html");
exit;
}
if (empty($parms)) {
$controller->{$method}();
} else {
$parms_array = array_slice($this->url_as_parts, 2);
call_user_func_array(array($controller, $method), $parms_array);
}
}
The following line does not produce an error and the path is correct
require_once (APP_PATH . "config/config.php"); but I cant access $config['system_language'] which is inside the file config.php.
Note that when I change the require_once to require or include, everything is OK.
As comes from require_once description - file required only once
Any other require_once of this file will not work.
And you obviously run you function ParseURL more than once. So, your require_once not working on second and consecutive calls.
So, you can use just require or, as I see this is part of a class, create, for example, a wrapper method which will assign config data to your class variable. I.e:
public function getConfig()
{
$this->config = require_once('FILE');
}
In this case your config file should return array or object of config variables.
Can it be that something else includes config/config.php, and then redefines/overwrites the variable $config?
The difference between require_once() and is regular counterparts (include() etc) is that require_once() only includes (and executes, if applicable) something if it hasn't been included before.
This might be because you are already loading config/config.php somewhere before in your code.
Calling require_once(APP_PATH . "config/config.php"); checks that the file config.php already is included and hence does not include it inside that function.
That is the reason your function does not have access to $config variable.
Hope that helps.
I am writing a light weight php mvc framework for my portfolio and as a barebone setup for my future developments. I am stuck now because I am trying to use PSR-4 autoloader through composer. I understand the concept of PSR-4 etc but I am wondering how should I handle the routing.
My folder structure is:
--|-Root---
index.php
composer.json
-----|-application------
--------|-controller----
--------|-model---------
--------|-core----------
-----------|-baseController.php
-----------|-Application.php
-----------|-baseView.php
-----------|-baseModel.php
--------|-view----------
--------|-config
-----------|-config.php
-----|-vendor------
--------|-autoload.php
-----|-assets------
I am fairly good with php but writing an own mvc framework is a hard challange, even bigger because I never used PSR standards before.
Now my questions are:
Should I use router at all?
If yes then what pattern should I use to acomplish that.
So, in my index.php I define all constants to store directories like ROOT, APP, VENDOR. I then load vendor/autoload.php generated from my composer.json. After autoload.php I load and initiate my config by calling this code:
if(is_readable(APP . 'config/config.php'))
{
require APP . 'config/config.php';
//Initiate config
new AppWorld\Confyy\config();
}
else
{
throw new Exception('config.php file was not found in' . APP . 'config');
}
After config I setup application environment and then I initiate my app by calling:
// Start the application
new AppWorld\FrostHeart\Application();
Then my baseController is very very thin:
<?php
namespace AppWorld\FrostHeart;
use AppWorld\FrostHeart\baseView as View;
abstract class baseController {
public $currentView;
public function __construct() {
//Initiate new View object and set currentView to this object.
$this->currentView = new View();
}
}
And this is my baseView.php:
<?php
namespace AppWorld\FrostHeart;
class baseView {
public function show($file, $data = null, $showTemplate = 1) {
if($data != null) {
foreach($data as $key => $value) {
$this->{$key} = $value;
}
}
if($showTemplate === 1) {
require VIEW_DIR . header . ".php";
require VIEW_DIR . $file . ".php";
require VIEW_DIR . footer . ".php";
}
elseif($showTemplate === 0)
{
require VIEW_DIR . $file . ".php";
}
}
}
my config.php:
<?php
namespace AppWorld\Confyy;
class config {
public function __construct() {
$this->application();
$this->database();
}
public function application() {
/**
* Define application environment, defaults are:
*
* development
* live
*
*/
define("ENVIRONMENT", "development");
//Define base url
define("BASE_URL", "http://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
//Define default controller
define("DEFAULT_CONTROLLER", "landing");
//Define default method
define("DEFAULT_METHOD", "index");
//Define controllers directory
define("CONTROLLER_DIR", APP . "controller/");
//Define views directory
define("VIEW_DIR", APP . "view/");
}
public function database() {
//Define DB Server
define("DB_SERVER", "localhost");
//Define DB User
define("DB_USER", "root");
//Define DB Password
define("DB_PASSWORD", "");
//Define DB Name
define("DB_NAME", "test");
}
}
and at last my composer.json autoload section:
"autoload": {
"psr-4":{
"AppWorld\\": "application",
"AppWorld\\Conffy\\": "application/config",
"AppWorld\\FrostHeart\\": "application/core",
"AppWorld\\Controls\\": "application/controller"
}
}
So how should I implement a router that routes the URL requests and load correct files?
Thanks!
I'm working on a project whereby I have the following file structure:
index.php
|---lib
|--|lib|type|class_name.php
|--|lib|size|example_class.php
I'd like to auto load the classes, class_name and example_class (named the same as the PHP classes), so that in index.php the classes would already be instantiated so I could do:
$class_name->getPrivateParam('name');
I've had a look on the net but can't quite find the right answer - can anyone help me out?
EDIT
Thanks for the replies. Let me expand on my scenario. I'm trying to write a WordPress plugin that can be dropped into a project and additional functionality added by dropping a class into a folder 'functionality' for example, inside the plugin. There will never be 1000 classes, at a push maybe 10?
I could write a method to iterate through the folder structure of the 'lib' folder, including every class then assigning it to a variable (of the class name), but didn't think that was a very efficient way to do it but it perhaps seems that's the best way to achieve what I need?
Please, if you need to autoload classes - use the namespaces and class names conventions with SPL autoload, it will save your time for refactoring.
And of course, you will need to instantiate every class as an object.
Thank you.
Like in this thread:
PHP Autoloading in Namespaces
But if you want a complex workaround, please take a look at Symfony's autoload class:
https://github.com/symfony/ClassLoader/blob/master/ClassLoader.php
Or like this (I did it in one of my projects):
<?
spl_autoload_register(function($className)
{
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=CORE_PATH."/classes/".(empty($namespace)?"":$namespace."/")."{$className}.class.php";
include_once($class);
});
?>
and then you can instantiate your class like this:
<?
$example=new NS1\NS2\ExampleClass($exampleConstructParam);
?>
and this is your class (found in /NS1/NS2/ExampleClass.class.php):
<?
namespace NS1\NS2
{
class Symbols extends \DB\Table
{
public function __construct($param)
{
echo "hello!";
}
}
}
?>
If you have an access to the command line, you can try it with composer in the classMap section with something like this:
{
"autoload": {
"classmap": ["yourpath/", "anotherpath/"]
}
}
then you have a wordpress plugin to enable composer in the wordpress cli : http://wordpress.org/plugins/composer/
function __autoload($class_name) {
$class_name = strtolower($class_name);
$path = "{$class_name}.php";
if (file_exists($path)) {
require_once($path);
} else {
die("The file {$class_name}.php could not be found!");
}
}
UPDATE:
__autoload() is deprecated as of PHP 7.2
http://php.net/manual/de/function.spl-autoload-register.php
spl_autoload_register(function ($class) {
#require_once('lib/type/' . $class . '.php');
#require_once('lib/size/' . $class . '.php');
});
I have an example here that I use for autoloading and initiliazing.
Basically a better version of spl_autoload_register since it only tries to require the class file whenever you initializes the class.
Here it automatically gets every file inside your class folder, requires the files and initializes it. All you have to do, is name the class the same as the file.
index.php
<?php
require_once __DIR__ . '/app/autoload.php';
$loader = new Loader(false);
User::dump(['hello' => 'test']);
autoload.php
<?php
class Loader
{
public static $library;
protected static $classPath = __DIR__ . "/classes/";
protected static $interfacePath = __DIR__ . "/classes/interfaces/";
public function __construct($requireInterface = true)
{
if(!isset(static::$library)) {
// Get all files inside the class folder
foreach(array_map('basename', glob(static::$classPath . "*.php", GLOB_BRACE)) as $classExt) {
// Make sure the class is not already declared
if(!in_array($classExt, get_declared_classes())) {
// Get rid of php extension easily without pathinfo
$classNoExt = substr($classExt, 0, -4);
$file = static::$path . $classExt;
if($requireInterface) {
// Get interface file
$interface = static::$interfacePath . $classExt;
// Check if interface file exists
if(!file_exists($interface)) {
// Throw exception
die("Unable to load interface file: " . $interface);
}
// Require interface
require_once $interface;
//Check if interface is set
if(!interface_exists("Interface" . $classNoExt)) {
// Throw exception
die("Unable to find interface: " . $interface);
}
}
// Require class
require_once $file;
// Check if class file exists
if(class_exists($classNoExt)) {
// Set class // class.container.php
static::$library[$classNoExt] = new $classNoExt();
} else {
// Throw error
die("Unable to load class: " . $classNoExt);
}
}
}
}
}
/*public function get($class)
{
return (in_array($class, get_declared_classes()) ? static::$library[$class] : die("Class <b>{$class}</b> doesn't exist."));
}*/
}
You can easily manage with a bit of coding, to require classes in different folders too. Hopefully this can be of some use to you.
You can specify a namespaces-friendly autoloading using this autoloader.
<?php
spl_autoload_register(function($className) {
$file = __DIR__ . '\\' . $className . '.php';
$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
if (file_exists($file)) {
include $file;
}
});
Make sure that you specify the class file's location corretly.
Source
spl_autoload_register(function ($class_name) {
$iterator = new DirectoryIterator(dirname(__FILE__));
$files = $iterator->getPath()."/classes/".$class_name.".class.php";
if (file_exists($files)) {
include($files);
} else {
die("Warning:The file {$files}.class.php could not be found!");
}
});
do this in a file and called it anything like (mr_load.php)
this were u put all your classes
spl_autoload_register(function($class){
$path = '\Applicaton/classes/';
$extension = '.php';
$fileName = $path.$class.$extension;
include $_SERVER['DOCUMENT_ROOT'].$fileName;
})
;
then create another file and include mr_load.php; $load_class = new BusStop(); $load_class->method()
I'm trying to write my own little MVC framework for my projects, something I can just drop in and get up and running quickly, mostly for learning purposes. Every request gets routed through index.php which has this code:
<?php
// Run application
require 'application/app.php';
$app = new App();
$app->run();
This is my application class:
<?php
class App {
public function run() {
// Determine request path
$path = $_SERVER['REQUEST_URI'];
// Load routes
require_once 'routes.php';
// Match this request to a route
if(isset(Routes::$routes[$path])) {
} else {
// Use default route
$controller = Routes::$routes['/'][0];
$action = Routes::$routes['/'][1];
}
// Check if controller exists
if(file_exists('controllers/' . $controller . '.php')) {
// Include and instantiate controller
require_once 'controllers/' . $controller . '.php';
$controller = new $controller . 'Controller';
// Run method for this route
if(method_exists($controller, $action)) {
return $controller->$action();
} else {
die('Method ' . $action . ' missing in controller ' . $controller);
}
} else {
die('Controller ' . $controller . 'Controller missing');
}
}
}
and this is my routes file:
<?php
class Routes {
public static $routes = array(
'/' => array('Pages', 'home')
);
}
When I try loading the root directory (/) I get this:
Controller PagesController missing
For some reason the file_exists function can't see my controller. This is my directory structure:
/application
/controllers
Pages.php
/models
/views
app.php
routes.php
So by using if(file_exists('controllers/' . $controller . '.php')) from app.php, it should be able to find controllers/Pages.php, but it can't.
Anyone know how I can fix this?
You are using relative path's for your includes. As your application grows, it will become a nightmare.
I suggest you
write a autoloader class, that deals with including files. Use some mapping mechanism that translates namespaces / class names into path's.
use absolute paths. See the adjusted code below.
Example:
// Run application
define('ROOT', dirname(__FILE__) );
require ROOT . '/application/app.php';
$app = new App();
$app->run();
And later:
// Check if controller exists
if(file_exists(ROOT . '/application/controllers/' . $controller . '.php')) {
// Include and instantiate controller
require_once ROOT. '/application/controllers/' . $controller . '.php';
$controller = new $controller . 'Controller';