Procmail setup, to execute PHP script - php

I've got a procmail setup working pretty well, seems to be executing my PHP script no problem when it receives an email.
Here is an example of the .procmailrc file:
#BEGIN PROCMAIL SCRIPT FOR MAIL PARSING
DEFAULT=$HOME/Maildir/
MAILDIR=$HOME/Maildir
PMDIR=$HOME/.procmail
LOGFILE=$PMDIR/log.`date +%y-%m-%d`
SHELL=/bin/sh
:0
|`/usr/local/php53/bin/php /home/usrmail/email/script.php`
The log output below:
From x13542053#homiemail-mx22.g.dreamhost.com Mon Feb 18 20:49:35 2013
Subject: TEST
Folder: HELLO 2559
/bin/sh: HELLO: No such file or directory
Is just a simple echo "HELLO"; in the php script, seems to work fine!
However when I try to actually parse the email using the following code I get the error below in the log:
$rawEmail = '';
if (($fp = fopen('php://stdin', 'r')) !== false) {
while (!feof($fp)) {
$rawEmail .= fread($fp, 1024);
}
fclose($fp);
}
$email = new Zend_Mail_Message(array(
'raw' => $rawEmail
));
From actualaddress#gmail.com Mon Feb 18 20:44:36 2013
Subject: Re: Test
Folder: Fatal error: Class 'Zend_Mail_Message' not found in /home/sy 2747
/bin/sh: Fatal: No such file or directory
This isn't working correctly obviously, I'm not sure why. For one, the From header went through on this one but not the other, that seems intermittent.
Also the directory (/home/sy) is either truncated or something is cutting it off to cause an error.
I'm not familiar with Zend really at all, or procmail. I was happy enough to get this far, just want to parse the email a bit so I can fetch the body of the email and put it somewhere. Someone convinced me this would be a better way than just using IMAP or something and I listened. If anyone's got any wonderful solutions or alternatives I'm all ears. Thanks guys!

You are mixing two related but different pieces of syntax.
If you want to pipe to your script, it should be just
:0
* conditions, maybe
| /path/to/script
or if you want to use the output of the script, something like
:0
* conditions, maybe
`echo HELLO`
would file into a folder named HELLO, i.e. use the output from the script as a literal.
As for the error message from PHP, I imagine you need to add something to PHP's library path (quick googling suggests you should fix the include_path in your php.ini).
What are you trying to accomplish, though? If you just want to send the message where the headers say it should be going, something like
:0
* conditions, maybe
! -t
should get you that. I cannot imagine a situation where you would want to do this (other than if you are trying to solve the wrong problem altogether). If you want to send a truncated copy of the message, something like
:0c
* conditions, maybe
{
:0fw
| head -n 10
:0
! -t
}
would truncate the message to the first ten lines. If you want to truncate to 1024 bytes exactly, that's not much harder.
On the other hand, if you just want to store the message's body (full RFC822 body, i.e. any MIME attachments etc will just be included verbatim, undecoded) you can do that with
:0b
saved/
or maybe if you want PHP there
:0b
| /path/to/script.php
For what it's worth, the error message is being truncated, but that is mainly because you are trying to use it as the name of the script to deliver the email to. If you take out the backquotes, the error message should end up in Procmail's standard error without truncation.

Related

Open Linux terminal command in PHP

I have a server running on Linux that execute commands to 12 nodes (12 computers with Linux running in them). I recently downloaded PHP on the server to create web pages that can execute commands by opening a specific PHP file.
I used exec(), passthru(), shell_​exec(), and system(). system() is the only one that returns a part of my code. I would like PHP to act like open termainal command in linux and I cannot figure out how to do it!
Here is an example of what is happening now (Linux directly vs PHP):
When using linux open terminal command directly:
user#wizard:/home/hyperwall/Desktop> /usr/local/bin/chbg -mt
I get an output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
and additional code to send it to 12 nodes.
Now with PHP:
switch($_REQUEST['do'])
{ case 'test':
echo system('/usr/local/bin/chbg -mt');
break;
}
Output:
The following settings will be used:
option = mtsu COLOR = IMAGE = imagehereyouknow!
NODES = LOCAL
And stops! Anyone has an explanation of what is happening? And how to fix it? Only system displays part of the code the other functions display nothing!
My First thought is it can be something about std and output error. Some softwares dump some informations on std out and some in std error. When you are not redirecting std error to std out, most of the system calls only returns the stdout part. It sounds thats why you see the whole output in terminal and can't in the system calls.
So try with
/usr/local/bin/chbg -mt 2>&1
Edit:
Also for a temporary work through, you can try some other things. For example redirect the output to file next to the script and read its contents after executing the command, This way you can use the exec:
exec("usr/local/bin/chbg -mt 2>&1 > chbg_out");
//Then start reading chbg_out and see is it work
Edit2
Also it does not make sense why others not working for you.
For example this piece of code written in c, dumps a string in stderr and there is other in stdout.
#include <stdio.h>
#include<stdlib.h>
int main()
{
fputs("\nerr\nrro\nrrr\n",stderr);
fputs("\nou\nuu\nuttt\n",stdout);
return 0;
}
and this php script, tries to run that via exec:
<?php
exec("/tmp/ctest",&$result);
foreach ( $result as $v )
{
echo $v;
}
#output ouuuuttt
?>
See it still dumps out the stdout. But it did not receive the stderr.
Now consider this:
<?php
exec("/tmp/ctest 2>&1",&$result);
foreach ( $result as $v )
{
echo $v;
}
//output: errrrorrrouuuuttt
?>
See, this time we got the whole outputs.
This time the system:
<?php
echo system("/tmp/ctest 2>&1");
//output: err rro rrr ou uu uttt uttt
?>
and so on ...
Maybe your chbg -mt writes additional code to stderr instead of stdout? Try to execute your script inside php like this:
/usr/local/bin/chbg -mt 2>&1
The other responses are good for generic advice. But in this specific case, it appears you are trying to change your background on your desktop. This requires many special considerations because of 'user context':
First, your web server is probably running as a different user, and therefore would not have permissions to change your desktop.
Second, the program probably requires some environmental variables from your user context. For example, X programs need a DISPLAY variable, ssh-agent needs SSH_AGENT_PID and SSH_AUTH_SOCK, etc. I don't know much about changing backgrounds, but I'm guessing it involves D-Bus, which probably requires things like DBUS_SESSION_BUS_ADDRESS, KONSOLE_DBUS_SERVICE, KONSOLE_DBUS_SESSION, and KONSOLE_DBUS_WINDOW. There may be many others. Note that some of these vars change every time you log in, so you can't hard-code them on the PHP side.
For testing, it might be simpler to start your own webserver right from your user session. (i.e. Don't use the system one, it has to run as you. You will need to run it on an alternate port, like 8080). The web server you start manually will have all the 'context' it needs. I'll mention websocketd because it just came out and looks neat.
For "production", you may need to run a daemon in your user context all the time, and have the web server talk to that daemon to 'get stuff done' inside your user context.
PHP's system only returns the last line of execution:
Return Value: Returns the last line of the command output on success, and FALSE on failure.
You will most likely want to use either exec or passthru. exec has an optional parameter to put the output into an array. You could implode the output and use that to echo it.
switch($_REQUEST['do'])
{ case 'test':
exec('/usr/local/bin/chbg -mt', $output);
echo implode('\n', $output); // Could use <br /> if HTML output is desired
break;
}
I think that the result of execution, can changes between users.
First, try to run your PHP script directly into your terminal php yourScript.php
If it runs as expected, go to your Apache service and update it to run with your own credentials
You are trying to change the backgrounds for currently logged in users... While they are using the desktop. Like while I'm typing this message. I minimize my browser and 'ooh my desktop background is different'. Hopefully this is for something important like it turns red when the reactor or overheating.
Anyway to my answer:
Instead of trying to remotely connect and run items as the individual users. Setup each user to run a bash script (in their own account, in their own shell) on a repeating timer. Say every 10 minutes. Have it select the SAME file.. from a network location
/somenetworkshare/backgrounds/images/current.png
Then you can update ALL nodes (1 to a million) just by changing the image itself in /somenetworkshare/backgrounds/images/current.png
I wrote something a while ago that does just this -- you can run a command interpreter (/bin/sh), send it commands, read back responses, send more commands, etc. It uses proc_open() to open a child process and talk to it.
It's at http://github.com/andrasq/quicklib, Quick/Proc/Process.php
Using it would look something like (easier if you have a flexible autoloader; I wrote one of those too in Quicklib):
include 'lib/Quick/Proc/Exception.php';
include 'lib/Quick/Proc/Exists.php';
include 'lib/Quick/Proc/Process.php';
$proc = new Quick_Proc_Process("/bin/sh");
$proc->putInput("pwd\n");
$lines = $proc->getOutputLines($nlines = 10, $timeoutSec = 0.2);
echo $lines[0];
$proc->putInput("date\n");
$lines = $proc->getOutputLines(1, 0.2);
echo $lines[0];
Outputs
/home/andras/quicklib
Sat Feb 21 01:50:39 EST 2015
The unit of communication between php and the process is newline terminated lines. All commands must be newline terminated, and all responses are retrieved in units of lines. Don't forget the newlines, they're hard to identify afterward.
I am working on a project that uses Terminal A on machine A to output to Terminal B on Machine B, both using linux for now. I didnt see it mentioned, but perhaps you can use redirection, something like this in your webserver:
switch($_REQUEST['do'])
{ case 'test':
#process ID on the target (12345, 12346 etc)
echo system('/usr/local/bin/chbg -mt > /proc/<processID>/fd/1');
#OR
#device file on the target (pts/0,tty0, etc)
echo system('/usr/local/bin/chbg -mt > /dev/<TTY-TYPE>/<TTYNUM>');
break;
}
Definitely the permissions need to be set correctly for this to work. The command "mesg y" in a terminal may also assist...Hope that helps.

Read linux console PHP

I want to read the console logs of a process that is running, I currently have this
$output = shell_exec('pgrep tfs');
echo "<pre>$output</pre>";
And that returns me a random number like 34034
I've almost never worked with linux before so I dont really know how to do this.
You do realize that that's what pgrep does, right? It returns the process ID of the process you're asking about. So that's not a random number you're getting back. Your script is working perfectly.
Why don't you find the actual log file itself (usually in /var/logs) and use something like fopen to open and parse it?

pipe mail to PHP script : cant find the pip.php file

hi i'm trying to pipe incoming emails to php script
i did step by step from my manual but when i send an email i get this error from my delivery system :
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es)
failed:
pipe to |/home2/mimjobco/public_html/pipe.php
i chosse pipe.php address from cpanel so it cant be wrong
here is the picture !
here is my pipe.php code :
#!/usr/bin/php –q
<?php
require_once('class/support.php');
require_once('class/db.php');
$title = 'email_request';
$text = 'email_req_text';
$sup_id = 1 ;
$sup = new support;
$sup->title = $title;
$sup->part_id = $sup_id ;
$sup->text = $text;
$sup->email = 'email';
$sup->type = 1;
$sup->set_ticket();
mail('xxxx#gmail.com','new message recived','new message recived ');
i also set it's permission to 755
am i missing something ?
is there another thing that i should have done? someone had mention something about crone job ?!
The error message says "/home2/mimjobco/pipe.php", but the screenshot shows the file is in your "public_html" directory (presumably, "/home2/mimjobco/public_html/pipe.php").
Note that "pipe.php" should only be in "public_html" if you want it to be accessible on the website. Otherwise, it should go elsewhere in your home directory hierarchy (e.g. ~/bin/).
It looks like you are using bluehost, here is someone else who was able to fix the problem: http://www.bluehostforum.com/showthread.php?5786-Reading-email-with-php&p=26554#post26554
Setting up filter in cPanel, problem that delivery error coming back. Many solutions not available on a shared server.
Finally, this seems to work to avoid the error in delivery emails coming back - note the -q:
|/usr/bin/php -q /home/myacct/public_html/mydir/myfile.php
Solution came from http://forums.exocrew.com/index.php?showtopic=1838. (DEAD LINK)
The code for parsing emails being piped to the php file is at:
http://evolt.org/node/27914/
This gives you the message parsed as variables for subject, from, body etc.
Hope this helps!

PHP mail filtering script: exit codes not recognized in .qmail file

Short story
I've got a PHP script filtering incoming mail using a .qmail file. The script works perfectly well and logs all activity but, as far as I know, the last .qmail line shouldn't be executed when my script returns a dot-qmail exit code 99 that should stop processing further .qmail lines.
Long story:
I'm using a Parallels Plesk Panel version 9.3.0 under Linux 2.6.18-4-686.
My PHP CLI version is 5.2.0-8+etch16 (cli) (built: Nov 24 2009 11:14:47).
Not satisfied with Spamassassin, Dr. Web and zen.spamhaus.org and their results, I decided to create my own PHP script for filtering all incoming mail.
(An aside to some of you who might think "this guy is reinventing the wheel": I know my customers personally and their specific needs so, after thousands of tests, this turned out to be the best option because it avoids black box models and lets me control the process in a comprehensive way, also freeing server resources and opening doors to other cool functionality).
However I'm having a hard time installing the script at the server.
qmailfilter is my script and you can see it at http://titanpad.com/1IFDj1jvB0
I edited an existing .qmail file in /var/qmail/mailnames/customerdomain.com/username/.qmail to be:
|/var/my/qmailfilter/qmailfilter
|/usr/bin/deliverquota ./Maildir
qmailfilter PHP script executes and logs perfectly when I send a message to this user account, returns the exit code (99 for discarding message and 0 for proceeding to next .qmail line delivering the message).
Turns out that it delivers the message irrespectively of the many exit codes I've already tried.
The script (see line 174) outputs a text exit code without any whitespace before or after. I tried exit($code), print $code, echo($code) and even file_put_contents("php://stdout", $code), and also exit(chr($code)).
dot-qmail codes are:
0 - Success (go to next .qmail line)
99 - Success and abort (do not execute next lines)
100 - permanent error (bounce)
111 - soft error (retry later)
Source: The Big Qmail Picture.
Other attempts/experiments:
Removed the shebang line (#!/usr/bin/php) and changed the first .qmail line to |php -q /var/my/qmailfilter/qmailfilter
Checked the last line of the script for whitespacing
Read dot-qmail man file but nothing conclusive was found
Joined .qmail lines:
|/var/my/qmailfilter/qmailfilter |/usr/bin/deliverquota ./Maildir
In this case I got a message having only the proper return code without any header, subject or message body.
Commented out (#) the second .qmail line, but stopped receiving any kind of messages.
Edited /var/qmail/control/defaultdelivery to add a first line:
|php /var/my/qmailfilter/qmailfilter
|/usr/bin/deliverquota ./Maildir
and renamed user .qmail file to _qmail. Same results.
Should I deliver the message via PHP script and forget exit codes?
If so, is it enough to save the message to the user Maildir/new?
If so, is the message filename important?
Any idea will be appreciated. Thanks very much!
UPDATE: For those of you who need it, I published the final script at icebex.com slash qmailfilter
I only took a quick look at the code, but it looked like you were using string values. exit('99') and exit(99) are not the same. Make sure you use integers and not strings.
exit('99') will print 99 and return 0.
exit(99) will return 99.

Calling php from php through exec() gives no result

I have a PHP script that creates other PHP files based on user input. Basically, there are files containing language specific constants (define) that can be translated by the user. In order to avoid runtime errors, I want to test newly written files for parse errors (due to "unusual" character sequences). I have read several posts here on SO (like PHP include files with parse errors) and tried a function that uses
$output = exec("php -l $filename");
to determine whether a file parses correctly. This works perfectly on my local machine, but at on the provider's machine, the output of calls to exec("php ...") seems to be always empty. I tried a call to ls and it gives me output, leading me to the assumption that PHP is somehow configured to not react to command line invocations or so. Does anyone know a way around this?
EDIT: I forgot to mention, I had already tried shell_exec and it gives no result, either. In response to sganesh's answer: I had tried that too, sorry I forgot to mention. However, the output (second argument) will always be an empty array, and the return value will always be 127, no matter if the PHP file to test has syntax errors or not.
I had the same problem. The solution that worked for me was found in running-at-from-php-gives-no-output. I needed to add output redirection.
$output = exec("php -l $filename 2>&1");
You can try with exec second and third arguments.
second argument will have the output of the command.
third argument will have the return value.
And exec will return only last line of the command.
$filename = "a.php";
$output = exec("php -l $filename",$op,$ret_val);
print $output."\n";
print $ret_val."\n";
var_dump($op);
By executing shell_exec(), you can see the output as if you executed that file via command line. You can just see if there is an error right here.
<?php
if (strpos(shell_exec('php -l file.php'), 'Syntax Error')) {
die('An error!');
}
There may also be a possibility that shell_exec() or exec() may be disable by your host.
Nice idea to check the file validity :-)!
Now, from the PHP manual for exec():
Note: When safe mode is enabled, you can only execute files within the safe_mode_exec_dir. For practical reasons, it is currently not allowed to have components in the path to the executable.
Can you check if this is not the case for you?
Also, can you check by providing the full path of the PHP interpreter in the exec() instead of only php. Let me know how you fare.
Pinaki
the correct way is to add >2&1 as tested on a windows system using imagemagick!
I worked around my original problem by using a different method. Here is what I do now:
Write a temporary file with contents <?php include "< File to test >"; echo "OK"; ?>
Generate the correct URL for the temporary file
Perform HTTP request with this URL
Check if result equals "OK". If yes, the file to test parses without errors.
Delete temporary file
Maybe this could be done without the temporary file by issuing an HTTP request to the file to test directly. However, if there is a parse error and errors are suppressed, the output will be empty and not discernible from the output in the case of a file that gives no parse errors. This method is risky because the file is actually executed instead of just checked. In my case, there is only a limited number of users who have access to this functionality in the first place. Still, I'm naturally not entirely happy with it.
Why the exec() approach did not work, I still do not know exactly. pinaki might be right by suggesting to provide the full path to the PHP executable, but I cannot find out the full path.
Thank you everyone for answering, I upvoted you all. However, I cannot accept any of your answers as none of your suggestions really solved my problem.

Categories