Processwire/API hook (PHP function inside a function) - php

I'm writing a hook using the ProcessWire API... pretty common practice with it's powerful API.
The below works completely fine...
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
$arguments = $event->arguments();
$page = $event->arguments(0);
if ($page->template == 'user') {
// Require relevent libraries
require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');
// SendGrid API init
$sgAPIKey = "XXXX";
// Set email confirmation settings
$email_admin = 'test#example.com';
$email_customer = $page->email;
$email_admin_subject = "You added a new user $page->name";
$email_customer_subject = 'Your login details';
$from = new \SendGrid\Email("Example User", $email_admin);
$subject = "Sending with SendGrid is Fun";
$to = new \SendGrid\Email("Example User", $email_customer);
$content = new \SendGrid\Content("text/plain", "and easy to do anywhere, even with PHP");
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
// Dump SendGrid object with TracyDebugger
bd($mail);
}
});
However, as soon as I add a function to send the email (in order to set up two separate send mail functions (one to admin, one to customer) it doesn't work at all. No errors... just $mail returns NULL.
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
$arguments = $event->arguments();
$page = $event->arguments(0);
if ($page->template == 'user') {
// Require relevent libraries
require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');
// SendGrid API init
$sgAPIKey = "XXXX";
// Set email confirmation settings
$email_admin = 'test#example.com';
$email_customer = $page->email;
$email_admin_subject = "You added a new user $page->name";
$email_customer_subject = 'Your login details';
$email_customer_body = 'This is a test';
function send_email($from_email, $to_email, $subject, $body) {
global $sgAPIKey;
$from = new \SendGrid\Email(null, $from_email);
$to = new \SendGrid\Email(null, $to_email);
$content = new \SendGrid\Content("text/html", $body);
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
}
send_email($email_admin, $email_customer, $email_customer_subject, $email_customer_body);
// Dump SendGrid object with TracyDebugger
global $mail;
bd($mail);
}
});
Is there any reason why a function like this wouldn't work? Is it because technically there's a function inside a function? I would've at least have thought it would've returned an error.

Functions inside of functions are allowed in PHP, however the issue that you are experiencing is more of an issue with scoping. $mail is no longer in scope after that function is completed, meaning, among other things, that you can no longer access that variable.
One possible solution is to return that variable when the function completes, like so:
function send_email($from_email, $to_email, $subject, $body) {
global $sgAPIKey;
$from = new \SendGrid\Email(null, $from_email);
$to = new \SendGrid\Email(null, $to_email);
$content = new \SendGrid\Content("text/html", $body);
$mail = new \SendGrid\Mail($from, $subject, $to, $content);
$sg = new \SendGrid($sgAPIKey);
$response = $sg->client->mail()->send()->post($mail);
return $mail;
}
That way, when you execute the function, you can set it to a variable.
As an aside, I noticed you attempted to use the global keyword to access that $mail variable. Not only is that typically frowned upon as bad practice, it would never work in this context. The global keyword is used to make variables that are in the global namespace accessable. The typical use is as follows:
$global_variable = "foobar";
class Foo {
public static function test() {
return $global_variable;
}
public static function test_two() {
global $global_variable;
return $global_variable;
}
}
echo(Foo::test()); //echoes nothing, since in scope, the variable is not set
echo(Foo::test_two()); //echoes 'foobar', since we told PHP to put it in scope
TLDR: The global keyword makes variables that are in the global scope, be visible in the local scope.

Related

Joomla: onContentAfterSave not triggered for articles

I'm developing a Joomla plugin with onContentAfterSave event to send an email after saving a new articles.
the event are triggered when i save a new menu item or a new category.
but not for new article.
Joomla! 3.7.5
public function onContentAfterSave($context, $article, $isNew){
$link = JRoute::_(ContentHelperRoute::getArticleRoute( $article->id, $article->catid ));
$mailer = JFactory::getMailer();
$config = JFactory::getConfig();
$sender = array(
$config->get( 'mailfrom' ),
$config->get( 'fromname' )
);
$mailer->setSender($sender);
$user = JFactory::getUser();
$recipient = $user->email;
$recipient = array($recipient);
$mailer->addRecipient($recipient);
$body = '<p>Bonjour</p>'
.'Un nouveau article a été ajouté.';
$mailer->isHtml(true);
$mailer->Encoding = 'base64';
$mailer->setSubject('Nouveau article - BBN Times');
$mailer->setBody($body);
$send = $mailer->Send();
if ( $send !== true ) {
echo 'Error sending email: ';
} else {
echo 'Mail sent';
}
return true;
}
The onContentAfterSave is triggered by the Joomla core, and not by the extension's model, which means it should be triggered by any content saving.
I can think of 2 reasons why it is not triggered in your case:
You have a condition in your constructor checking for the extension type and only allowing certain extensions to use that event (or somewhere else in your plugin).
You have an error in the code above.

add html ouput in joomla email

i am trying to set html on the output of the email send by joomla. my file is located in the joomla core.
i know i have to add something like ->isHTML(true); but i do not know where and how.
here is the code:
class MailtoController extends JControllerLegacy
{
/**
* Show the form so that the user can send the link to someone.
*
* #return void
*
* #since 1.5
*/
public function mailto()
{
$session = JFactory::getSession();
$session->set('com_mailto.formtime', time());
$this->input->set('view', 'mailto');
$this->display();
}
public function send()
{
// Check for request forgeries
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
$app = JFactory::getApplication();
$session = JFactory::getSession();
$timeout = $session->get('com_mailto.formtime', 0);
if ($timeout == 0 || time() - $timeout < 1)
{
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
$SiteName = $app->get('sitename');
$link = MailtoHelper::validateHash($this->input->get('link', '', 'post'));
// Verify that this is a local link
if (!$link || !JUri::isInternal($link))
{
// Non-local url...
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
// An array of email headers we do not want to allow as input
$headers = array (
'Content-Type:',
'MIME-Version:',
'Content-Transfer-Encoding:',
'bcc:',
'cc:'
);
// An array of the input fields to scan for injected headers
$fields = array(
'mailto',
'sender',
'from',
'subject',
);
/*
* Here is the meat and potatoes of the header injection test. We
* iterate over the array of form input and check for header strings.
* If we find one, send an unauthorized header and die.
*/
foreach ($fields as $field)
{
foreach ($headers as $header)
{
if (strpos($_POST[$field], $header) !== false)
{
JError::raiseError(403, '');
}
}
}
/*
* Free up memory
*/
unset ($headers, $fields);
$email = $this->input->post->getString('mailto', '');
$sender = $this->input->post->getString('sender', '');
$from = $this->input->post->getString('from', '');
$subject_default = JText::sprintf('COM_MAILTO_SENT_BY', $sender);
$subject = $this->input->post->getString('subject', $subject_default);
// Check for a valid to address
$error = false;
if (!$email || !JMailHelper::isEmailAddress($email))
{
$error = JText::sprintf('COM_MAILTO_EMAIL_INVALID', $email);
JError::raiseWarning(0, $error);
}
// Check for a valid from address
if (!$from || !JMailHelper::isEmailAddress($from))
{
$error = JText::sprintf('COM_MAILTO_EMAIL_INVALID', $from);
JError::raiseWarning(0, $error);
}
if ($error)
{
return $this->mailto();
}
// Build the message to send
$msg = JText::_('COM_MAILTO_EMAIL_MSG');
$link = $link;
//$body = sprintf($msg, $SiteName, $sender, $from, $link);
$body = "<p>Hello Test F,</p><br/><p>Thank you for registering at Deals&offers. Your account is created and activated.</p><br/>You may login to ".$SiteName." using the following username and password:</br><p>Username: ".$sender."</p><p>Password: ".$from."/p><br/><p><b>Note:</b> It is recomended to change your password after first login. ".$link."</p>";
// Clean the email data
$subject = JMailHelper::cleanSubject($subject);
$body = JMailHelper::cleanBody($body);
// To send we need to use punycode.
$from = JStringPunycode::emailToPunycode($from);
$from = JMailHelper::cleanAddress($from);
$email = JStringPunycode::emailToPunycode($email);
// Send the email
if (JFactory::getMailer()->sendMail($from, $sender, $email, $subject, $body) !== true)
{
JError::raiseNotice(500, JText::_('COM_MAILTO_EMAIL_NOT_SENT'));
return $this->mailto();
}
JFactory::getApplication()->enqueueMessage('ok!', '');
$this->input->set('view', 'sent');
$this->display();
}
}
thank you very much
you can add before body or between subject and body . however, it must be before the submit command !!
here is an example of PhpMailler firstly, you need to call the class like this and you can use it
$this->mail= new PHPMailer();
$this->mail->IsSMTP();
$this->mailIsHTML(true);
$subject = JMailHelper::cleanSubject($subject);
$body = JMailHelper::cleanBody($body);
however if the function is static also you call the function in same class
you can call the function by sef command
self::mailIsHTML(true)

Trouble using PEAR's Mail_Queue

I'm trying to implement PEAR's Mail_Queue package to queue some emails for a web application. I've used the documentation at http://pear.php.net/manual/en/package.mail.mail-queue.mail-queue.tutorial.php to write a small test script.
My problem is that the database is not being updated, and it's not producing errors.
EDIT
// mail_queue db options
$db_options['type'] = 'mdb2';
$db_options['dsn'] = DSN;
$db_options['mail_table'] = 'mail_queue';
// mail_queue sending options
$mail_options['driver'] = 'smtp';
$mail_options['host'] = 'smtp.gmail.com';
$mail_options['port'] = 25;
$mail_options['localhost'] = $host;
$mail_options['auth'] = true;
$mail_options['user'] = MAILUSER;
$mail_options['pass'] = MAILPASS;
require "Queue.php";
$mail_queue =& new Mail_Queue($db_options,$mail_options);
$from = 'someone#domain.ca';
$to = 'martin#starmedia.ca';
$message = 'This is a test';
$headers = array('From' => $from,
'To' => $to,
'Subject' => 'Someone has sent you an email!');
$mime =& new Mail_mime();
$mime->setTXTBody($message);
$body = $mime->get();
$headers = $mime->headers($headers,true);
print $mail_queue->put($from,$to,$headers,$body);
This produces the error Mail Queue Error: Cannot connect to database . However I checked all of the connection information and it's correct. Also, adding if (PEAR::isError($mail)) die($mail->getMessage()); produces no errors!
OK, I finally have my mail queue file working. Here are the steps I took to get it to function:
1. Enable error messages
To enable error handling, I added this snippet:
function handle_pear_error($e) {
die($e->getMessage() . ' ' . print_r($e->getUserInfo(), true));
}
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handle_pear_error');
Once I added this, I reloaded the page and I was getting the following error:
Call to undefined function: MDB2_Driver_mysql::_isNewLinkSet()
2. Update MDB2's MySQL driver
I searched that error and found that it's usually a result of either not having an up-to-date MDB2 library or its MySQL driver.
So I updated both and it's working!

EWS - php sending email with attachment

I'm new to using EWS from Exchangeclient classes.
I'm looking for a simple example how to send an email with an attachment. I've found examples about how to send an email but not sending an email with an attachment.
This is my script:
$exchangeclient = new Exchangeclient();
$exchangeclient->init($username, $password, NULL, 'ews/Services.wsdl');
$exchangeclient->send_message($mail_from, $subject, $body, 'HTML', true, true);
function - PHP Classes:
function send_message($to, $subject, $content, $bodytype="Text", $saveinsent=true, $markasread=true) {
$this->setup();
if($saveinsent) {
$CreateItem->MessageDisposition = "SendOnly";
$CreateItem->SavedItemFolderId->DistinguishedFolderId->Id = "sentitems";
}
else
$CreateItem->MessageDisposition = "SendOnly";
$CreateItem->Items->Message->ItemClass = "IPM.Note";
$CreateItem->Items->Message->Subject = $subject;
$CreateItem->Items->Message->Body->BodyType = $bodytype;
$CreateItem->Items->Message->Body->_ = $content;
$CreateItem->Items->Message->ToRecipients->Mailbox->EmailAddress = $to;
if($markasread)
$CreateItem->Items->Message->IsRead = "true";
$response = $this->client->CreateItem($CreateItem);
$this->teardown();
if($response->ResponseMessages->CreateItemResponseMessage->ResponseCode == "NoError")
return true;
else {
$this->lastError = $response->ResponseMessages->CreateItemResponseMessage->ResponseCode;
return false;
}
}
You have to first save the email as a draft (with the appropriate message disposition), then CreateAttachment() so it has an attachment, then edit it with UpdateItem() so the message disposition is SendOnly. Then it will be sent.
See David Sterling's reply on this thread: http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/f7d5257e-ec98-40fd-b301-f378ba3080fd/ (It's about Meeting Requests but they work the same way.)

phpMailer blank page when creating multiple instances of the class

I am creating a function to send a notification email to a user using the phpMailer lib.
public function notify($address,$subject = '',$body = null,$mailer_options = array()) {
try {
$phpmailer = new PHPMailer($exceptions = true);
$phpmailer->CharSet = 'UTF-8';
$phpmailer->IsSMTP();
$phpmailer->SMTPAuth = true;
$phpmailer->SMTPKeepAlive = true;
//$phpmailer->SMTPDebug = true;
$phpmailer->IsHTML(true);
$phpmailer->Host = ...
$phpmailer->Username = ...
$phpmailer->Password = ...
$phpmailer->From = ...
$phpmailer->FromName =...
$phpmailer->AddAddress($address);
$phpmailer->Subject = $subject;
$phpmailer->Body = $body;
$phpmailer->Send();
$phpmailer->ClearAllRecipients();
}
It works fine if i just send an email or sending multiple emails inside the class.
But if do
for($i=0;$i<3;$++)
{
$notification = new $Notification();
$notification->notify(...);
}
It retuns a blank page. No errors, messages, nothing.
Before you ask i have display_errors turned on.
What can it be?
It works fine if i just have one instance of phpmailer like this:
$phpmailer = new PHPMailer($exceptions = true);
(...)
for($i=0;$i<3;$i++)
{
$phpmailer->AddAddress('address');
$phpmailer->Subject = "";
$phpmailer->Body = "sasa";
$phpmailer->Send();
$phpmailer->ClearAllRecipients();
}
Remove the $ from new Notification:
for($i=0;$i<3;$++)
{
$notification = new Notification();
$notification->notify(...);
}
new $Notification will create a new instance from the value of variable $Notification.
That would only work if $Notification really contains "Notification" (assuming your class is named "Notification")
If you've turned display_errors on in your PHP script, but the server has disabled it by default, errors won't be displayed if there is a syntax error in your script.

Categories