PHP - text not added to a variable inside foreach loop - php

I have this code in my WordPress plugin, it's supposed to get some data from database and after that send emails to different adresses with a common subject but different email body.
<?php
$pdv_subject = "Confirmation links from" . date('d-m-Y', time());
//
$pdv_message_a = "Salut!\n";
$pdv_email_a = 'user#example.com';
$pdv_headers_a[] = 'Cc: user#example.com';
//
$pdv_message_b = "Ciao!\n";
$pdv_email_b = 'user#example.com';
$pdv_headers_b[] = 'Cc: user#example.com';
//
$pdv_message_p = "Hello!\n";
$pdv_email_p = 'user#example.com';
$pdv_headers_p[] = 'Cc: user#example.com';
//
foreach( $results as $key => $val ){
if(date('d-m-Y', $val['confirmed_at']) === date('d-m-Y', time()) && $val['pco'] === '650'){
$pdv_message_a .= $val['link'] . "\n";
}
//
if(date('d-m-Y', $val['confirmed_at']) === date('d-m-Y', time()) && $val['pco'] === '620'){
$pdv_message_b .= $val['link'] . "\n";
}
//
if(date('d-m-Y', $val['confirmed_at']) === date('d-m-Y', time()) && $val['pco'] === '660' ){
$pdv_message_p .= $val['link'] . "\n";
}
}
In the code I've omitted the wp_mail function, I've done a test and it's working fine. The only problem I have is that the $pdv_message_ that needs to be added inside the if statement will be not added, this will cause that the email will be sent without the links inside the body. I've done a var_dump() and I'm able to see the $val but why the links aren't added to the messages?

Aside from anything, I think I'd lay the code out like this
foreach( $results as $key => $val ){
if(date('d-m-Y', $val['confirmed_at']) === date('d-m-Y', time())) {
switch ($val['pco']) {
case '620':
$pdv_message_b .= $val['link'] . "\n";
break;
case '650':
$pdv_message_a .= $val['link'] . "\n";
break;
case '660':
$pdv_message_p .= $val['link'] . "\n";
break;
}
}
}
(I'm not suggesting this is an answer to your problem, but it looks a lot nicer IMO and saves repeating all those identical if clauses.)

Related

How to refactor a long function?

I have a function that prepares a receipt output. But since it has all kinds of conditions it ends up being very long and difficult to understand..
How would one go about refactoring this? Any ideas?
If I split this into 100 small functions would that really be better?
public static function prepare_receipt($printer)
{
if (self::hasItems($printer['id']))
{
$output = '';
if ($_POST['pre_receipt'])
{
$output .= "======== Pre receipt =======\n\n\n";
}
/**
* Time and table
*/
if ($_POST['isTakeaway'] || $_POST["isDeliveryGuys"] || $_POST["isBolt"]) {
$output .= "Table: " . $_POST['table'] . "\n";
$output .= "Floor: " . $_POST['floor'] . "\n";
$output .= "Time: " . $_POST['takeawayTime'] . "\n";
if ($_POST['order_comment']) {
$output .= "Comment: " . removeSpecialChars($_POST['order_comment']) . "\n";
}
} else {
$output .= "Table: " . $_POST['table'] . "\n\n";
$output .= "Floor: " . $_POST['floor'] . "\n\n";
if ($_POST['order_comment']) {
$output .= "Comment: " . removeSpecialChars($_POST['order_comment']) . "\n";
}
}
$output .= "------------------------\n";
/**
* Food items
*/
foreach ($_POST['orderedItems'] as $orderedItem)
{
$has_unprinted_quantity = false;
if (isset($orderedItem['last_printed_quantity'])) {
$unprinted_quantity_count = intval($orderedItem['is_printed_quantity']) - intval($orderedItem['last_printed_quantity']);
if ($unprinted_quantity_count > 0) {
$has_unprinted_quantity = true;
}
}
if ( ($orderedItem['should_print'] &&
!$orderedItem['is_printed'] &&
$orderedItem['is_visible']) ||
$_POST['pre_receipt'] ||
$has_unprinted_quantity)
{
if (is_array($orderedItem['printers'])) {
$in_printer = in_array($printer['id'], $orderedItem['printers']);
} else {
$in_printer = in_array($printer['id'], json_decode($orderedItem['printers'], true));
}
if ( $in_printer || $_POST['pre_receipt'] )
{
if ($orderedItem['is_sidedish'] && !$_POST['pre_receipt']) {
continue;
}
if ($has_unprinted_quantity) {
$output .= $unprinted_quantity_count . 'x ';
} else {
$output .= $orderedItem['quantity'] . 'x ';
}
// We ned to split it for multiple lines...
$itemDescriptionParts = self::split($orderedItem['description']);
foreach ($itemDescriptionParts as $itemDescription) {
$itemDescriptionClean = removeSpecialChars($itemDescription);
$output .= $itemDescriptionClean;
}
// Add price for pre receipt
if ($_POST['pre_receipt']) {
$output .= " - " . number_format($orderedItem['price_with_discount'], 2, '.', ',');
}
if (!$_POST['pre_receipt']) {
if ($orderedItem['comments'] != '') {
$output .= " > " . removeSpecialChars(substr($orderedItem['comments'], 0, 27)) . "\n";
}
}
/** Side dishes */
if (isset($orderedItem['side_dishes']) && !$_POST['pre_receipt'])
{
foreach ($orderedItem['side_dishes'] as $side_dish) {
$output .= "\n + " . removeSpecialChars(substr($side_dish['description'], 0, 27)) . "\n";
}
}
$output .= "\n";
}
}
}
/**
* Sums
*/
/**
* Footer
*/
$output .= "------------------------\n";
if ($_POST['pre_receipt'])
{
$output .= "\nSubtotal: " . number_format($_POST['order']['subtotal'], 2, '.', ',') . "\n";
$output .= "Discount: " . number_format($_POST['order']['discount'], 2, '.', ',') . "\n";
$output .= "Total: " . number_format($_POST['order']['total'], 2, '.', ',') . "\n\n";
}
$output .= "Time: " . getTime() . "\n";
return $output;
}
else
{
return 'EMPTY';
}
}
Any pointers in the right direction would be much appreciated.
Refactoring works often well, if it follows semantics. In your case: You made already comments for different sections. This is often a sign for a function on it's own.
Just to give you an idea: How it may look like afterwards:
$output .= create_headline(...);
$output .= create_time_table(...);
$output .= create_separator();
foreach ($_POST['orderedItems'] as $orderedItem) {
$output .= create_food_item($orderedItem, $_POST['pre_receipt'], ...);
}
$output .= create_separator();
$output .= create_footer(...);
This will save time when searching for a bug in a certain area of the receipt.
I would advice https://en.wikipedia.org/wiki/Divide-and-conquer_algorithm, and your function already has comment that indicates how this function can be divided in multiple that has a single responsability.
I would also advice not to use $_POST directly, all input data must always be validated and possibly filtered. Data from input should be passed as dependency, to adhere dependency injection, see https://phptherightway.com/ for other good practices.
I would also avoid the use of string concatenation, store all the parts within an array and then join/implode them using a separator.
Looking at your code smart use of ternary operators and shifting the orderitem loop into different function can drastically reduce your code length by half. There is no need to create function for each operation like printing head, printing tail etc as the logic in those print is pretty simple and your code can prettry muddy and difficult to navigate if there are large number of unwanted functions. You can do something like below. Also note using . (dot) operator for string concatenation make your string less readable hence prefer printing variables with {} operator.
<?php
public static function prepare_receipt($printer)
{
if (self::hasItems($printer['id']))
{
$output = isset($_POST['pre_receipt']) ? "======== Pre receipt =======\n\n\n" : "" ;
//addiing time table
$output .= "Table: {$_POST['table']}. \n Floor: {$_POST['floor']}. \n";
//adding time if it is takeaway or isDeliveryGuys or isBolt
$output .= ($_POST['isTakeaway'] || $_POST["isDeliveryGuys"] || $_POST["isBolt"]) ? "Time: {$_POST['takeawayTime']}. \n" : "" ;
//adding order comment
$output .= $_POST['order_comment']) ? "Comment: {removeSpecialChars($_POST['order_comment'])} \n" : "" ;
//print order items
this->getOrderItems($_POST[orderedItems], &$output);
// footer
$output .= "------------------------\n";
if ($_POST['pre_receipt'])
$output .= "\nSubtotal: {number_format($_POST['order']['subtotal'], 2, '.', ',')} \n Discount: { number_format($_POST['order']['discount'], 2, '.', ',') } \n Total: {number_format($_POST['order']['total'], 2, '.', ',')} \n\n";
$output .= "Time: " . getTime() . "\n";
return $output;
}
else
{
return 'EMPTY';
}
}
?>
.

Remove empty fields in an array after foreach in PHP

I am new to PHP. This is my code from our mailing.php. When a user submits a request, there are 5-7 select-able fields and 20-25 fields that end up not being selected. The output lists all fields and values regardless of whether they are empty or have been selected. I understand I need to use either unset or array_filter, but cannot figure out how and where I need to insert into code.
if($_POST && count($_POST)) {
$body = '';
foreach($_POST as $key=>$value)
$body .= $key . ": " . $value . "\r\n";
mail("email#email.com", "Email Received at email#email.com", $body);
You can try this
if($_POST && count($_POST)) {
$_POST = array_filter($_POST);
$body = '';
foreach($_POST as $key=>$value)
$body .= $key . ": " . $value . "\r\n";
mail("email#email.com", "Email Received at email#email.com", $body);
OR
if($_POST && count($_POST)) {
$body = '';
foreach($_POST as $key=>$value){
$trim_value = trim($value);
if (!empty($trim_value)){
$body .= $key . ": " . $value . "\r\n";
}
}
mail("email#email.com", "Email Received at email#email.com", $body);
Just before foreach loop you should use this
$_POST = array_filter($_POST);
Another option is to use a conditional inside foreach loop
foreach($_POST as $key=>$value)
if ($value != '' && $value != null)
$body .= $key . ": " . $value . "\r\n";

Prepared PHP statement not printing out

I have a statement that is grabbing information from the database, and then is printed out after it is fully prepared.. For some reason though, my script is not printing out the information. I have it in this if statement:
if($community == ''){ print $community . "\n\n" . "END" . "\n"; } else { print $community; echo "hi";}
This prints out when it is ran:
() wrote:
But that is all it prints out. That is coming from the 8th $community .= line. So, my question is, why is it ONLY printing out () Wrote: and not all the variables as well?
// and ticker_symbol ='".$sym."'
$c_sql = "SELECT message_id, subject, author, FROM_UNIXTIME(datestamp,'%m-%d-%Y') AS formatted_datestamp, forum_id, body, thread, user_id FROM phorum_messages WHERE user_id=13423720 ORDER BY datestamp DESC LIMIT 5";
$c_result = mysql_query($c_sql,$connection) or die("Couldn't execute get query");
// Declare Variables
$body = $c_result['body'];
$forum_id = $c_result['forum_id'];
$user_id = $c_result['user_id'];
$author = $c_result['author'];
$formatted_datestamp = $c_result['formatted_datestamp'];
// Prepare the statement
if ($c_result != "") {
$community .= $forumPost = '<<<ENDL '. "\n";
$community .= $body . "\n";
$community .= 'ENDL;' . "\n";
$community .= '$forumPost = stripBBCode(strip_tags($forumPost));' . "\n";
$community .= "\n";
$community .= '<div class="comment">' . "\n";
$community .= '<table cellspacing="0" cellpadding="0" border="0" class="reply"><tbody><tr>' . "\n";
$community .= '<td width="90%"><b>'.$author.' ('.$formatted_datestamp.') wrote:</b><br />' . "\n";
$community .= '<p>'.iconv("ISO-8859-1//TRANSLIT", "UTF-8", $forumPost).'</p></td>' . "\n";
$community .= '</tr></tbody></table>'. "\n";
$community .= '</div>' . "\n";
}
// Print out the prepared statement
if($community = ''){ print $community . "\n\n" . "END" . "\n"; } else { print $community;}
When you are calling if($community = ''){ you only have one equals sign which will set $community to a blank string.
I think what you mean to do is if($community == ''){
It should have the double-equal:
if($community == '')
With a single = sign you're simply assigning an empty string to variable $community - and then checking whether it's true. Empty strings evaluate to false, hence you're getting into your else part - and losing your value in the process.
You only have one = sign
you need:
if($community == '') { etc...

Opening e-mail with PHP IMAP

A user over at w3schools forums assisted me with some code on using IMAP functions to check my mail inbox on a private server and do what i like with it, i created my own set of functions for posting the e-mail content to a MySQL table.
Could somebody help me find a solution to how can i open the e-mail inbox, check for e-mails in the inbox (There will be only one there because previous emails will be automatically deleted. Define the open e-mail message as $open_email_msg
Allow me to initiate my set of commands for posting the e-mail to a MySQL table, then delete the e-mail and close the inbox?
This is the code the person assisted me with:
<?php
$now = time(); // current time
$mailbox = '{192.168.150.11:143/imap/novalidate-cert}'; // see http://www.php.net/manual/en/function.imap-open.php
$mbox = imap_open($mailbox, 'username', 'password'); // log in to mail server
if (!$mbox)
echo ('Failed opening mailbox<br>' . print_r(imap_errors(), true)); // remove the print_r for production use
else
{
$box = imap_check($mbox); // get the inbox
for ($imap_idx = 1; $imap_idx <= $box->Nmsgs; $imap_idx++) // loop through the messages
{
$headers = imap_headerinfo($mbox, $imap_idx); // http://www.php.net/manual/en/function.imap-headerinfo.php
$raw_headers = imap_fetchheader($mbox, $imap_idx); // http://www.php.net/manual/en/function.imap-fetchheader.php
$selected_headers = '';
$text_part = '';
$html_part = '';
$original_message = imap_body($mbox, $imap_idx); // save the copy of the entire thing, attachments and all
// build selected headers string
for ($ii = 0; $ii < count($headers->from); $ii++)
$selected_headers .= 'From: ' . $headers->from[$ii]->mailbox . '#' . $headers->from[$ii]->host . "\n";
for ($ii = 0; $ii < count($headers->to); $ii++)
$selected_headers .= 'To: ' . $headers->to[$ii]->mailbox . '#' . $headers->to[$ii]->host . "\n";
for ($ii = 0; $ii < count($headers->cc); $ii++)
$selected_headers .= 'Cc: ' . $headers->cc[$ii]->mailbox . '#' . $headers->cc[$ii]->host . "\n";
for ($ii = 0; $ii < count($headers->bcc); $ii++)
$selected_headers .= 'Bcc: ' . $headers->bcc[$ii]->mailbox . '#' . $headers->bcc[$ii]->host . "\n";
if (!empty($headers->date))
$selected_headers .= 'Date: ' . $headers->date . "\n";
if (!empty($headers->subject))
$selected_headers .= 'Subject: ' . $headers->subject . "\n";
// see below; getMsg uses global variables
getMsg($mbox, $imap_idx);
$text_part = $plainmsg; // text portion of the email
$html_part = $htmlmsg; // html portion of the email
// check for text portion first
$msg_text = trim(strip_tags($plainmsg
Try this code to read emails.
$username="yourusername#yourmailhost.com";
$password="yourPassword123!";
$hostname="{imap.hostinger.com:993/imap/ssl}INBOX";
$imap=imap_open($hostname,$username,$password) or die('Cannot connect: '.imap_last_error());
$message_count = imap_num_msg($imap);
echo "<b>$message_count messages</b><br>";
for ($i = 1; $i <= $message_count; ++$i){
$header = imap_header($imap, $i);
$body = imap_fetchbody($imap, $i, '2');
$prettydate = date("jS F Y", $header->udate);
if(isset($header->from[0]->personal)){
$personal = $header->from[0]->personal;
}else{
$personal = $header->from[0]->mailbox;
}
$subject=$header->Subject;
$email = "$personal <{$header->from[0]->mailbox}#{$header->from[0]->host}>";
echo "On $prettydate, $email said \"$body\".\n";
echo '<br><br>';
}
print_r(imap_errors());
imap_close($imap);
I believe this link will help you as I used this myself and this is properly working for me.
There you can register and download the code, using it is simple.
Or what you can do if you want to get the information of header only is:
$mbox = imap_open("{xyz#abc.com:995/pop3/ssl/novalidate-cert}INBOX", 'abc#xyz.com', 'pass')
or die("can't connect: " . imap_last_error());
$MC = imap_check($mbox);
$result = imap_fetch_overview($mbox,"1:{$MC->Nmsgs}",0);
foreach ($result as $overview) {
echo "#{$overview->msgno} ({$overview->date}) - From: {$overview->from}
{$overview->subject}\n";
echo "<br>";
}

PHP script performance issue

There seems to be a performance issue with the script as it is really slow. I was wondering what I could do to speed this up. If you have any ideas, please let me know. I can't seem to figure it out.
Below is the code:
<?php
include_once("connect.php.inc");
class HtmlEnc{
static function uniord($c) {
$ud = 0;
if (ord($c{0}) >= 0 && ord($c{0}) <= 127) $ud = ord($c{0});
if (ord($c{0}) >= 192 && ord($c{0}) <= 223) $ud = (ord($c{0})-192)*64 + (ord($c{1})-128);
if (ord($c{0}) >= 224 && ord($c{0}) <= 239) $ud = (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128);
if (ord($c{0}) >= 240 && ord($c{0}) <= 247) $ud = (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128);
if (ord($c{0}) >= 248 && ord($c{0}) <= 251) $ud = (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128);
if (ord($c{0}) >= 252 && ord($c{0}) <= 253) $ud = (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128);
if (ord($c{0}) >= 254 && ord($c{0}) <= 255) $ud = false; // error
return $ud;
}
static function toHtml($str){
$html_str = "";
while (strlen($str) > 0) {
preg_match("/^(.)(.*)$/u", $str, $match);
$test = utf8_decode($match[1]);
if ($test != "?") {
$html_str .= htmlentities(htmlentities($test));
} else if (strlen($match[1]) > 1) {
$html_str .= "&#".self::uniord($match[1]).";";
} else $html_str .= htmlentities(htmlentities($match[1]));
$str = $match[2];
}
return $html_str;
}
}
/*
List of mail servers
*/
function alreadyDone($domain){
$domain = strtolower($domain);
$qry = "SELECT * FROM emdb WHERE domain ='" . $domain . "'";
$result = mysql_query($qry);
return (mysql_num_rows($result)!=0);
}
$template_fn = $_REQUEST['template'];
//"mail_template.html";
$keywords = HtmlEnc::toHtml($_REQUEST['Keywords']);
$keywords = str_replace("&","&",$keywords);
$domain = $_REQUEST['Domain'];
$rank = $_REQUEST['Rank'];
$to = $_REQUEST['Email'];
$adminEmail = "test#example.com";
if (!alreadyDone($domain)) {
if ($to=="") {
$to = "info#" . $domain;
}
function int_divide($x, $y) {
if ($x == 0) return 0;
if ($y == 0) return FALSE;
return ($x - ($x % $y)) / $y;
}
$page = int_divide($rank,10) + 1;
if ($template_fn == "mail_template_nick.html" || $template_fn == "mail_template_chet.html" || "mail_template_salesperson.php")
$subject = $domain." is on Page ".$page." of Google - Want to be #1?";
elseif ($template_fn == "seo_template.html")
$subject = "Outsource your SEO - Lowest rates guaranteed!";
elseif ($template_fn == "adwords_template.html")
$subject = $domain . " - Save your money on Google Adwords";
else $subject = $domain . " is ranked " . $rank . " on Google - Be 1st!";
$message = file_get_contents($template_fn);
/*$message = "<body>
<p>Hi There,</p>
<p>How's your week been so far?</p>
<p>When I Googled "{KEYWORD}", I found {WEBSITE} on page {PAGE}, not on page 1. This means consumers will find your competitors before they find you!</p>
<p>93% of all people, never go past the 1st page of Google, so at this very moment you're losing sales & leads to a competitor. </p>
<p>If you agree your Google exposure needs drastic improvement, please call me for a chat, I'm sure I can give some good, free advice. </p>
<p> </p>
<p><strong>Best Regards,</strong></p>
<p><strong>Kayne Chong </strong><strong>- Business Development Director</strong></p>
<p><strong>Tel:</strong> | <strong>Fax: </strong><br />
<strong>Office:</strong> <br />
<strong>Web:</strong> <a href='http://www.seoagency.com.sg/' target='_blank'><em>www.seoagency.com.sg</em></a><br />
<strong><em>Web marketing that brings BUSINESS to you!</em></strong></p>
</body>";*/
$message = str_replace("{WEBSITE}", $domain , $message);
$message = str_replace("{PAGE}", $page , $message);
//$message = str_replace("{RANK}", $rank , $message);
$message = str_replace("{KEYWORD}", $keywords , $message);
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
// Additional headers
/*$headers .= 'Bcc: ' . $adminEmail . "\r\n";
if ($template_fn == "mail_template_salesperson.php")
{ $headers .= 'From: Kayne - Web Marketing Experts <test#example.com>' . "\r\n";
$headers .= 'Reply-To: test#example.com' . "\r\n";}
elseif ($template_fn == "mail_template_chet.html")
{ $headers .= 'From: Chester - Web Marketing Experts <test#example.com>' . "\r\n";
$headers .= 'Reply-To: test#example.com' . "\r\n";}*/
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
$headers .= 'Bcc: ' . $adminEmail . "\r\n";
$headers .= 'From: Info - Web Marketing Experts <test#example.com>' . "\r\n";
$headers .= 'Reply-To: test#example.com' . "\r\n";
if (mail($to, $subject, $message, $headers)) {
echo "Mail successfully sent to $to and $adminEmail";
} else echo "Mail sending failed!";
$qry = "INSERT INTO emdb (domain, keywords, rank, last, count) VALUES ('$domain','$keywords','$rank',CURDATE(), '1')";
mysql_query($qry) or die(mysql_error());
echo "<BR />";
echo "DB updated";
} else {
echo "Domain name $domain has already been processed";
}
?>
Thank you.
Jae
Replace every string concatenation with the "." operator with an array push, for example array [ ] = "foo" and then return a string concatenation implode ( array );
Use ob_start(); to cache the output:
ob_start();
echo $a,$b,$c;
$str = ob_get_contents();
ob_end_clean();
You can optimize if to switch and change the order to your expected result. For example if result a is more likely then result b the condition to catch result a should be the first condition.
Put a primary key and secondary key on your table(s).
1.1) Don't use a glue and don't add the construction of the array to the time. Here is a benchmark for http://www.sitecrafting.com/blog/php-string-concat-vs-array
1.2) http://dan.doezema.com/2011/07/php-output-profiling-echo-vs-concat ( although echo is fastest concat is slower then array and also he uses a glue!
1.3) https://stackoverflow.com/questions 1.4) http://www.sitepoint.com/high-performance-string-concatenation-in-php/
Here are my results (30000 strings, time in milliseconds) (Script is taken from 1.4):
standard: 0.02418089
implode w/ glue: 0.00435901
implode w/o glue: 0.02205801
foreach: 0.02081609
Conclusion: use implode with glue.
Your toHtml() is pointless (not to mention it's implemented poorly hence the low performance), you don't need to convert every unicode character to &#...; notation, just put this in your <head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
and print utf-8 strings as they are, your browser will know how to deal with them.

Categories