I have been experimenting with Slim for a few days now and there is a lot that I like. However, there is one thing that nags me - when Slim is used to build a REST API it insists on putting everything into one single .php file - or even worse, a load of anonymous functions (one for each exposed REST method).
This works, that is not the issue. However, does it not mean that when used for building any but the most trivial of APIs you are imposing an unnecessary burden on the server by getting it to load and parse a potentially really big PHP file when only a tiny percentage of its code is relevant?
If yes, then it begs the next question - I am a newbie to micro frameworks - is there a micro framework that does things in a way that avoids this issue?
I'm unsure whether you are looking for a framework for a complete website or for an api alone. If latter I can recommend restler, which is a very simple, OO and stable package for developing API's.
On the other hand Laravel has built in resource controllers to ease the api development, it also has a very fast growing community.
If you're looking for both a website framework ánd an api framework in one, my guess is it will be very difficult combining that into one micro framework. Laravel/Symfony and other frameworks will eventually be needed especially if you expect growth in the project.
I made a REST API using AltoRouter:
http://altorouter.com/
I like the fact that after one route matches I can choose how to make the call, so I can point to the folder where I have all the REST controllers divided in several well organized files.
http://altorouter.com/usage/processing-requests.html
An example:
function rest_data($data, $format)
{
header("Cache-Control: no-cache, must-revalidate");
header("Expires: 0");
header('Content-Type: ' . $format);
if (is_object($data) && method_exists($data, '__keepOut'))
{
$data = clone $data;
foreach ($data->__keepOut() as $prop)
{
unset($data->$prop);
}
}
$options = 0;
$json=json_encode($data, $options);
echo $json;
}
$router = new AltoRouter();
$router->setBasePath('/rest');
$router->map('GET|POST','/', 'home#index', 'home');
$router->map('GET','/sample_users/all', 'sample_user#all', 'sample_users_get');
// match current request
$match = $router->match();
if($match && $match['name']=='home')
{
// write some intro
exit();
}
if($match)
{
$target=$match['target'];
list($class_name,$function_name) = explode("#",$target);
require($conf["src.path"].'/rest/'.$class_name.'.php');
foreach($_GET as $k=>$v) $match['params'][$k] = $v;
$controller = new $class_name;
$res = $controller->$function_name($match['params']);
rest_data($res,RestFormat::JSON);
}
If you are not so keen on the Slim PHP framework might I suggest something like Symfony ? Personally I like the way Slim works, and suits what I need to build right down to a T - however I can see your frustration with creating a RESTful solution. Symfony on the other hand breaks things up a little more so you have less fat controllers.
If Symfony isn't right for you I guess you could pull out a heavyweight ike Laravel?
Related
I'd like to be able to manage WebDAV directories (and even reimplement the way files are read and written) in Symfony. To do so I found SabreDAV, which is itself a framework with all the basic classes required.
My problem is, while it's quite easy to get a WebDAV server running using SabreDAV alone, it doesn't work that well when I use Symfony.
Without Symfony, it boils down to:
$server = new DAV\Server($rootDirectory);
$server->exec();
And I can use cadaver to access my directory.
More here: http://code.google.com/p/sabredav/wiki/GettingStarted
I tried to do the same in my controller with Symfony, using:
return new Response($server->exec());
but for some reason cadaver doesn't have access to the folder.
I guess I'm missing something about the way responses work in Symfony, but what? SabreDAV uses its own system of http requests and responses, but if (as I presume) Symfony doesn't mess with superglobal variables such as $_SERVER, this shouldn't be an issue.
About requests and responses in Symfony: http://symfony.com/doc/current/book/http_fundamentals.html#requests-and-responses-in-symfony
Here's what I did; it's a bit slow and there must be a better way, but I'll make do with that for the moment:
Controller.php :
$path=(__DIR__.'/../../../../web/public/');
$path=realpath($path);
$publicDir= new \MyClasses\FS\MyDirectory($path);
$server = new \Sabre\DAV\Server($publicDir);
$server->setBaseUri('/Symfony/web/app_dev.php/');
{
$SyRequest = Request::createFromGlobals();
$_server=$SyRequest->server->all();
$_post=$SyRequest->request->all();
}
{
$SaRequest=new \MyClasses\HTTP\Request($_server,$_post);
$resourceStream=false;
$SaRequest->setBody($SyRequest->getContent($resourceStream),$resourceStream);
}
{
$server->httpRequest=$SaRequest;
$SaResponse=new \MyClasses\HTTP\Response();
$server->httpResponse=$SaResponse;
$server->exec();
}
{
$content=ob_get_clean();
}
{
$SyResponse=new Response($content,http_response_code(),headers_list());
}
return $SyResponse;
$server->exec();
Doesn't really return anything. It attempts to set headers itself, and stream the output to php://output (indeed, with the built-in request/response system).
If you want to embed SabreDAV into symfony, the most proper way to solve this is to subclass both Sabre\HTTP\Request and Sabre\HTTP\Response, and set these in the server (setting the ->httpRequest and ->httpResponse properties) before calling ->exec.
Your overridden request/response objects should then map to symfony's equivalents.
I don't know enough about symfony to tell you if they map cleanly and easily though, and I imagine it will in practice be simpler to try to work around symfony's system (although from an architectural standpoint, it will not be the most proper).
I have a simple controller file StudentController.php
<?php
$data = array();
$data["firstName"] = $_GET["firstName"];
loadView("StudentView.php", $data);
?>
I have a even simpler view file called StudentView.php
<?php
echo $firstName;
?>
I have absolutely no idea how to implement loadView($view, $data) function. I want variables from $data in controller became available in view ($data["foo"] from controller became $foo in view)
I want achieve what is very easy to do in CodeIgniter but I have no idea how it is implemented. I tried to look into Controller.php and Loader.php in source files, but it was too messy for me to understand.
I don't want to use CodeIgniter or any other framework, I want to natively do in PHP.
If you're going to be building a large website to be used by the general public, a framework is generally a good idea for multiple reasons:
Properly unit tested - generally speaking, you can be confident that the core of your website is functioning as it's intended to
Community support - have questions and you can easily get answers; generally these frameworks are open sourced and usually actively developed by the PHP community
Secure - Framework developers are, well, framework developers; and they have been trained to write code with security as a top priority
However, this question has nothing to do with frameworks vs not, so I'll answer the question you asked with a very simple function:
function loadView($view, $data) {
extract($data);
ob_start();
require_once $view;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
You can chose to return the contents or print them directly, but that function should do what you need. I'm making no guarantees about the security of this code, and I have obviously done no error checking. But it should serve as a great foundation to get you started.
Is there any standard library to do Rails style URL mapping in PHP? I am not using any framework, all the code is hand-written. Basically, I am looking for a library that does this
example.com/user/1/active
this should map to a user, with id = 1 and status = 2 (those being the parameters). I should be able to define the map.
There are roughly ten thousand ways to do this in PHP.
I've recently become a fan of klein.php, a lightweight bit of router code with some handy convenience methods. It's not a framework, and doesn't get in the way of you using one if you wanted to.
It's basically little more than "here's a URL pattern, and here's the function to run when the pattern matches."
Frameworks are really built to handle that automatically, but short of using a framework, you would be best off writing your own .htaccess rules (if you are using linux or os x), or try checking out how say, CakePHP handles url rewriting and base off of that.
Example:
http://example.com/name/corey
RewriteRule ^(.+)/(.+)$ /$1.php?name=$2 [NC,L]
That would rewrite the above url to /name.php?name=corey
PHP's purpose is not to handle differently formatted URLs. There should be some custom application logic taking care of this.
You've mentioned that you are not using any framework at this moment, so I would like to propose you to include Silex, it's a micro framework based on the components of Symfony 2.
Here's the 'Hello World' example:
require_once __DIR__.'/silex.phar';
$app = new Silex\Application();
$app->get('/hello/{name}', function($name) use($app) {
return 'Hello '.$app->escape($name);
});
$app->run();
You've mentioned that you are currently using PHP 5.2. Silex uses namespaces, which are available from PHP 5.3 and so on, so you will have to upgrade your PHP to take this approach.
Go with Symfony framework.
http://symfony.com/blog/new-in-symfony-1-2-toward-a-restful-architecture-part-1
Look at this response:
https://stackoverflow.com/questions/238125/best-framework-for-php-and-creation-of-restful-based-web-services
I'd love to see some code here rather than enjoy some sourse outside. =)
A solution could be to use the Zend_Service_Amazon_S3 component that's provided in Zend Framework -- if it's like many other components of ZF, it might be possible to use it outside of the framework, without having to do too much work to "extract" it.
I've never used it, but there are some examples of code on that manual page, and it doesn't seem too hard to use (quoting) :
require_once 'Zend/Service/Amazon/S3.php';
$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);
$s3->createBucket("my-own-bucket");
$s3->putObject("my-own-bucket/myobject", "somedata");
echo $s3->getObject("my-own-bucket/myobject");
(There are a couple of other examples I won't copy-paste)
An advantage of using a Zend Framework component is that ZF has (mostly) a good reputation, with code that's tested, maintained, supported, ...
Another solution could be to use this Amazon S3 PHP class ; I've never used it either, though...
<?php
require_once("sdk.class.php");
$s3 = new AmazonS3();
$bkt = (strtolower)$s3->key . "-bucket00";
$res = $s3->create_bucket($bkt, AmazonS3::REGION_US_E1);
?>
Can anyone post simple step by step integration for openid into a site which has a login system already?
I decided to use PHP OpenID 2.1.3 but could get where to start and what to do.
I think your best bet is using the OpenID module from the Zend Framework. It can be used on it's own, without having to use the whole framework, and they have a fairly simple explanation on how to use it on their manual pages. It's as simple (if you understand the concept of OpenID) as:
login_page.php:
// Load the library Zend Framework way, or load it yourself...
// Always good to pick apart the library anyway, to see how it works:
Zend_Loader::loadClass('Zend_OpenId');
$consumer = new Zend_OpenId_Consumer();
if(!$consumer->login($_POST['openid_identifier'], 'redirect_to.php'))
{
die('OpenID login failed.');
}
redirect_to.php:
Zend_Loader::loadClass('Zend_OpenId');
$consumer = new Zend_OpenId_Consumer();
if($consumer->verify($_GET, $id))
{
echo htmlspecialchars($id).' is a valid ID.';
}
else
{
// redirect to "login.php?login=failed".
if(!headers_sent())
{
header('HTTP/1.1 307 Temporary Redirect', true, 307);
header('Location: login.php?login=failed');
}
else die('Invalid ID.');
}
It is a lot easier to use than the PHP OpenID Library (php-openid) provided by the OpenID Foundation.
EDIT: How to implement Zend_OpenId (in response to comment).
Download the latest Zend Framework, and extract the folder ZendFramework-1.9.2/library/Zend/OpenId.
There are however a few things you have to do:
Change the class extends value in [...]/OpenId/Exception.php from Zend_Exception to Exception.
Go through every file (tedious, I know) and replace all the require's and include's to absolute path names.
Now you can reference the classes by:
require_once '/path/to/OpenId/Consumer.php';
$consumer = new Zend_OpenId_Consumer();
// If you plan on making your own OpenID's, use 'Provider' instead of 'Comsumer'.
require_once '/path/to/OpenId/Provider.php';
$provider = new Zend_OpenId_Provider();
Now, the best advice I can give you though is to read through the manuals! Don't expect it to work first time... Zend's implementation may be easier, but that doesn't stop OpenID being a pain in the ass!
No, there is no simple guide. There are too many login systems and different implementations to make this simple and straightforward.
For particular scripts, try googling it. For any other scripts, you will have to integrate OpenID into your application. If you use MVC, you're in luck: Have a look at the user model and plug OpenID into it.