I've got a script running when a certain email address receives an email, procmail pipes to a PHP script, which is then parsed by Plancake, not many problems there. I've got an if statement on strpos, depending on if the body contains a certain text. For some reason, when I add the MySQL code, the entire thing stops working. Unfortunately the way it's setup I'm not quite sure how to add error checking. Here's the code:
<?php
require_once("PlancakeEmailParser.php");
$rawEmail = '';
if (($fp = fopen('php://stdin', 'r')) !== false) {
while (!feof($fp)) {
$rawEmail .= fread($fp, 1024);
}
fclose($fp);
}
$emailParser = new PlancakeEmailParser($rawEmail);
$emailSubject = $emailParser->getSubject();
$emailBody = $emailParser->getPlainBody();
$emailHeader = $emailParser->getHeader('From');
$message = "FROM: ".$emailHeader."\n\nSubject: ".$emailSubject."\n\nBody: ".$emailBody;
$status = 4;
preg_match("/\d+/", "$emailSubject", $matches);
$number = $matches[0];
$short = substr($message, 0, strpos( $message, 'Begin'));
if (stripos($short,'approve') !== false) {
echo 'true';
$msg = approve;
//file_put_contents('/home/symantec_mail/task' . $number . 'short.php',$msg);
file_put_contents('/home/symantec_mail/task' . $number . 'approve_short_reply.txt',$message);
file_put_contents('/home/symantec_mail/task' . $number . 'approve_reply.txt',$rawEmail);
}
if (stripos($short,'complete') !== false) {
echo 'true';
$msg = complete;
when I uncomment the following mysqli code, everything stops.
//$mysqli = new mysqli("localhost", "user", "pass", "db");
//$update = $mysqli->prepare("UPDATE task_overview SET status = ? WHERE task_id = ?");
//$update->bind_param('ii', $status, $number");
//$update->execute();
rest of the code.
//file_put_contents('/home/symantec_mail/task' . $number . 'short.php',$msg);
file_put_contents('/home/symantec_mail/' . $number . 'complete_short_reply.txt',$message);
file_put_contents('/home/symantec_mail/' . $number . 'complete_reply.txt',$rawEmail);
}
?>
Really not sure why I can't execute these commands. I will point out that it's on a different shell account than my normal web server, although the PHP is still executing, I'm really not sure if I'm communicating with the MySQL server. Please if you have any suggestions, even if it's for error checking I'll greatly appreciate it.
Related
I'm trying to create a piece of code that will go into the mailbox and take out the attachments of a specific file. So far I am only able to view if there is an attachment or if there is not an attachment on the e-mail.
But I want it to be able to take the attachments out of the e-mail and then save them to a specified directory. The type of attachment I'm trying to take out is a .jpg
I've tried a bunch of different pieces of code that I've found on google and I've been trying to tailor it to fit into my code, but so far I have been unsuccessful in finding anything that works correctly.
I was wondering if anyone would be able to help me create a piece of code that would be able to take the attachments out of the emails and store them in a directory.
Thanks.
<?php
/* connect to email */
$hostname = '{*****.com:110/pop3}INBOX';
$username = '*****';
$password = '*****';
// try to connect
$inbox = imap_open($hostname,$username,$password) or die('Cannot connect to server: ' . imap_last_error());
// grab emails
$emails = imap_search($inbox,'ALL');
// Search for the 39th email, which has an attachment
$count = 39;
// Fetch all the information about an email
$attachment = imap_fetchstructure($inbox, $count);
// find out how may parts the object has
$numparts = count($attachment->parts);
// find if if multipart message
if ($numparts >= 2) {
foreach ($attachment->parts as $part) {
if ($part->disposition == "INLINE") {
// inline message. Show number of lines
printf("Inline message has %s lines<BR>", $part->lines);
} elseif ($part->disposition == "ATTACHMENT") {
// an attachment
echo "Attachment found!";
// print out the file name
echo "Filename: ", $part->dparameters[0]->value;
}
}
}
//}
else {
// only one part so get some useful info
echo "No attachment";
}
imap_close($imap);
?>
Instead of imap_search I used imap_check to retrieve messages overview, and the following worked.
Go over messages found with imap_check, and this is how you extract the binary data of attachment:
$mbox = imap_open( . . . . );
$IMAPobj = imap_check($inbox);
$start = $IMAPobj->Nmsgs-30;
$end = $IMAPobj->Nmsgs;
$result = imap_fetch_overview($inbox,"$start:$end",0);
$count = $end;
foreach ($result as $overview) {
$parts = mail_mime_to_array($inbox, $count);
foreach($parts as $part) {
if(#$part['filename'] || #$part['name'] ) {
$partName = $part['filename'] ? $part['filename'] : $part['name'];
echo "Attachment name is " . basename($partName);
echo "\n";
if(preg_match( . . . write here a regex to detect ".jpg" in $partName . . .)) {
echo "Found file! Extracting binary data...";
$fileContents = $part['data'];
file_put_contents("attachment.jpg", $fileContents);
}
}
}
}
I was looking for a practical way to detect file system changes. Than I found this pretty simple script from "Jonathan Franzone". But my problem is, it doesn't scan sub folders. Since I'm just a newbie in PHP, I would like to ask in here to have robust offers to solve.
Note: I made an extended search on site before writing. Many questions asked about this aproach to secure website. But no complete reply at all.
<?php
/**
* File : ftpMonitor.php
* Monitors a remote directory via FTP and emails a list of changes if any are
* found.
*
* #version June 4, 2008
* #author Jonathan Franzone
*/
// Configuration ///////////////////////////////////////////////////////////////
$host = 'ftp.domain.com';
$port = 21;
$user = 'username';
$pass = 'password';
$remote_dir = '/public_html';
$cache_file = 'ftp_cache';
$email_notify = 'your.email#gmail.com';
$email_from = 'email.from#gmail.com';
// Main Run Program ////////////////////////////////////////////////////////////
// Connect to FTP Host
$conn = ftp_connect($host, $port) or die("Could not connect to {$host}\n");
// Login
if(ftp_login($conn, $user, $pass)) {
// Retrieve File List
$files = ftp_nlist($conn, $remote_dir);
// Filter out . and .. listings
$ftpFiles = array();
foreach($files as $file)
{
$thisFile = basename($file);
if($thisFile != '.' && $thisFile != '..') {
$ftpFiles[] = $thisFile;
}
}
// Retrieve the current listing from the cache file
$currentFiles = array();
if(file_exists($cache_file))
{
// Read contents of file
$handle = fopen($cache_file, "r");
if($handle)
{
$contents = fread($handle, filesize($cache_file));
fclose($handle);
// Unserialize the contents
$currentFiles = unserialize($contents);
}
}
// Sort arrays before comparison
sort($currentFiles, SORT_STRING);
sort($ftpFiles, SORT_STRING);
// Perform an array diff to see if there are changes
$diff = array_diff($ftpFiles, $currentFiles);
if(count($diff) > 0)
{
// Email the changes
$msg = "<html><head><title>ftpMonitor Changes</title></head><body>" .
"<h1>ftpMonitor Found Changes:</h1><ul>";
foreach($diff as $file)
{
$msg .= "<li>{$file}</li>";
}
$msg .= "</ul>";
$msg .= '<em>Script by Jonathan Franzone</em>';
$msg .= "</body></html>";
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "To: {$email_notify}\r\n";
$headers .= "From: {$email_from}\r\n";
$headers .= "X-Mailer: PHP/" . phpversion();
mail($email_notify, "ftpMonitor Changes Found", $msg, $headers);
}
// Write new file list out to cache
$handle = fopen($cache_file, "w");
fwrite($handle, serialize($ftpFiles));
fflush($handle);
fclose($handle);
}
else {
echo "Could not login to {$host}\n";
}
// Close Connection
ftp_close($conn);
?>
Thanks for anyone have a solution or at least try to help.
EDIT: Actually I was willing to ask for deleting automatically but, I dont want to be too much demanding. Why not if it will not be a pain.
I want to retrieve email from gmails' imap server but the problem is that the responses from the server are multiple lines long (as demonstrated here) and fgets only retrieves one line.
I've tried using fgets, fread, socket_read but none of them work so either i'm using the wrong method or using the methods incorrectly. I also tried this tutorial but it didn't work either. I would appreciate if someone could help me with this.
Thanks and i'm really sorry if this is an amateur question.
Code:
<?php
$stuff = fsockopen('ssl://imap.gmail.com',993);
$reply = fgets($stuff,4096);
echo 'connection: '.$reply.'<br/>';
$request = fputs($stuff,"a1 LOGIN MyUserName Password\r\n");
$receive = socket_read($stuff, 4096);
echo 'login: '.$receive.'<br/>';
$request = fputs($stuff,"a2 EXAMINE INBOX\r\n");
$reply = '';
while(!feof($stuff))
$reply .= fread($stuff, 4096);
echo $reply;
/*
$request = fputs($stuff,'a3 FETCH 1 BODY[]\r\n');
$reply = fgets($stuff);
echo $reply;
*/
?>
Max's answer below works. This is my implementation of it.
private function Response($instructionNumber)
{
$end_of_response = false;
while (!$end_of_response)
{
$line = fgets($this->connection,self::responseSize);
$response .= $line.'<br/>';
if(preg_match("/$instructionNumber (OK|NO|BAD)/", $response,$responseCode))
$end_of_response = true;
}
return array('code' => $responseCode[1],
'response'=>$response);
}
Generally, you know to stop reading when you get the OK/BAD/NO response for the tag you sent. If you send a1 LOGIN ... you stop when you get a1 OK/BAD/NO ....
It's been a while since I wrote PHP, and I don't know that much about IMAP, but if it's anything like NNTP, your code would look a bit like this (wrote it in the SO editor, might be bugged) :
$buffer = '';
function read_line($socket) {
global $buffer;
while (strpos($buffer, "\n") === false)
$buffer .= fread($socket, 1024);
$lineEnd = strpos($buffer, "\n");
$line = substr($buffer, 0, $lineEnd-1);
$buffer = substr($buffer, $lineEnd);
return $line;
}
function send_line($socket, $line) {
fwrite($socket, $line);
}
$socket = fsockopen('ssl://imap.gmail.com',993);
$welcome = read_line($socket);
send_line("a1 LOGIN MyUserName Password\r\n");
$reply = read_line($socket);
send_line("a2 EXAMINE INBOX\r\n");
while (($reply = trim(read_line($socket))) != '.') {
echo $reply.PHP_EOL;
}
echo "Done";
The basic concepts are :
Always buffer all incoming data. PHP doesn't handle lines very well, so do the splitting yourself.
Don't randomly read everything, but know what to expect. You expect one welcome line, LOGIN has one reply, and EXAMINE INBOX keeps outputting data until there's a single dot, so immediately stop reading once you see that.
You'll most likely want a simple function to take care of the reading. You could even write another function to make it easy:
function read_block($socket) {
$block = '';
while ('.' != trim($reply = read_line($socket)) {
$block .= $reply;
}
return $block;
}
I have set email interception on my server.
following is my email forwarder set on server
testemail#my.server.com,"/home/server/php_pipe_mail.php"
following is my code for php_pipe_mail.php
#!/usr/bin/php -q
<?php
require_once('mimeDecode.php');
include('sql-connect.php');
error_reporting(E_ALL);
ob_start();
$raw_email = '';
if (!$stdin = fopen("php://stdin", "R"))
{
echo "ERROR: UNABLE TO OPEN php://stdin \n";
}
// ABLE TO READ THE MAIL
else
{
while (!feof($stdin))
{
$raw_email .= fread($stdin, 4096);
}
fclose($stdin);
}
$raw_email = preg_replace('/ +/', ' ', $raw_email);
var_dump($raw_email);
$buf = ob_get_contents();
$params['include_bodies'] = true;
$params['decode_bodies'] = true;
$params['decode_headers'] = true;
$params['input'] = $buf;
$params['crlf'] = "\r\n";
//Creating temp file on server
$myFile = "amail.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
fwrite($fh, $buf);
fclose($fh);
//Generating mail structure in object format
$structure = Mail_mimeDecode::decode($params);
$attachment = array();
$mail_date= date( 'Y-m-d H:i:s', strtotime($structure->headers['date']) );
$from = $structure->headers['from'];
$to = $structure->headers['to'];
$subject = htmlentities($structure->headers['subject'],ENT_QUOTES);
if($structure->ctype_primary == "multipart")
{
$body_text = $structure->parts[0]->parts[0]->body;
$body_html = $structure->parts[0]->parts[1]->body;
$x = 0;
//fetch attachment
foreach ($structure->parts as $part) {
// only save if an attachment
if (isset($part->disposition) and ($part->disposition=='attachment')) {
$attachment[$x]["filename"] = $part->d_parameters['filename'];
$attachment[$x]["content_type"] = $part->ctype_primary . "/" . $part->ctype_secondary;
$attachment[$x]["body"] = addslashes($part->body);
$x++;
}
}
}
else
{
$body_text = $structure->parts[0]->body;
$body_html = $structure->parts[1]->body;
}
$qry1 = "insert into mail_buffer(mail_date,mail_from, mail_to,mail_subject,mail_text_body,mail_html_body) Values('". $mail_date ."','".$from."','".$to."','".$subject."','".$body_text."','".$body_html."')";
mysql_query($qry1) or die(mysql_error($con));
$last_id = mysql_insert_id();
if(count($attachment) > 0)
{
for($i=0; $i < count($attachment); $i++)
{
$qry = "insert into mail_attachment(email_id,content_type, file_name,body) Values('". $last_id ."','".$attachment[$i]['content_type']."','".$attachment[$i]['filename']."','".$attachment[$i]['body']."')";
mysql_query($qry) or die(mysql_error($con));
}
}
mysql_close($con);
ob_end_clean();
?>
Now above script works perfectly fine.
I am able to fetch message header, body and attachments and can store them in database without any problems.
When email without attachments come everything works fine and email is delivered to email address I am intercepting.
But following is not working.
When email with attachments comes than email content is being stored in database but email is not delivering to email address I am intercepting and I am getting following error message in bounce back email.
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 |/home/server/php_pipe_mail.php
generated by testemail#my.server.com
Can anyone help me regarding the matter.
Thanks.
Could it be that, when an attachment is present, your script is echoing something? I have had problems piping emails before, and seen failure messages returned to senders, and they have been due to the piping script producing some kind of output. Maybe your error_reporting(E_ALL); is allowing the script to produce an output - try error_reporting(0);
I have a php script that steps through a folder containing tab delimited files, parsing them line by line and inserting the data into a mysql database. I cannot use LOAD TABLE because of security restrictions on my server and I do not have access to the configuration files. The script works just fine parsing 1 or 2 smaller files but when when working with several large files I get a 500 error. There do not appear to be any error logs containing messages pertaining to the error, at least none that my hosting provider gives me access to. Below is the code, I am also open to suggestions for alternate ways of doing what I need to do. Ultimately I want this script to fire off every 30 minutes or so, inserting new data and deleting the files when finished.
EDIT: After making the changes Phil suggested, the script still fails but I now have the following message in my error log "mod_fcgid: read data timeout in 120 seconds", looks like the script is timing out, any idea where I can change the timeout setting?
$folder = opendir($dir);
while (($file = readdir($folder)) !== false) {
$filepath = $dir . "/" . $file;
//If it is a file and ends in txt, parse it and insert the records into the db
if (is_file($filepath) && substr($filepath, strlen($filepath) - 3) == "txt") {
uploadDataToDB($filepath, $connection);
}
}
function uploadDataToDB($filepath, $connection) {
ini_set('display_errors', 'On');
error_reporting(E_ALL);
ini_set('max_execution_time', 300);
$insertString = "INSERT INTO dirty_products values(";
$count = 1;
$file = #fopen($filepath, "r");
while (($line = fgets($file)) !== false) {
$values = "";
$valueArray = explode("\t", $line);
foreach ($valueArray as $value) {
//Escape single quotes
$value = str_replace("'", "\'", $value);
if ($values != "")
$values = $values . ",'" . $value . "'";
else
$values = "'" . $value . "'";
}
mysql_query($insertString . $values . ")", $connection);
$count++;
}
fclose($file);
echo "Count: " . $count . "</p>";
}
First thing I'd do is use prepared statements (using PDO).
Using the mysql_query() function, you're creating a new statement for every insert and you may be exceeding the allowed limit.
If you use a prepared statement, only one statement is created and compiled on the database server.
Example
function uploadDataToDB($filepath, $connection) {
ini_set('display_errors', 'On');
error_reporting(E_ALL);
ini_set('max_execution_time', 300);
$db = new PDO(/* DB connection parameters */);
$stmt = $db->prepare('INSERT INTO dirty_products VALUES (
?, ?, ?, ?, ?, ?)');
// match number of placeholders to number of TSV fields
$count = 1;
$file = #fopen($filepath, "r");
while (($line = fgets($file)) !== false) {
$valueArray = explode("\t", $line);
$stmt->execute($valueArray);
$count++;
}
fclose($file);
$db = null;
echo "Count: " . $count . "</p>";
}
Considering you want to run this script on a schedule, I'd avoid the web server entirely and run the script via the CLI using cron or whatever scheduling service your host provides. This will help you avoid any timeout configured in the web server.