Is it possible for a PHP script to insert a block of code into a database, and then some kind of daemon sees that it was put in, and then runs the code? Kind of like a cron job, or a job queue.
Technically you can do it. The code should be stored in a TEXT column and then you could evaluate it with eval: http://es.php.net/manual/en/function.eval.php
This is not a very good idea for several reasons: code stored in a database is not under version control, and the security implications are pretty severe. Most job queue systems store a "job type" and "job parameters" instead of executable code. The job type could be the name of a file to include, or the name of a class to instantiate in an OOP setting. Then you would call a specific function defined there, passing in the parameters.
The job parameters can be any PHP data structure if you use the serialize function to turn it into a string first. http://es.php.net/manual/en/function.serialize.php
Related
I have an error reporting function in a web application, and when a user posts an error, an email sends out to the developer email. Current workflow is like user input -> db write -> send email -> redirect.
To prevent the email function holding back the rest of the user process, I want to separate it, so the email sending process can do their thing but the users can keep working. So its like
user input -> db write --> redirect
\-> send email
First thing that came into my mind is that I send an ajax request to start the email process so the error reporting and the email function can work asynchronously, but I'm curious if there would be a better way to do this.
There are different ways to do this depending on how complex you want to get. PHP does have process control stuff, but especially if your site is going to be hosted on a shared hosting provider, the availability of that functionality in your hosting environment is not guaranteed.
Probably one of the more foolproof ways to do this in terms of ensuring compatibility across a wide range of hosting environments is to start a new "mails to send" database table and log a row to that for each mail you want to send. Then set up a cron task on your server which runs a script which pulls all rows from this table, sends the email, then removes the row from the table. With CodeIgniter, if you call the index.php script like
php -f index.php foo bar
it will call the same method that would be called if the /foo/bar path is called via the standard routing system (eg, the bar method of the Foo controller). Then, inside that method, you can use if (!is_cli()) { exit(); } to make sure that method isn't being called from a web request, and flock() to make sure you don't have two processes sending emails at one time (in case one hangs or takes a long time or something). Select everything from the "mails to send" table, iterate through them row by row, send the mail, do some logging if applicable, then delete the row. (More info on doing CLI scripts on CodeIgniter.)
Then set up a cron task to run this script every X minutes, perhaps set up some way to check the table now and then to make sure it's not growing too large (which would be a sign that the mail sending script is failing somehow), and there you go.
As mentioned above, there are more clever ways to implement something like this, but this is a fairly broadly-compatible and foolproof one.
Forking off a process from a PHP script that is handling a web server request is possible, but you should be wary of a few things:
Your original PHP process and the forked off process will probably share a lot of data objects. While some variables may be copied and can be manipulated independently in the child and parent processes, some vars (like db connections or file handles, etc.) may refer to the same computing resource. You should be careful to avoid re-using resource variables. Have the child reconnect to your db and re open files, etc.
If a process forks off, it might have trouble connecting to a db or mail gateway, etc. You should probably make this forked child process loop to try and accomplish its goal and then eventually die after a certain number of attempts if it's doing something important.
There are probably a dozen other warnings about multithreading, race conditions, resource usage, etc. Just remember that forking off processes means that you are consuming more resources, that those resources might be in use by other processes, and you might get weird, hard-to-troubleshoot problems.
All that said, I have had some luck using a combination of the exec command to fork off a separate process and then calling the posix_setsid function so that the forked-off child process can fully detach itself from apache and continue running even if the parent process finishes or apache restarts or whatever.
USE THIS CODE AT YOUR OWN RISK.
From your CodeIgniter script, you can fork off a child process using exec, like so:
// the PARENT process (a CodeIgniter script running in response to http request)
// put this code in a controller or something
// here's a command to run the PHP executable in the background on some file
// routing the output and error messages to another file
$cmd = "/usr/bin/php /path/to/child-script.php > /tmp/foo/out.txt 2>&1 & echo \$!";
// will contain an array of output lines from the exec command
$cmd_output = NULL;
// will contain the success/failure code returned by the OS.
// Will be zero for a valid command, non-zero otherwise
$cmd_result = NULL;
// $return will contain the last line from the result of
// the command which should be the PID of the process we have spawned
$cmd_return = exec ( $cmd, $cmd_output, $cmd_result );
NOTE: that you could instead use pcntl_fork to fork off the process. The reason I have not is because that means the child process would inherit every variable in the codeigniter parent script which can lead to some confusing behavior. E.g., if one process changes the db connection, that change might suddenly appear in the other script, etc. The use of exec() here more thoroughly separates the two scripts and makes things simpler. If you want to change $cmd above to run a CodeIgniter controller, see CodeIgniter from the Command Line.
In the child process, you must call posix_setsid() so that the child script detaches itself from the parent. If you do not, then the child process might be killed when the parent process finishes (or is killed) or if the web server restarts or crashes or whatever.
Here is the code in the child process, which requires the POSIX extension to be installed, enabled, and not disabled in PHP.ini by the disable_functions directive. This extension is very often disabled (and for good reason) in your web server's PHP.ini, but sometimes still available for CLI scripts. Another good reason to use exec to fork off a command-line process.
// child-script.php
// CHILD process. Put your emailing code or other long-running junk in here
// because this is a brand-new, separate process, you might need to load configuration files, connect to the db, etc.
if (!extension_loaded("posix")){
throw new Exception("This script requires posix extension");
}
// NOTE: the output and results of this file will be completely unavailable to the parent script and you might never know what happens if you don't write a log file or something. Consider opening a log file somewhere
// process id of this process, should match contents of $cmd_return above
$mypid = posix_getpid();
// session id -- not to be confused with php session id
// apparently this call will make this process a 'session leader'
$sid = posix_setsid();
if ($sid < 0) {
throw new Exception("setsid failed, returned $sid");
}
// this output should be routed by the exec command above to
// /tmp/foo/out.txt
echo "setsid success, sid=$sid\n";
// PUT YOUR EMAILING CODE HERE
I have a PHP file that will only connect to DB and displays the resultset in an HTML table. How do we create a unit test script for such PHP file?
Thanks a lot in advance.
If you did not defined any function on your code (and don't want to), this is not an ideal scenario. You can still write a PHPUnit test starting PHP's built-in web server and perform HTTP requests (using Guzzle?). Then, ensure that what's being generated is consistent with the records of your database.
However, it may not be really needed to write tests only for this functionality, since it can be easily tested by hand and you risk to write a lot of duplicate code between your script and the test(s).
I'm building a login class in php that will use sessions. I wanted to know:
If an instance of this very class will be saved until it is destroyed, even if I move to another page(without destroying it)?
Will I have to rebuild another instance of the class every time (with some saved data in the sessions)?
What is the life of a php class?
PHP variables persist while the program is running... just like any other programming language.
Now, how long does the program actually run? We have to distinguish between:
The PHP interpreter itself (written in C)
Your script (written in PHP)
The PHP interpreter is not designed to share variables between scripts so it doesn't really matter how long it runs.
Your script will run, well, until it's finished: it reaches the last line of finds an exit, die() or return statement. This simple fact should already answer your question. But it's also worth taking into account that there's no point in keeping a PHP script running continuously like a desktop application when it's only used to serve an HTTP request. Unlike other protocols (namely FTP or IRC), HTTP is stateless: each user request starts and closes the connection*.
(*) That's not entirely true (connections can and are normally reused) but doesn't affect the design implications.
Yes, the php class will be destroyed. You can serialize the object and store it in the session, if you choose : Documentation
A PHP object (class instance) acts just like a variable and will be destroyed at the end of the page request. Moreover you cannot store an object in a PHP session. The best you can try is to serialize() it and unserialize() it afterwards to keep your data.
You should see this per request. If you make a new request when going t another page then yes it needs to be rebuild.
What you could also do is Inversion of control or some sort of register setup. This way you can define it once and return an instance.
Example:
$ioc->translate(function() {
# Do stuff load configs. Get data from previous request
return new \Danoon\Link\Translate('../etc/lang/en_US.php');
});
I was wondering, I have a few functions in PHP that're not called every time but still are included in my files on each load. Does it still run the code even if your not calling the function at that time? The reason I'm asking, the codes in my function are expensive to run CPU wise and I don't call them every time and want to make sure if there not called they do not run the code within the function.
Thank you
In short, a function that isn't explicitly called does not run. However, here is a short what and why we use functions that I found.
A function is a "black box" that we've locked part of our program
into. The idea behind a function is that it compartmentalizes part of
the program, and in particular, that the code within the function has
some useful properties:
It performs some well-defined task, which will be useful to other
parts of the program.
It might be useful to other programs as well; that is, we might be
able to reuse it (and without having to rewrite it).
The rest of the program doesn't have to know the details of how the
function is implemented. This can make the rest of the program
easier to think about.
The function performs its task well. It may be written to do a
little more than is required by the first program that calls it,
with the anticipation that the calling program (or some other
program) may later need the extra functionality or improved
performance. (It's important that a finished function do its job
well, otherwise there might be a reluctance to call it, and it
therefore might not achieve the goal of reusability.)
By placing the code to perform the useful task into a function, and
simply calling the function in the other parts of the program where
the task must be performed, the rest of the program becomes clearer:
rather than having some large, complicated, difficult-to-understand
piece of code repeated wherever the task is being performed, we have
a single simple function call, and the name of the function reminds
us which task is being performed.
Since the rest of the program doesn't have to know the details of
how the function is implemented, the rest of the program doesn't
care if the function is reimplemented later, in some different way
(as long as it continues to perform its same task, of course!). This
means that one part of the program can be rewritten, to improve
performance or add a new feature (or simply to fix a bug), without
having to rewrite the rest of the program.
Functions are probably the most important weapon in our battle against
software complexity. You'll want to learn when it's appropriate to
break processing out into functions (and also when it's not), and how
to set up function interfaces to best achieve the qualities mentioned
above: reuseability, information hiding, clarity, and maintainability.
http://www.eskimo.com/~scs/cclass/notes/sx5.html
How long does the instance of a class, object, in PHP last. Is it confined to the running script or will it last for a session? If it does last for a session is this regardless of whether the PHP script has start ed the session?
A simple question but this makes a big difference to me because it will mean user data will survive as an on the server and won't need storing in the session variable. Hence affecting some fundamentals of my design.
Thanks
Colin
the question doesn't really belong to OOP but to PHP behavior in general
All PHP data is going nowhere as well as PHP script itself.
PHP scripts execution is atomic. It's not like a desktop application constantly running in your browser, and not even a daemon with persistent connection to your desktop application. It's more like a command line utility - doing it's job and exits.
That's why using external storage, like file or database is required. But of course you can save only strings there, not instances of variables or anything of the kind. Strings only.
It depends on the way PHP is configured. If PHP is configured as CGI, instances would be lost on each invocation. PHP would be invoked for each http request.
If PHP is configured as a module, then there would be multiple processes handling PHP requests. So, the instance would survive in "that particular" process. But subsequent requests might be handled by a different process.
If you need class instance to survive, you will need to serialize it and store it in DB or file.
If this information is transient (or stored somewhere else) you can store (seralize) it in session. One such example is user's full name which might be required for each http request, so it can be read from DB once and then stored in session.
Example of storing class instances in session : http://www.talkphp.com/advanced-php-programming/3407-storing-class-instance-into-session.html
It's nicely explained here :
How long does an instance variable persist? In Rails? In Java? In PHP?