Laravel: Customize the request flow - php

Within my app ("BIRD3"), I have a NodeJS server that uses the hprose RPC system to talk to a PHP server to query it run a request and return the result (the PHP server is multi-process and spawns a sub-process per request - for now). This proposes a few difficulties; headers, cookies, sessions.
In my Yii1 based app, I used an in-development branch of the runkit extension. But, as you can tell, this is super hacky, not clean, and dependency-wise, not a smart idea. But it worked, for the most part. Here is a snippet from that very bit of code I did:
<?php
// Header.
runkit_function_redefine("headers_sent", '', 'return false;');
runkit_function_redefine(
"header", '$to,$replace=false,$status=200',
'return HttpResponse::header($to);'
);
// We have a custom handler.
runkit_function_redefine(
"setcookie",
'$name,$value,$expire=0,$path="/",$domain=null,$secure=false,$httponly=false',
'return HttpResponse::setcookie($name,$value,$expire,$domain,$secure,$httponly);'
);
// Because...
runkit_function_redefine(
"session_regenerate_id",
'$deleteOld=false',
'return bird3_session_regenerate_id($deleteOld);'
);
Now, why did I need this? Simple: Yii does not have a direct way to override Session/Header/Cookie management without doing a good load of wiring of the internals. Overriding internal dependencies with extended, derived classes is not very easy and bulks up the config file a lot.
So my question is:
Does Laravel give me the possibility to extend a few classes, override methods that do Session and Header and Cookie management and enhance it to use my custom functions instead?

Related

$GLOBALS['TSFE']->set_no_cache() is not working From typo3 version 6.2.17 onwards

I have called global 'set_no_cache' function in intialize action in my extesion.
$GLOBALS['TSFE']->set_no_cache();
but unfortunately it is not working From typo3 version 6.2.17 onwards
So Is there any alternative solution?
If you have any idea then please share.
Please note that set_no_cache completely disables any output cache in TYPO3. You most certainly dont need that while developing and should never set it in productive systems.
You can control what actions are cached and which aren't in the ext_localconf.php of your extension.
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendor' . $_EXTKEY,
$pluginName
$controllerActionCombinations,
$uncachedActions
);
Basically, you just state your controllers actions in either $controllerActionCombinations or $uncachedActions to set up wether they're cached. Look up this Reference page for more information: https://docs.typo3.org/typo3cms/ExtbaseFluidBook/b-ExtbaseReference/Index.html
If you really need to put a system into uncachable mode, I found it to be a good practice to bind that to the development context as a Typoscript condition in your setup like so:
[applicationContext = Development]
config.no_cache = 1
[end]
More information on these conditions regarding Application Context here: http://usetypo3.com/application-context.html

Are Yii sessions and PHP sessions cross-compatible?

In Yii, while looking at the source code for CWebUser::logout, I've noticed that they use Yii::app()->getSession()->destroy() instead of the usual PHP session_destroy.
Doing a bit of research I saw that Yii has a class called CHttpSession with its own methods to store data.
This got me thinking - are they cross-compatible? Is CHttpSession just a nice wrapper? Or is it an all or nothing process?
In my custom code, I've been using $_SESSION to do all of my session-related stuff. While in things generated by Yii, I assume that it uses CHttpSession. Is it a problem to use both and mix them up?
I am now in the process of moving my session handling to AWS DynamoDB (https://github.com/aws/aws-sdk-php/blob/master/docs/feature-dynamodb-session-handler.rst), and before I add this additional layer, I want to make sure everything is compatible.
You can use Database based session to recover that. Its really simple. Just put
'session' => array(
'class'=>'CDbHttpSession',
'connectionID' => 'db'
),
on config/main.php components
CHttpSession is a nifty OO wrapper for php sessions. The underlying implementation uses php's session methods. Here's a snippet of part of the code for CHttpSession::open():
public function open()
{
if($this->getUseCustomStorage())
#session_set_save_handler( array($this,'openSession'),array($this,'closeSession'),array($this,'readSession'),array($this,'writeSession'),array($this,'destroySession'),array($this,'gcSession'));
#session_start();
For Yii convention, always use CHttpSession instead of $_SESSION.

Getting CakeS3 to work in the CakeShell

I want to be able to call the CakeS3 plugin from the Cake Shell. However, as I understand it components cannot be loaded from the shell. I have read this post outlining strategies for overcoming it: using components in Cakephp 2+ Shell - however, I have had no success. The CakeS3 code here is similar to perfectly functioning cake S3 code in the rest of my app.
<?php
App::uses('Folder','Utility');
App::uses('File','Utility');
App::uses('CakeS3.CakeS3','Controller/Component');
class S3Shell extends AppShell {
public $uses = array('Upload', 'User', 'Comment');
public function main() {
$this->CakeS3 = new CakeS3.CakeS3(
array(
's3Key' => 'key',
's3Secret' => 'key',
'bucket' => 'bucket')
);
$this->out('Hello world.');
$this->CakeS3->permission('private');
$response = $this->CakeS3->putObject(WWW_ROOT . '/file.type' , 'file.type', $this->CakeS3->permission('private'));
if ($response == false){
echo "it failed";
} else {
echo "it worked";
}
}
This returns an error of "Fatal error: Class 'CakeS3' not found in /home/app/Console/Command/S3Shell.php. The main reason I am trying to get this to work is so I can automate some uploads with a cron. Of course, if there is a better way, I am all ears.
Forgive me this "advertising"... ;) but my plugin is probably better written and has a better architecture than this CakeS3 plugin if it is using a component which should be a model or behaviour task. Also it was made for exactly the use case you have. Plus it supports a few more storage systems than only S3.
You could do that for example in your shell:
StorageManager::adapter('S3')->write($key, StorageManager::adapter('Local')->read($key));
A file should be handled as an entity on its own that is associated to whatever it needs to be associated to. Every uploaded file (if you use or extend the models that come with the plugin, if not you have to take care of that) is stored as a single database entry that contains the name of the config that was used and some meta data for that file. If you do the line of code above in your shell you will have to keep record in the table if you want to access it this way later. Just check the examples in the readme.md out. You don't have to use the database table as a reference to your files but I really recommend the system the plugin implements.
Also, you might not be aware that WWW_ROOT is public accessible, so in the case you store sensitive data there it can be accessed publicly.
And finally in a shell you should not use echo but $this->out() for proper shell output.
I think the App:uses should look like:
App::uses('CakeS3', 'CakeS3.Controller/Component');
I'm the author of CakeS3, and no I'm afraid there is no "supported" way to do this as when we built this plugin, we didn't need to run uploads from shell and just needed a simple interface to S3 from our controllers. We then open sourced the plugin as a simple S3 connector.
If you'd like to have a go at modifying it to support shell access, I'd welcome a PR.
I don't have a particular road map for the plugin, so I've tagged your issue on github as an enhancement and will certainly consider it in future development, but I can't guarantee that it would fit your time requirements so that's why I mention you doing a PR.

Different behaviour with and without Symfony's response system

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).

Load PHP Script Outside of Zend Framework Before Bootstrapping

I need to run a php script once before my zend framework application is bootstrapped and run. This works now by calling this initial script in my /public/index.php, however the script is run for all subsequent zend framework page requests as well. I need this script to only be run once on the initial request and not again when additional pages are loaded via ajax.
My initial attempts were to set some php constants in the /public/index.php file like so:
if (!defined('SOME_VAR')) require_once 'path/to/script/to/run/once.php';
define('SOME_VAR', '1);
However, when another page is loaded via ajax, even though I've defined 'SOME_VAR', it doesn't persist and stay as defined and the script is executed again.
I'm using Zend Framework 1.11, Apache (Xampp).
Executing this script AFTER Zend has been bootstrapped and run (inside Zend Framework) is not an option.
Constants don't work because they only exist for the duration of the request.
It sounds like you want to figure out if the current request is a regular request or an XmlHttpRequest (AJAX) request.
You could try something like this at the top of your index.php:
<?php
define('IS_AJAX_REQUEST', isset($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if (! IS_AJAX_REQUEST){
// run your code.
}
If you're using sessions, you could also just set a flag in the session once you special code has been run, and test for that.
According to the Zend Framework Documentation:
However, should custom initialization be necessary, you have two choices. First, you can write methods prefixed with _init to specify discrete code to bootstrap. These methods will be called by bootstrap(), and can also be called as if they were public methods: bootstrap(). They should accept an optional array of options.
If your resource method returns a value, it will be stored in a container in the bootstrap. This can be useful when different resources need to interact (such as one resource injecting itself into another). The method getResource() can then be used to retrieve those values.
The other option is to use resource plugins. Resource plugins are objects that perform specific initializations, and may be specified:
When instantiating the Zend_Application object
During initialization of the bootstrap object
By explicitly enabling them via method calls to the bootstrap object
Resource plugins implement Zend_Application_Resource_ResourceAbstract, which defines simply that they allow injection of the caller and options, and that they have an init() method.

Categories