This extension is a helper class for running actions. It makes controller actions reusable within different contexts.
Developed with Yii 1.1.7
When using 'touchUrlExt' (see below) you have to install the extension ehttpclient
Extract the files under .../protected/extensions.
This is only a quick overview of the usage. I don't list all configurable properties or methods here. Please take a look at the comments in the code of ERunActions.php
1. 'Touch' a url
Use this static methods to start processes at a remote or the own webserver. A request to the url will be sent, but not waiting for a response.
ERunActions::touchUrl($url,$postData=null,$contentType=null);
uses a simple built in httpclient (fsockopen).
ERunActions::touchUrlExt($url,$postData=null,$contentType=null,$httpClientConfig=array());
uses the extension EHttpClient, if you need support for redirect, proxies, certificates ...
NOTE: - touchUrl only works with absolute urls - Since v1.1 touchUrl works with https too
2. Run a controller action
Similar to CController.forward but with the possibility to suppress output with logging output, skip filters and/or before-afterAction.
ERunActions::runAction($route,$params=array(),$ignoreFilters=true,$ignoreBeforeAfterAction=true,$logOutput=false,$silent=false);
The 'route' is the route to the controller including the action. $params will be added as query params.
You can configure to ignore filters, before and afterAction of the controller, only log the output of the controller if $silent and $logOutput is set to true.
If both $ignoreFilters and $ignoreBeforeAfterAction are set to false, this will be the same as when using the method CController.forward.
3. Run a php script
This is a simple method that includes a script and extract the params as variable. The include file has to be located in runaction/config by default.
ERunActions::runScript($scriptName,$params=array(),$scriptPath=null)
4. Run a controller action as a background task
Use this if you have implemented time-consuming controller actions and the user has not to wait until finished. For example:
public function actionTimeConsumingProcess() { if (ERunActions::runBackground()) { //do all the stuff that should work in background //mail->send() .... } else { //this code will be executed immediately //echo 'Time-consuming process has been started' //user->setFlash ...render ... redirect, } }
5. Run preconfigured actions as batchjob
Run the config script 'cron.php' from runactions/config
$this->widget('ext.runactions.ERunActions');
The cron.php should return a batch config array(actiontype => configarray). There are 4 actiontypes (see methods from above) available
For example:
return array( //execute ImportController actionRun ignoring filters and before- afterAction of the controller ERunActions::TYPE_ACTION => array('route' => '/import/run'), ... //run the php file runaction/config/afterimport.php to do something with the imported data ERunActions::TYPE_SCRIPT => array('script' => 'afterimport'), ... //inform another server that the process is finished ERunActions::TYPE_TOUCH => array('url'=>'http://example.com/processfinished'); );
You can override the configure the properties of the widget in the config of the action.
Run the config script 'runactions/config/myscript.php'
$this->widget('ext.runactions.ERunActions', 'config'=>'myscript', 'ignoreBeforeAfterAction' => true, 'interval' => 3600, 'allowedIps' => array('127.0.0.1'), );
Content of 'myscript.php'
return array( ... ERunActions::TYPE_ACTION => array('route' => '/cache/flush' 'ignoreBeforeAfterAction' => false, ), ... );
6. Use the widget to expose a 'cron' controller action
Add the RunActionsController as 'cron' to the controllerMap in applications config/main.php
'controllerMap' => array( 'cron' => 'ext.runactions.controllers.RunActionsController', ... ),
Now you can run the config script runactions/config/cron.php by calling
http://localhost/index.php/cron
or another script by
http://localhost/index.php/cron/run/config/myscript
or running in background so that a HTTP 200 OK will immediatly be returned
http://localhost/index.php/cron/touch/config/myscript
Configure the urls in your crontab by using 'wget'.
7. GET / POST requests
You can use the builtin Http client for simple requests:
echo ERunActions::httpGET('https://example.com',array('type'=>1,'key'=>123));
Will get the content from the url 'https://example.com/?type=1&key=123'
echo ERunActions::httpPOST('https://example.com',array('name'=>'unknown'),null,array('type'=>1,'key'=>123));
Will POST the form variable name='unknown' to the url 'https://example.com/?type=1&key=123
8. Interval filter
You can install the component 'ERunActionsIntervalFilter' (since v1.1) as a filter in a controller. See CController::filters()
public function filters() { return array( ... array( 'ext.runactions.components.ERunActionsIntervalFilter + export, import', 'interval'=>15, //seconds 'perClient'=>true, //default = false //'httpErrorNo' => 403, (=default) //'httpErrorMessage' => 'Forbidden', (=default) ), .... );
This will ensure, that the controller actions 'export' and 'import' can only be executed once withing the time interval of 15 seconds per client (= IP-Address) If the action is called more than once, a CHttpException will be thrown.
Note: There maybe has to be stored a lot of data in the global storage if you set 'perClient' to true.
9. Notes
a) In a controller action executed by 'runAction', 'touchUrl' or a batch script you can use the static methods
to switch behavior if the action is called in contexts above.
b) The widget catches all errors (even php errors) and uses Yii::log if an error occurs. So running cron jobs will not display internal errors.
Changelog
Total 20 comments
There seems to be an undocumented dependancy on something called "EHttpClient" - whats that about?
If you need to access the web user that initiated the request when running a background task, you might want to pass on the PHPSESSID cookie with the background request, please see this topic
I tried to use runBackground to read data from fingerprint machine and save to database, but still the server is time out.
Any help on this?
Try to test the touchUrl method at the server.
This should do a httprequest to actionA. You should be able to debug or log the code. This is how runBackground works, but only one action is used.
As pseudo-code for the runBackground method
I have updated the function and returns the url that it visits. I try to visit this url with wget from inside the server and it returns me to the message of the else statement
if(ERunActions::runBackground()){}else{echo 'error';}
which means the the url works but the code cannot run this method.
so it cannot run the ERunActions::runBackground() for a reason.
Please take a look at the runBackground function in ERunActions.php
It 'touches' the same controller action where 'runBackground' is called a second times. As I wrote in the comment of this function, the $request->getHostInfo() there can detect a not 'reachable url' when a server is behind a firewall (maybe '127.0.0.1' or '192.168.x.x is not really reachable...).
So you can try this:
Add a die($url) or Yii::log(...) there to get the url and try to call this url from inside your server/php enviroment (comandline: wget ...).
If this url doesn't work, you can set the param 'internalHostInfo' to a reachable scheme 'http://....'.
Is there any Dependency in the php version because this ext it doesn't work in my server while locally works fine.
For cron/background tasks I typically have a controller written specifically to handle these requests. Inside your controller you add the following:
where Yii::app()->params['httpKey'] is any security key/password that you can assign (i.e. use a hash algorithm to generate it).
The purpose of this filter is to authenticate anyone trying to access it via a GET key, and this performed before any action in the controller. If authentication fails then it returns a 404 error.
I don't use runBackground for actions which need authentication. Using the implementation above you can setup your touchUrl and add in the key as a GET parameter. (i.e http://www.myblog.com/backgroundtasks/sendemail?key=a123gasj3kasfl...)
That's it, now you can keep away unauthenticated users from triggering your cron/background actions.
adhoc answer - not tested:
runBackground calls 'touchUrl', that means, it's a simple httprequest to the same controller action where runBackground is called. But this request is sent from php, not from the browser and therefore - I think - this is an anonymus/guest request (because the php script is not authenticated).
Maybe you can build your rules as you would do, but you have to add an extra rule to allow to execute the action from the php-script (ip = 127.0.0.1 or the internal ip of your server)
How can ERunActions::runBackground() get around yii's access rules? It wont work unless I use it in a action that allows all users.
Thanks for your remark.
As referenced in the source the internal httpclient is a (quick) port from this code.
I will change the code to your bugfix in the next release.
If you're trying to use ERunActions::runBackground() inside an action which deals with form data. Most likely your $_POST will be a nested array. In this case an exception occurs "urlencode() expects parameter 1 to be string, array given".
I got around this by using PHP's native http_build_query() in components/ERunActionsHttpClient.php
I replaced it with this:
I suspect that by using this function you won't need the is_array conditional. And I'm also guessing it'll work for $_GET.
Anyway I've only tested for nested $_POST arrays and it's working for me.
Cheers, jc
Thanks for your answer. Another question - does runactions works with yii 1.1.9? Just upgraded, but seems it's not working. I have lines at log, that runactions executed succefully, but seems to be not, cause any data that must be changed by actions not changed.
You can create a cron.php that runs a script and in the script you can run the actions.
cron.php
runactions/config/scripts/cronscript.php
You cannot set a interval in the runAction method only for the runactions widget. If you need different intervals you have to generate multiple urls/cronscripts (take a look at RunActionsController.php).
You can add different actions to your CronController like
Hello. Thanks for useful extension. I have a question: How to add multiple actions of one type in config file. I.e. i want to do something like this in my cron.php
Please see this topic.
If you have problems with 'runBackground' add an action like below to a controller and check if you can find the log item in your logfile:
After reading extension documentation very difficult to understand how to use it. But really it's simple and useful. After hour of search found this forum topic where explained "How it's works" :)
Thanks for good extension. Save a lot of time.
the article you provided i v read , fsockopen limitation in that document may be the max size . it may only occur in loop or iteration environment. when using while or for statement it will cause that happens. if the script is long live it will cause some bad things happening such as memory leak ,memory exhaust, treasure handler waste (you see the db connection ,file handler ,socket are). i just use it to do async call in methods of controller or model not in console environment and no loop .
another thing: Yii::import('ext.runactions.components.ERunAction'); should be Yii::import('ext.runactions.components.ERunActions'); if run as cron , are there some trick to stop the cron job ? i do the cron example but in the log file give me this error info: [error] [runactions] Invalid time interval - Last call: Allowed interval: 3600
runactions itself has no limitations. Touchurl does only a httprequest to the own or another http-server (without reading data).
A limitation can be the server performance, configured maxclients in apache ... etc. If your service (for example converting image, videos ...) is running at the same server the memory-limit can be a problem too.
You have to check about issues about the different request adapters of ehttpclient. For example, the internal httpclient or the default ehttpclient uses 'fsockopen'. There is an issue about this published (April, 2005) in the fsockopen PHP manual.
But when using touchUrlExt you can test with other adapters (curl,...) too.
I would set up a test-application with 'touchUrl'/'touchUrlExt' (sleep, log profiling....) in a loop and test different adapters from ehttpclient. The internal httpclient of the exentsion has no 'overhead' and should be the 'fastest', but only uses 'fsockopen'.
joblo : firstly great job! i want to use the async feature , but don't clear if it has connection limits , if many users call this code at same time:
ERunActions::touchUrlExt(app()->createAbsoluteUrl('site/someAction'));so what's your advice ? does it lose action call when workload is too much? i 'v used the gearman for this purpose now ! but if i can use this extension it will be better . thanks for this great extension ,
Leave a comment
Please login to leave your comment.