Magento custom controller action is called twice - php

I added a ajax add to cart to the rwd theme, and the action controller is called twice for every http request. Any help with solving the problem or debugging is welcome, I already lost 2 weeks on this. This all works on our development environment, but acts weird on staging. The dev environment is hosted locally on MAMP, staging is hosted on OVH shared hosting.
edit2: removed irrelevant info

found this error message in error.log
FastCGI: comm with server "/..../staging/index.php" aborted: error parsing headers: duplicate header 'Content-Type', referer: http://staging.xxxx.be/product.html
also found a solution here: http://blog.imseo.it/2014/09/08/magento-fastcgi-error-parsing-headers-duplicate-header/
The solution is to replace the function sendHeaders in
app/code/core/Mage/Core/Controller/Response/Http.php
public function sendHeaders()
{
if (!$this->canSendHeaders()) {
Mage::log('HEADERS ALREADY SENT: '.mageDebugBacktrace(true, true, true));
return $this;
}
if (in_array(substr(php_sapi_name(), 0, 3), array('cgi', 'fpm')))
{
// remove duplicate headers
$remove = array('status', 'content-type');
// already sent headers
$sent = array();
foreach (headers_list() as $header)
{
// parse name
if (!$pos = strpos($header, ':'))
continue;
$sent[strtolower(substr($header, 0, $pos))] = true;
}
// raw headers
$headersRaw = array();
foreach ($this->_headersRaw as $i=>$header)
{
// parse name
if (!$pos = strpos($header, ':'))
continue;
$name = strtolower(substr($header, 0, $pos));
if (in_array($name, $remove))
{
// check sent headers
if ($sent[$name])
{
unset($this->_headersRaw[$i]);
continue;
}
// check header
if (!is_null($existing = $headers[$name]))
{
$this->_headersRaw[$existing] = $header;
unset($this->_headersRaw[$i]);
}
else
$headersRaw[$name] = $i;
}
}
// object headers
$headers = array();
foreach ($this->_headers as $i=>$header)
{
$name = strtolower($header['name']);
if (in_array($name, $remove))
{
// check sent headers
if ($sent[$name])
{
unset($this->_headers[$i]);
continue;
}
// check header
if (!is_null($existing = $headers[$name]))
{
$this->_headers[$existing] = $header;
unset($this->_headers[$i]);
}
else
$headers[$name] = $i;
// check raw headers
if (!is_null($existing = $headersRaw[$name]))
unset($this->_headersRaw[$existing]);
}
}
}
parent::sendHeaders();
}

Related

php: inconsistent behaviour with HTTP headers

am testing lots of links on the same domain to see whether they exist or not. I am using the following code:
function get_http_response_code($url)
{
$headers = get_headers($url);
return substr($headers[0], 9, 3);
}
function getURLs()
{
foreach($allResults as $result)
{
$tempURL = 'http://www.doma.in/foo/'.$result.'/bar';
if(get_http_response_code($tempURL) != "404" && get_http_response_code($tempURL) != "500")
{
$URLs[] = $tempURL;
}
else
{
echo $tempURL.' could not be reached<br />';
}
return $URLs;
}
$URLs = getURLs();
The problem is, among the hundreds that do exist, the $URLs array contains URLs that do not exist (404); sometimes two, sometimes four, but every time it produces an HTTP/1.0 404 Not Found error. Why such variance? Is there a timeout I should be setting? Any help will be appreciated.
As I understand from Your code the problem is in mistake of variable $url
Try this.
...
foreach($allResults as $result)
{
$tempURL = 'http://www.doma.in/foo/'.$result['url'].'/bar';
...
$url changed to $result

PHP: Get http status code that own script just sent out via shutdown function

I have a shutdown function that checks to see if a redirect was just issued. From headers_list() I can get the headers sent and see the location header. My question is how would I figure out what http_response_code was used in the header() function. Headers list doesn't have the response code.
Example code to play around with. I don't use redirects in the example code, otherwise it would loop. Main thing is I would like to detect a 301 vs any other kind of redirect. This would be inside drupal (via drupal_goto using hook_exit); but the example code below shows the issue. I have no way of knowing what status number was passed to the browser via header().
<?php
register_shutdown_function('test');
if (mt_rand(0, 1)) {
header('X-test: junk 1', TRUE, 201);
}
else {
header('X-test: junk 0', TRUE, 202);
}
exit();
function test() {
if ($location = test_headers_contain('X-test: ')) {
// Would like to check the status code that was sent out
echo $location . '<br>';
$list = headers_list();
$txt = str_replace(' ', ' ', nl2br(htmlentities(print_r($list, TRUE))));
echo $txt;
}
}
function test_headers_contain($text) {
if (function_exists('headers_list')) {
$list = headers_list();
if (empty($list)) {
return FALSE;
}
foreach ($list as $header) {
$info = stristr($header, $text);
if ($info !== FALSE) {
return $info;
}
}
}
return FALSE;
}
?>
This code outputs this
X-test: junk 1
Array
(
[0] => X-Powered-By: PHP/5.2.10
[1] => X-test: junk 1
)
Revision 302033 added the function http_response_code in response to just the sort of issue you describe, but I'm not certain when it will be included in a release. It's not in 5.3.4. If you have access, you could build a patched version of PHP with this function added. If not, you could request it of whoever on your host does have access.

How to remove an email message in Maildir from PHP?

I'm going crazy with a little problem with Maildir and PHP.
I need to check the APACHE_RUN_USER's Maildir and parse delivery-status messages.
The problem removing message after reading; i noticed that Zend_Mail_Storage_Maildir->removeMessage() is still a stub.
try {
$mailbox = new Zend_Mail_Storage_Maildir( array('dirname' => '/home/' . $_ENV['APACHE_RUN_USER'] . '/Maildir/') );
foreach ($mailbox as $id => $message) {
// seen flag
if ($message->hasFlag(Zend_Mail_Storage::FLAG_SEEN)) { continue; }
//get the unique id
$uniqueid = $mailbox->getUniqueId($id);
//obtain message headers
$headers = $message->getHeaders();
//check if the original message was sent from this app and is a delivery-status
$result = strpos($message, $id_header);
if($result === false) { echo '1 mail skipped: ' . $uniqueid . '. <br />'; continue; }
$result = strpos($headers['content-type'], 'delivery-status');
//if no skip to the next mail
if($result === false) { echo '1 mail skipped: ' . $uniqueid . '. <br />'; continue; }
// if everything it's ok process it.
// clear results
$data = array();
// foreach line of message
foreach( preg_split('/(\r?\n)/', $message) as $line ){
//clear results
$matches = array();
//perform matches on textlines
if( preg_match('/^(.+)\:\s{0,1}(.+)$/', $line, $matches) ) {
//grab intrested headers
foreach( array('Action', 'Status', 'Remote-MTA', 'Diagnostic-Code', $id_header) as $header) {
if($matches[1] == $header) $data[$header] = $matches[2];
}
}
}
// *** I NEED TO DROP THE MESSAGE HERE ***
// not working code ***
$currentmessageid = $mailbox->getNumberByUniqueId($uniqueid);
$mailbox->removeMessage($currentmessageid);
// *** I NEED TO DROP THE MESSAGE HERE ***
// print out results
echo '<pre class="email">';
print_r( $data );
echo '</pre>';
}
} catch (Exception $e) {
echo $e;
}
How can I remove it by hand? Some workarounds?
Thanks.
Sorry , its not implemented yet !
check out issue tracker http://framework.zend.com/issues/browse/ZF-9574
its open issue till today but some comment might be helpful :
In order to delete an email from a
maildir or mbox storage one must use:
Zend_Mail_Storage_Writable_Maildir or
Zend_Mail_Storage_Writable_Mbox
There are historical reasons for this
and they should be addressed and
standardised. For now the above
classes must be used or an exception
will be thrown with a message that is
a bit misleading.
Please refer to:
http://framework.zend.com/issues/browse/ZF-9574
for more details.
In order of tawfekov answer I solved as follow:
Opening mailbox:
$mailbox = new Zend_Mail_Storage_Writable_Maildir( array('dirname' => '/home/' . $_ENV['APACHE_RUN_USER'] . '/Maildir/') );
Processing mail code:
foreach ($mailbox as $id => $message) {
$uniqueid = $mailbox->getUniqueId($id);
/* ... mail processing code ... */
// mark as read
$currentmessageid = $mailbox->getNumberByUniqueId($uniqueid);
$mailbox->setFlags($currentmessageid, array(Zend_Mail_Storage::FLAG_SEEN));
// or uncomment to delete it
//$mailbox->removeMessage($currentmessageid);
}

Fetching mail from a POP3 server using php

I am trying to fetch a mail from POP3 (I am using POP3 mail server and I am trying to fetch the mail content and store into a database table for my project.), but I can't find any PHP script for that, all are only for IMAP.
Do you know how to fetch mail from a POP3 server?
Thanks.
Somewhat surprisingly, PHP's imap library can be also used for working with POP3 mailboxes. Most of the advanced IMAP features won't work, of course (e.g. folders or fetching message parts), but the basic POP3 functionality is implemented.
The main difference is the option string that you're passing to imap_open - to quote that page:
// To connect to a POP3 server on port 110 on the local server, use:
$mbox = imap_open ("{localhost:110/pop3}INBOX", "user_id", "password");
Other than that, it's fair sailing - you won't need more than imap_open, imap_num_msg, imap_body, imap_delete and imap_close for basic POP3 access.
PHP's IMAP functions can deal with both IMAP and POP3 boxes.
These functions enable you to operate with the IMAP protocol, as well as the NNTP, POP3 and local mailbox access methods.
Be warned, however, that some IMAP functions will not work correctly with the POP protocol.
there is a User Contributed Note that provides an interesting snippet. You may want to take a look at it. I can't say anything about its quality but from the surface, it looks okay.
Below, the Contributed Note:
For all the people coming here praying for:
1) a dead-easy way to read MIME attachments, or
2) a dead-easy way to access POP3 folders
Look no further.
function pop3_login($host,$port,$user,$pass,$folder="INBOX",$ssl=false)
{
$ssl=($ssl==false)?"/novalidate-cert":"";
return (imap_open("{"."$host:$port/pop3$ssl"."}$folder",$user,$pass));
}
function pop3_stat($connection)
{
$check = imap_mailboxmsginfo($connection);
return ((array)$check);
}
function pop3_list($connection,$message="")
{
if ($message)
{
$range=$message;
} else {
$MC = imap_check($connection);
$range = "1:".$MC->Nmsgs;
}
$response = imap_fetch_overview($connection,$range);
foreach ($response as $msg) $result[$msg->msgno]=(array)$msg;
return $result;
}
function pop3_retr($connection,$message)
{
return(imap_fetchheader($connection,$message,FT_PREFETCHTEXT));
}
function pop3_dele($connection,$message)
{
return(imap_delete($connection,$message));
}
function mail_parse_headers($headers)
{
$headers=preg_replace('/\r\n\s+/m', '',$headers);
preg_match_all('/([^: ]+): (.+?(?:\r\n\s(?:.+?))*)?\r\n/m', $headers, $matches);
foreach ($matches[1] as $key =>$value) $result[$value]=$matches[2][$key];
return($result);
}
function mail_mime_to_array($imap,$mid,$parse_headers=false)
{
$mail = imap_fetchstructure($imap,$mid);
$mail = mail_get_parts($imap,$mid,$mail,0);
if ($parse_headers) $mail[0]["parsed"]=mail_parse_headers($mail[0]["data"]);
return($mail);
}
function mail_get_parts($imap,$mid,$part,$prefix)
{
$attachments=array();
$attachments[$prefix]=mail_decode_part($imap,$mid,$part,$prefix);
if (isset($part->parts)) // multipart
{
$prefix = ($prefix == "0")?"":"$prefix.";
foreach ($part->parts as $number=>$subpart)
$attachments=array_merge($attachments, mail_get_parts($imap,$mid,$subpart,$prefix.($number+1)));
}
return $attachments;
}
function mail_decode_part($connection,$message_number,$part,$prefix)
{
$attachment = array();
if($part->ifdparameters) {
foreach($part->dparameters as $object) {
$attachment[strtolower($object->attribute)]=$object->value;
if(strtolower($object->attribute) == 'filename') {
$attachment['is_attachment'] = true;
$attachment['filename'] = $object->value;
}
}
}
if($part->ifparameters) {
foreach($part->parameters as $object) {
$attachment[strtolower($object->attribute)]=$object->value;
if(strtolower($object->attribute) == 'name') {
$attachment['is_attachment'] = true;
$attachment['name'] = $object->value;
}
}
}
$attachment['data'] = imap_fetchbody($connection, $message_number, $prefix);
if($part->encoding == 3) { // 3 = BASE64
$attachment['data'] = base64_decode($attachment['data']);
}
elseif($part->encoding == 4) { // 4 = QUOTED-PRINTABLE
$attachment['data'] = quoted_printable_decode($attachment['data']);
}
return($attachment);
}
you can use pop3 e-mail client class which can Access to e-mail mailboxes using the POP3 protocol.
You will get each e-mail body part and can store it in database, even you can retrieve attached files without deleting the original mail in the inbox.
For more go to http://www.phpclasses.org/package/2-PHP-Access-to-e-mail-mailboxes-using-the-POP3-protocol.html
IF you have PHP build with IMAP support, it would be easy, see IMAP documentation (especially comments at this page) at http://php.net/manual/en/book.imap.php
UPDATE: to clarify my answer - as you see in the comments and function reference, PHP imap_* functions can be used also for pop3.
You can open a socket connection and send POP3 commands directly to your server to retrieve emails.
The code below opens a connection to the server, authenticates, requests a count of available messages, downloads them one by one, then deletes them from the server. During the interaction with the server, if an unexpected response is received, the connection is closed.
You should be able to alter the code below to get what you need.
Create a config.ini file and populate it like this:
pop3_host=your.pop3.host
pop3_user=youremailusername
pop3_pass=youremailpassword
Obviously substitute the values with your actual host, username and password. Then change the parse_ini_file parameter to point to your config.ini file.
<?php
$config = parse_ini_file('/path/to/config.ini');
$stream = fsockopen('ssl://' . $config['pop3_host'], 995, $error_code, $error_message);
if (!$stream) {
die('fsockopen ' . $error_code . ' ' . $error_message);
}
$s = fgets($stream);
if (substr($s, 0, 3) !== '+OK') {
quit('OPEN');
}
chat('USER ' . $config['pop3_user']);
chat('PASS ' . $config['pop3_pass']);
$s = chat('STAT');
$stat = explode(' ', $s);
if (count($stat) !== 3) {
quit('STAT+');
}
$n = (integer)$stat[1];
for ($i = 1; $i <= $n; $i++) {
chat('RETR ' . $i);
$file = fopen($i . '.msg', 'wb');
if (!$file) {
quit('FILE ' . $i);
}
while (true) {
$s = fgets($stream);
if ($s === '.' . "\r\n") {
fclose($file);
break;
}
fputs($file, $s);
}
chat('DELE ' . $i);
}
chat('QUIT');
fclose($stream);
function chat(string $command): string {
global $stream;
fputs($stream, $command . "\r\n");
$s = fgets($stream);
if (substr($s, 0, 3) !== '+OK') {
quit(explode(' ', $command)[0]);
}
return $s;
}
function quit(string $message): void {
global $stream;
fputs($stream, 'QUIT' . "\r\n");
$s = fgets($stream);
fclose($stream);
die($message);
}

Using PHP's IMAP library triggers Kaspersky's Antivirus

I just started today working with PHP's IMAP library, and while imap_fetchbody or imap_body are called, it is triggering my Kaspersky antivirus. The viruses are Trojan.Win32.Agent.dmyq and Trojan.Win32.FraudPack.aoda. I am running this off a local development machine with XAMPP and Kaspersky AV.
Now, I am sure there are viruses there since there is spam in the box (who doesn't need a some viagra or vicodin these days?). And I know that since the raw body includes attachments and different mime-types, bad stuff can be in the body.
So my question is: are there any risks using these libraries?
I am assuming that the IMAP functions are retrieving the body, caching it to disk/memory and the AV scanning it sees the data.
Is that correct? Are there any known security concerns using this library (I couldn't find any)? Does it clean up cached message parts perfectly or might viral files be sitting somewhere?
Is there a better way to get plain text out of the body than this? Right now I am using the following code (credit to Kevin Steffer):
function get_mime_type(&$structure) {
$primary_mime_type = array("TEXT", "MULTIPART","MESSAGE", "APPLICATION", "AUDIO","IMAGE", "VIDEO", "OTHER");
if($structure->subtype) {
return $primary_mime_type[(int) $structure->type] . '/' .$structure->subtype;
}
return "TEXT/PLAIN";
}
function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false) {
if(!$structure) {
$structure = imap_fetchstructure($stream, $msg_number);
}
if($structure) {
if($mime_type == get_mime_type($structure)) {
if(!$part_number) {
$part_number = "1";
}
$text = imap_fetchbody($stream, $msg_number, $part_number);
if($structure->encoding == 3) {
return imap_base64($text);
} else if($structure->encoding == 4) {
return imap_qprint($text);
} else {
return $text;
}
}
if($structure->type == 1) /* multipart */ {
while(list($index, $sub_structure) = each($structure->parts)) {
if($part_number) {
$prefix = $part_number . '.';
}
$data = get_part($stream, $msg_number, $mime_type, $sub_structure,$prefix . ($index + 1));
if($data) {
return $data;
}
} // END OF WHILE
} // END OF MULTIPART
} // END OF STRUTURE
return false;
} // END OF FUNCTION
$connection = imap_open($server, $login, $password);
$count = imap_num_msg($connection);
for($i = 1; $i <= $count; $i++) {
$header = imap_headerinfo($connection, $i);
$from = $header->fromaddress;
$to = $header->toaddress;
$subject = $header->subject;
$date = $header->date;
$body = get_part($connection, $i, "TEXT/PLAIN");
}
Your guess seems accurate. IMAP itself is fine. What you do with the contents is what's dangerous.
What's dangerous about virus e-mails is that users might open a .exe attachment or something, so bad attachments and potentially evil HTML are what's being checked. As long as your code handling attachments doesn't tell the user to open them and this is just automatic processing or whatever, you're good to go. If you're planning on outputting HTML contents, be sure to use something like HTML Purifier.
The AV is detecting these signatures as they pass through the networking stack, most likely. You should be able to tell the source of the detection from the messages Kaspersky is giving you.

Categories