Extract Via header branch token from SIP message with regex - php

I'm trying to extract branch=z9hG4bKlmrltg10b801lgkf0681.1 from the Via: header of a SIP message. Here is the PHP code I have tried:
preg_match('/.branch=.* + From:/', $msg, $result)
And here is the value of $msg:
"INVITE sip:3310094#mediastream.voip.cabletel.net:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.50.240:5060;branch=z9hG4bKlmrltg10b801lgkf0681.1
From: DEATON JEANETTE<sip:9123840782#mediastream.voip.cabletel.net:5060>;tag=SDg7j0c01-959bf958-d8f0f4ea-13c4-50029-140b-4d106390-140b"
How can I correct my regex to make this work?

Please parse your SIP messages properly. I find it highly unlikely that you only want the branch ID, you almost certainly want other information about the transaction other than a pseudo-call ID. SIP messages follow a standardised message format used by several other protocols (including HTTP ;-) ) and there are several libraries out there designed for parsing this message format.
To demonstrate how relatively simple and considerably more powerful this is, lets first take a look at the RFC822 message parser classes that I wrote some time ago (although they have been recently improved and updated). These can be used for parsing emails, I also have a few simple HTTP message parser classes that extend from these:
<?php
/**
* Class representing the basic RFC822 message format
*
* #author Chris Wright
* #version 1.1
*/
class RFC822Message
{
/**
* #var array Collection of headers from the message
*/
protected $headers = array();
/**
* #var string The message body
*/
protected $body;
/**
* Constructor
*
* #param array $headers Collection of headers from the message
* #param string $body The message body
*/
public function __construct($headers, $body)
{
$this->headers = $headers;
$this->body = $body;
}
/**
* Get the value of a header from the message
*
* #param string $name The name of the header
*
* #return array The value(s) of the header from the request
*/
public function getHeader($name)
{
$name = strtolower(trim($name));
return isset($this->headers[$name]) ? $this->headers[$name] : null;
}
/**
* Get the message body
*
* #return string The message body
*/
public function getBody()
{
return $this->body;
}
}
/**
* Factory which makes RFC822 message objects
*
* #author Chris Wright
* #version 1.1
*/
class RFC822MessageFactory
{
/**
* Create a new RFC822 message object
*
* #param array $headers The request headers
* #param string $body The request body
*/
public function create($headers, $body)
{
return new RFC822Message($headers, $body);
}
}
/**
* Parser which creates RFC822 message objects from strings
*
* #author Chris Wright
* #version 1.2
*/
class RFC822MessageParser
{
/**
* #var RFC822MessageFactory Factory which makes RFC822 message objects
*/
protected $messageFactory;
/**
* Constructor
*
* #param RFC822MessageFactory $messageFactory Factory which makes RFC822 message objects
*/
public function __construct(RFC822MessageFactory $messageFactory)
{
$this->messageFactory = $messageFactory;
}
/**
* Split a message into head and body sections
*
* #param string $message The message string
*
* #return array Head at index 0, body at index 1
*/
protected function splitHeadFromBody($message)
{
$parts = preg_split('/\r?\n\r?\n/', ltrim($message), 2);
return array(
$parts[0],
isset($parts[1]) ? $parts[1] : null
);
}
/**
* Parse the header section into a normalized array
*
* #param string $head The message head section
*
* #return array The parsed headers
*/
protected function parseHeaders($head)
{
$expr =
'!
^
([^()<>#,;:\\"/[\]?={} \t]+) # Header name
[ \t]*:[ \t]*
(
(?:
(?: # First line of value
(?:"(?:[^"\\\\]|\\\\.)*"|\S+) # Quoted string or unquoted token
[ \t]* # LWS
)*
(?: # Folded lines
\r?\n
[ \t]+ # ...must begin with LWS
(?:
(?:"(?:[^"\\\\]|\\\\.)*"|\S+) # ...followed by quoted string or unquoted tokens
[ \t]* # ...and maybe some more LWS
)*
)*
)?
)
\r?$
!smx';
preg_match_all($expr, $head, $matches);
$headers = array();
for ($i = 0; isset($matches[0][$i]); $i++) {
$name = strtolower($matches[1][$i]);
if (!isset($headers[$name])) {
$headers[$name] = array();
}
$value = preg_replace('/\s+("(?:[^"\\\\]|\\\\.)*"|\S+)/s', ' $1', $matches[2][$i]);
$headers[$name][] = $value;
}
return $headers;
}
/**
* Create a message object from a string
*
* #param string $message The message string
*
* #return RFC822Message The parsed message object
*/
public function parseMessage($message)
{
list($head, $body) = $this->splitHeadFromBody($message);
$headers = $this->parseHeaders($head);
return $this->requestFactory->create($headers, $body);
}
}
Nothing particularly scary there if you ignore the terrifying regex for parsing the headers :-P - seriously though, these classes can be used unmodified for parsing the header sections of emails, the basis of RFC822 formatted messages.
SIP models itself on HTTP, so with a couple of fairly simple modifications to the HTTP message parsing classes we can easily adapt them to SIP. Let's take a look at those - in these classes I have (more or less) done a search for HTTP and replaced it with SIP:
<?php
/**
* Abstract class representing a SIP message
*
* #author Chris Wright
* #version 1.0
*/
abstract class SIPMessage extends RFC822Message
{
/**
* #var string The message protocol version
*/
protected $version;
/**
* Constructor
*
* #param array $headers Collection of headers from the message
* #param string $body The message body
* #param string $version The message protocol version
*/
public function __construct($headers, $body, $version)
{
parent::__construct($headers, $body);
$this->version = $version;
}
/**
* Get the message protocol version
*
* #return string The message protocol version
*/
public function getVersion()
{
return $this->version;
}
}
/**
* Class representing a SIP request message
*
* #author Chris Wright
* #version 1.0
*/
class SIPRequest extends SIPMessage
{
/**
* #var string The request method
*/
private $method;
/**
* #var string The request URI
*/
private $uri;
/**
* Constructor
*
* #param array $headers The request headers
* #param string $body The request body
* #param string $version The request protocol version
* #param string $method The request method
* #param string $uri The request URI
*/
public function __construct($headers, $body, $version, $method, $uri)
{
parent::__construct($headers, $body, $version);
$this->method = $method;
$this->uri = $uri;
}
/**
* Get the request method
*
* #return string The request method
*/
public function getMethod()
{
return $this->method;
}
/**
* Get the request URI
*
* #return string The request URI
*/
public function getURI()
{
return $this->uri;
}
}
/**
* Class representing a SIP response message
*
* #author Chris Wright
* #version 1.0
*/
class SIPResponse extends SIPMessage
{
/**
* #var int The response code
*/
private $code;
/**
* #var string The response message
*/
private $message;
/**
* Constructor
*
* #param array $headers The request headers
* #param string $body The request body
* #param string $version The request protocol version
* #param int $code The response code
* #param string $message The response message
*/
public function __construct($headers, $body, $version, $code, $message)
{
parent::__construct($headers, $body, $version);
$this->code = $code;
$this->message = $message;
}
/**
* Get the response code
*
* #return int The response code
*/
public function getCode()
{
return $this->code;
}
/**
* Get the response message
*
* #return string The response message
*/
public function getMessage()
{
return $this->message;
}
}
/**
* Factory which makes SIP request objects
*
* #author Chris Wright
* #version 1.0
*/
class SIPRequestFactory extends RFC822MessageFactory
{
/**
* Create a new SIP request object
*
* The last 3 arguments of this method are only optional to prevent PHP from triggering
* an E_STRICT at compile time. IMO this particular error is itself an error on the part
* of the PHP designers, and I don't feel bad about about this workaround, even if it
* does mean the signature is technically wrong. It is the lesser of two evils.
*
* #param array $headers The request headers
* #param string $body The request body
* #param string $version The request protocol version
* #param string $method The request method
* #param string $uri The request URI
*/
public function create($headers, $body, $version = null, $method = null, $uri = null)
{
return new SIPRequest($headers, $body, $version, $method, $uri);
}
}
/**
* Factory which makes SIP response objects
*
* #author Chris Wright
* #version 1.0
*/
class SIPResponseFactory extends RFC822MessageFactory
{
/**
* Create a new SIP response object
*
* The last 3 arguments of this method are only optional to prevent PHP from triggering
* an E_STRICT at compile time. IMO this particular error is itself an error on the part
* of the PHP designers, and I don't feel bad about about this workaround, even if it
* does mean the signature is technically wrong. It is the lesser of two evils.
*
* #param array $headers The response headers
* #param string $body The response body
* #param string $version The response protocol version
* #param int $code The response code
* #param string $message The response message
*/
public function create($headers, $body, $version = null, $code = null, $message = null)
{
return new SIPResponse($headers, $body, $version, $code, $message);
}
}
/**
* Parser which creates SIP message objects from strings
*
* #author Chris Wright
* #version 1.0
*/
class SIPMessageParser extends RFC822MessageParser
{
/**
* #var SIPRequestFactory Factory which makes SIP request objects
*/
private $requestFactory;
/**
* #var SIPResponseFactory Factory which makes SIP response objects
*/
private $responseFactory;
/**
* Constructor
*
* #param SIPRequestFactory $requestFactory Factory which makes SIP request objects
* #param SIPResponseFactory $responseFactory Factory which makes SIP response objects
*/
public function __construct(SIPRequestFactory $requestFactory, SIPResponseFactory $responseFactory)
{
$this->requestFactory = $requestFactory;
$this->responseFactory = $responseFactory;
}
/**
* Remove the request line from the message and parse into tokens
*
* #param string $head The message head section
*
* #return array The parsed request line at index 0, the remainder of the message at index 1
*
* #throws \DomainException When the request line of the message is invalid
*/
private function removeAndParseRequestLine($head)
{
// Note: this method forgives a couple of minor standards violations, mostly for benefit
// of some older Polycom phones and for Voispeed, who seem to make stuff up as they go
// along. It also treats the whole line as case-insensitive even though methods are
// officially case-sensitive, because having two different casings of the same verb mean
// different things makes no sense semantically or implementationally.
// Side note, from RFC3261:
// > The SIP-Version string is case-insensitive, but implementations MUST send upper-case
// Wat. Go home Rosenberg, et. al., you're drunk.
$parts = preg_split('/\r?\n/', $head, 2);
$expr =
'#^
(?:
([^\r\n \t]+) [ \t]+ ([^\r\n \t]+) [ \t]+ SIP/(\d+\.\d+) # request
|
SIP/(\d+\.\d+) [ \t]+ (\d+) [ \t]+ ([^\r\n]+) # response
)
$#ix';
if (!preg_match($expr, $parts[0], $match)) {
throw new \DomainException('Request-Line of the message is invalid');
}
if (empty($match[4])) { // request
$requestLine = array(
'method' => strtoupper($match[1]),
'uri' => $match[2],
'version' => $match[3]
);
} else { // response
$requestLine = array(
'version' => $match[4],
'code' => (int) $match[5],
'message' => $match[6]
);
}
return array(
$requestLine,
isset($parts[1]) ? $parts[1] : ''
);
}
/**
* Create the appropriate message object from a string
*
* #param string $message The message string
*
* #return SIPRequest|SIPResponse The parsed message object
*
* #throws \DomainException When the message string is not valid SIP message
*/
public function parseMessage($message)
{
list($head, $body) = $this->splitHeadFromBody($message);
list($requestLine, $head) = $this->removeAndParseRequestLine($head);
$headers = $this->parseHeaders($head);
if (isset($requestLine['uri'])) {
return $this->requestFactory->create(
$headers,
$body,
$requestLine['version'],
$requestLine['method'],
$requestLine['uri']
);
} else {
return $this->responseFactory->create(
$headers,
$body,
$requestLine['version'],
$requestLine['code'],
$requestLine['message']
);
}
}
}
Seems like a lot of code just for extracting one header value, doesn't it? Well, it is. But that's not just what it does. It parses the whole message into a data structure that provides easy access to any number of bits of information, allowing for (more or less) anything that the standards can throw at you.
So, lets take a look at how you would actually use it:
// First we create a parser object
$messageParser = new SIPMessageParser(
new SIPRequestFactory,
new SIPResponseFactory
);
// Parse the message into an object
try {
$message = $messageParser->parseMessage($msg);
} catch (Exception $e) {
// The message parsing failed, handle the error here
}
// Get the value of the Via: header
$via = $message->getHeader('Via');
// SIP is irritatingly non-specific about the format of branch IDs. This
// expression matches either a quoted string or an unquoted token, which is
// about all that you can say for sure about arbitrary implementations.
$expr = '/branch=(?:"((?:[^"\\\\]|\\\\.)*)"|(.+?)(?:\s|;|$))/i';
// NB: this assumes the message has a single Via: header and a single branch ID.
// In reality this is rarely the case for messages that are received, although
// it is usually the case for messages before they are sent.
if (!preg_match($expr, $via[0], $matches)) {
// The Via: header does not contain a branch ID, handle this error
}
$branchId = !empty($matches[2]) ? $matches[2] : $matches[1];
var_dump($branchId);
See it working
This answer is almost certainly massively overkill for the problem at hand. However, I would regard it as the right way to approach this problem.

preg_match('/branch=.*/i', $msg, $result);
print_r($result);
Will yield something like:
Array
(
[0] => branch=z9hG4bKlmrltg10b801lgkf0681.1
)

Try this
$str = "INVITE sip:3310094#mediastream.voip.cabletel.net:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.50.240:5060;branch=z9hG4bKlmrltg10b801lgkf0681.1
From: DEATON JEANETTE<sip:9123840782#mediastream.voip.cabletel.net:5060>;tag=SDg7j0c01-959bf958-d8f0f4ea-13c4-50029-140b-4d106390-140b";
preg_match('/branch=(.*)From:/i', $str, $output);
print_r( $output );

Try this regex. It checks if there's a space or newline after the branch code. The result you want is always stored in $output[0]
$str = "INVITE sip:3310094#mediastream.voip.cabletel.net:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.50.240:5060;branch=z9hG4bKlmrltg10b801lgkf0681.1 From: DEATON JEANETTE<sip:9123840782#mediastream.voip.cabletel.net:5060>;tag=SDg7j0c01-959bf958-d8f0f4ea-13c4-50029-140b-4d106390-140b";
preg_match('/(branch=.*)( |\r\n)/', $str, $output);
print_r( $output ); // $output[0] is what you need
Example:
http://codepad.viper-7.com/Gj0lWD

You can use a look-ahead assertion like this:
preg_match_all('/.branch=(.*?)(?=^\S|\Z)/sm', $msg, $matches);
Here, (?=^\S|\Z) asserts a new line followed by a non-space (aka folding header) or end-of-subject. This is where the match should end.
Or just match branch= until the end of line:
preg_match_all('/.branch=(.*)/m', $msg, $matches);
Works for headers that are not folded.
See also: Basic rules of HTTP headers

Related

I am facing problem (csrf_token' URL query argument is invalid) with flag module at Drupal 8

I generated flag link
$flag_link = [
'#lazy_builder' => ['flag.link_builder:build', [
$product->getEntityTypeId(),
$product->id(),
'product_like',
]],
'#create_placeholder' => TRUE,
];
Flag link is generated successfully. But while I click flag link , I got error message as response
{message: "'csrf_token' URL query argument is invalid."}
message: "'csrf_token' URL query argument is invalid."
I found a temporary solution. Not sure if this is a bug in Flag that needs to be addressed by the module maintainers, or if this is working as intended, since this is a REST response, and not a typical Drupal call for a view or display mode.
In the ModuleRestResource.php file (In my case, the ModuleRestResource.php file is located at:
{{DRUPAL_ROOT}}/web/modules/custom/{{Module_Name}}/src/Plugin/rest/resource/{{Module_Name}}RestResource.php):
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\flag\FlagService;
use Drupal\Core\Render\RenderContext;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ModuleRestResource extends ResourceBase {
/**
* A current user instance.
*
* #var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* #var $entityTypeManager \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* #var \Drupal\flag\FlagService
*/
protected $flagService;
/**
* #var Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfService;
/**
* {#inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->logger = $container->get('logger.factory')->get('module');
$instance->currentUser = $container->get('current_user');
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->flagService = $container->get('flag');
$instance->csrfService = $container->get('csrf_token');
return $instance;
}
/**
* Responds to GET requests.
*
* #param string $payload
*
* #return \Drupal\rest\ResourceResponse
* The HTTP response object.
*
* #throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function get($payload) {
// You must to implement the logic of your REST Resource here.
// Use current user after pass authentication to validate access.
if (!$this->currentUser->hasPermission('access content')) {
throw new AccessDeniedHttpException();
}
if (!is_numeric($payload)) {
throw new BadRequestHttpException();
}
/*
* This is the object that will be returned with the node details.
*/
$obj = new \stdClass();
// First load our node.
/**
* #var \Drupal\Core\Entity\EntityInterface
*/
$node = $this->entityTypeManager->getStorage('node')->load($payload);
/**
* FIX STARTS HERE !!!!!
*/
/**
* Because we are rending code early in the process, we need to wrap in executeInRenderContext
*/
$render_context = new RenderContext();
$fl = \Drupal::service('renderer')->executeInRenderContext($render_context, function() use ($node, $payload) {
/**
* Get the flag we need and check if the selected node has been flagged by the current user
*
* Set the path to create a token. This is the value that is missing by default that creates an
* invalid CSRF Token. Important to note that the leading slash should be left off for token generation
* and then added to to the links href attribute
*
*/
$flag = $this->flagService->getFlagById('bookmark');
$is_flagged = (bool) $this->flagService->getEntityFlaggings($flag, $node, \Drupal::currentUser() );
$path = 'flag/'. ($is_flagged ? 'un' : '') .'flag/bookmark/' . $node->id();
$token = $this->csrfService->get($path);
$flag_link = $flag->getLinkTypePlugin()->getAsFlagLink($flag, $node);
$flag_link['#attributes']['href'] = '/' . $path . '?destination&token=' . $token;
/**
* Render the link into HTML
*/
return \Drupal::service('renderer')->render($flag_link);
});
/**
* This is required to bubble metadata
*/
if (!$render_context->isEmpty()) {
$bubbleable_metadata = $render_context->pop();
\Drupal\Core\Render\BubbleableMetadata::createFromObject($fl)
->merge($bubbleable_metadata);
}
/*
* !!!!! FIX ENDS HERE !!!!!
*/
$obj->flag_link = $fl;
return new ResourceResponse((array)$obj, 200);
}
}
Anyone who can get module maintainers to address this would be nice.

How to Log INFO to separate file in Laravel

How to specify a separate file for logging INFO in Laravel 5.1?
Do you want to specifically log info to one log file and another log type to another location? My solution might not help in that case, but could still be useful.
To write a log file to another location, use the method useDailyFiles or useFiles, and then info to log to the log file at the path you just specified. Like so:
Log::useDailyFiles(storage_path().'/logs/name-of-log.log');
Log::info([info to log]);
The first parameter for both methods is the path of the log file (which is created if it doesn't already exist) and for useDailyFiles the second argument is the number of days Laravel will log for before erasing old logs. The default value is unlimited, so in my example I haven't entered a value.
Since Laravel 5.6 you can create your own channel in config\logging.php. If you have upgraded from an older Laravel version you need to create this file (https://laravel.com/docs/5.6/upgrade).
Add this to you channel array in config\logging.php
'your_channel_name' => [
'driver' => 'single',
'path' => storage_path('logs/your_file_name.log'),
],
You can then call any of the 8 logging levels like that:
Illuminate\Support\Facades\Log::channel('your_channel_name')->info('your_message');
The logs will be stored in logs/your_file_name.log
Since Laravel >= 5.6 we can use Log Channels to make it work in a easy way. This allows you to create log channels which can be handled as own log files with own drivers, paths or levels. You just need this few lines to make it work.
Simple add a new channel (choose your channel name, e.g. "command")
config/logging.php:
return [
'channels' => [
'command' => [
'driver' => 'single',
'path' => storage_path('logs/command.log'),
'level' => 'debug',
],
],
];
Log where ever you want by parse the channel name:
Log::channel('command')->info('Something happened!');
A simple logger helper that allows you to log to multiple custom files on the fly. You can also add your custom handler and set the file path.
App\Helper\LogToChannels.php
<?php
/**
* Logger helper to log into different files
*
* #package App\Helpers
* #author Romain Laneuville <romain.laneuville#hotmail.fr>
*/
namespace App\Helpers;
use Monolog\Logger;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;
/**
* Class LogToChannels
*
* #package App\Helpers
*/
class LogToChannels
{
/**
* The LogToChannels channels.
*
* #var Logger[]
*/
protected $channels = [];
/**
* LogToChannels constructor.
*/
public function __construct()
{
}
/**
* #param string $channel The channel to log the record in
* #param int $level The error level
* #param string $message The error message
* #param array $context Optional context arguments
*
* #return bool Whether the record has been processed
*/
public function log(string $channel, int $level, string $message, array $context = []): bool
{
// Add the logger if it doesn't exist
if (!isset($this->channels[$channel])) {
$handler = new StreamHandler(
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channel . '.log'
);
$handler->setFormatter(new LineFormatter(null, null, true, true));
$this->addChannel($channel, $handler);
}
// LogToChannels the record
return $this->channels[$channel]->{Logger::getLevelName($level)}($message, $context);
}
/**
* Add a channel to log in
*
* #param string $channelName The channel name
* #param HandlerInterface $handler The channel handler
* #param string|null $path The path of the channel file, DEFAULT storage_path()/logs
*
* #throws \Exception When the channel already exists
*/
public function addChannel(string $channelName, HandlerInterface $handler, string $path = null)
{
if (isset($this->channels[$channelName])) {
throw new \Exception('This channel already exists');
}
$this->channels[$channelName] = new Logger($channelName);
$this->channels[$channelName]->pushHandler(
new $handler(
$path === null ?
storage_path() . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $channelName . '.log' :
$path . DIRECTORY_SEPARATOR . $channelName . '.log'
)
);
}
/**
* Adds a log record at the DEBUG level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function debug(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::DEBUG, $message, $context);
}
/**
* Adds a log record at the INFO level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function info(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::INFO, $message, $context);
}
/**
* Adds a log record at the NOTICE level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function notice(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::NOTICE, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function warn(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the WARNING level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function warning(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::WARNING, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function err(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the ERROR level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function error(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ERROR, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function crit(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the CRITICAL level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return Boolean Whether the record has been processed
*/
public function critical(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::CRITICAL, $message, $context);
}
/**
* Adds a log record at the ALERT level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function alert(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::ALERT, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function emerg(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
/**
* Adds a log record at the EMERGENCY level.
*
* #param string $channel The channel name
* #param string $message The log message
* #param array $context The log context
*
* #return bool Whether the record has been processed
*/
public function emergency(string $channel, string $message, array $context = []): bool
{
return $this->log($channel, Logger::EMERGENCY, $message, $context);
}
}
App\Providers\LogToChannelsServiceProvider.php
<?php
/**
* Logger service provider to be abled to log in different files
*
* #package App\Providers
* #author Romain Laneuville <romain.laneuville#hotmail.fr>
*/
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\LogToChannels;
/**
* Class LogToChannelsServiceProvider
*
* #package App\Providers
*/
class LogToChannelsServiceProvider extends ServiceProvider
{
/**
* Initialize the logger
*
* #return void
*/
public function register()
{
$this->app->singleton('App\Helpers\LogToChannels', function () {
return new LogToChannels();
});
}
}
config\app.php (add the service provider)
// Register Service Providers
$app->register(App\Providers\LogToChannelsServiceProvider::class);
Then anywhere in your app you can call using dependency injection (add the class in your constructor and bind it to a log class attribute)
$this->log->info('logger_name', 'Log message');
$this->log->error('other_logger_name', 'Log message', $someContext);
You can even customize your logger output by calling
$this->log->addChannel('channel_name', $customHandler);
And it will be accessible when you will call its name anywhere in your app.
If you would like add another monolog handler, you may use the application's configureMonologUsing method.
Place a call to this method in bootstrap/app.php file right before the $app variable is returned:
$app->configureMonologUsing(function($monolog) {
$monolog->pushHandler(new StreamHandler('path/to/info.log', Logger::INFO, false)); // false value as third argument to disable bubbling up the stack
});
return $app;
If you want to separate only a set of logs you can do it using useFiles method, as follows:
\Log::useFiles(storage_path() . '/logs/your_custom_log_file.log');
❗❗❗ But keep in mind that useFiles() does not overwrite the default log handler, so the logs will be added to laravel.log too.
In Laravel 5.4 when I need to create a log in a separate file, I fall back to file_put_contents function:
$myLogInfo = "...";
file_put_contents(
storage_path() . '/logs/your_custom_log_file.log',
$myLogInfo . PHP_EOL,
FILE_APPEND | LOCK_EX
);

PHP FILTER_VALIDATE_EMAIL does not work correctly

I'm using PHP 5.3.10. This is the code:
<?php
$email = "test#example.c";
if (filter_var($email, FILTER_VALIDATE_EMAIL))
echo "Email: ".$email." correct";
else
echo "email not correct";
?>
It returns: "Email: test#example.c correct.
I think that a top level domain with only one character is not correct (I'm not aware of one-character-length TLD according to this list: http://data.iana.org/TLD/tlds-alpha-by-domain.txt).
So, FILTER_VALIDATE_EMAIL filter is working correctly or not?
Validating e-mail adresses is kinda complicated.
Take a look at this list:
Valid email addresses
niceandsimple#example.com
very.common#example.com
a.little.lengthy.but.fine#dept.example.com
disposable.style.email.with+symbol#example.com
user#[IPv6:2001:db8:1ff::a0b:dbd0]
"much.more unusual"#example.com
"very.unusual.#.unusual.com"#example.com
"very.(),:;<>[]".VERY."very#\
"very".unusual"#strange.example.com
postbox#com (top-level domains are valid hostnames)
admin#mailserver1 (local domain name with no TLD)
!#$%&'*+-/=?^_`{}|~#example.org
"()<>[]:,;#\"!#$%&'*+-/=?^_`{}| ~.a"#example.org
" "#example.org (space between the quotes)
üñîçøðé#example.com (Unicode characters in local part)
Invalid email addresses
Abc.example.com (an # character must separate the local and domain
parts)
A#b#c#example.com (only one # is allowed outside quotation marks)
a"b(c)d,e:f;gi[j\k]l#example.com (none of the special characters
in this local part are allowed outside quotation marks)
just"not"right#example.com (quoted strings must be dot separated, or
the only element making up the local-part)
this is"not\allowed#example.com (spaces, quotes, and backslashes may
only exist when within quoted strings and preceded by a backslash)
this\ still"not\allowed#example.com (even if escaped (preceded by
a backslash), spaces, quotes, and backslashes must still be
contained by quotes)
Source http://en.wikipedia.org/wiki/Email_address
Allmost all e-mail validation implementations are "bugged" but the php implementation is fine to work with because it accepts all common e-mail adresses
UPDATE:
Found on http://www.php.net/manual/en/filter.filters.validate.php
Regarding "partial" addresses with no . in the domain part, a comment in the source code (in ext/filter/logical_filters.c) justifies this rejection thus:
* The regex below is based on a regex by Michael Rushton.
* However, it is not identical. I changed it to only consider routeable
* addresses as valid. Michael's regex considers a#b a valid address
* which conflicts with section 2.3.5 of RFC 5321 which states that:
*
* Only resolvable, fully-qualified domain names (FQDNs) are permitted
* when domain names are used in SMTP. In other words, names that can
* be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
* in Section 5) are permitted, as are CNAME RRs whose targets can be
* resolved, in turn, to MX or address RRs. Local nicknames or
* unqualified names MUST NOT be used.
And here is a link to the class from Michael Rushton (link broken see source below)
Which supports both RFC 5321/5322
<?php
/**
* Squiloople Framework
*
* LICENSE: Feel free to use and redistribute this code.
*
* #author Michael Rushton <michael#squiloople.com>
* #link http://squiloople.com/
* #package Squiloople
* #version 1.0
* #copyright © 2012 Michael Rushton
*/
/**
* Email Address Validator
*
* Validate email addresses according to the relevant standards
*/
final class EmailAddressValidator
{
// The RFC 5321 constant
const RFC_5321 = 5321;
// The RFC 5322 constant
const RFC_5322 = 5322;
/**
* The email address
*
* #access private
* #var string $_email_address
*/
private $_email_address;
/**
* A quoted string local part is either allowed (true) or not (false)
*
* #access private
* #var boolean $_quoted_string
*/
private $_quoted_string = FALSE;
/**
* An obsolete local part is either allowed (true) or not (false)
*
* #access private
* #var boolean $_obsolete
*/
private $_obsolete = FALSE;
/**
* A basic domain name is either required (true) or not (false)
*
* #access private
* #var boolean $_basic_domain_name
*/
private $_basic_domain_name = TRUE;
/**
* A domain literal domain is either allowed (true) or not (false)
*
* #access private
* #var boolean $_domain_literal
*/
private $_domain_literal = FALSE;
/**
* Comments and folding white spaces are either allowed (true) or not (false)
*
* #access private
* #var boolean $_cfws
*/
private $_cfws = FALSE;
/**
* Set the email address and turn on the relevant standard if required
*
* #access public
* #param string $email_address
* #param null|integer $standard
*/
public function __construct($email_address, $standard = NULL)
{
// Set the email address
$this->_email_address = $email_address;
// Set the relevant standard or throw an exception if an unknown is requested
switch ($standard)
{
// Do nothing if no standard requested
case NULL:
break;
// Otherwise if RFC 5321 requested
case self::RFC_5321:
$this->setStandard5321();
break;
// Otherwise if RFC 5322 requested
case self::RFC_5322:
$this->setStandard5322();
break;
// Otherwise throw an exception
default:
throw new Exception('Unknown RFC standard for email address validation.');
}
}
/**
* Call the constructor fluently
*
* #access public
* #static
* #param string $email_address
* #param null|integer $standard
* #return EmailAddressValidator
*/
public static function setEmailAddress($email_address, $standard = NULL)
{
return new self($email_address, $standard);
}
/**
* Validate the email address using a basic standard
*
* #access public
* #return EmailAddressValidator
*/
public function setStandardBasic()
{
// A quoted string local part is not allowed
$this->_quoted_string = FALSE;
// An obsolete local part is not allowed
$this->_obsolete = FALSE;
// A basic domain name is required
$this->_basic_domain_name = TRUE;
// A domain literal domain is not allowed
$this->_domain_literal = FALSE;
// Comments and folding white spaces are not allowed
$this->_cfws = FALSE;
// Return the EmailAddressValidator object
return $this;
}
/**
* Validate the email address using RFC 5321
*
* #access public
* #return EmailAddressValidator
*/
public function setStandard5321()
{
// A quoted string local part is allowed
$this->_quoted_string = TRUE;
// An obsolete local part is not allowed
$this->_obsolete = FALSE;
// Only a basic domain name is not required
$this->_basic_domain_name = FALSE;
// A domain literal domain is allowed
$this->_domain_literal = TRUE;
// Comments and folding white spaces are not allowed
$this->_cfws = FALSE;
// Return the EmailAddressValidator object
return $this;
}
/**
* Validate the email address using RFC 5322
*
* #access public
* #return EmailAddressValidator
*/
public function setStandard5322()
{
// A quoted string local part is disallowed
$this->_quoted_string = FALSE;
// An obsolete local part is allowed
$this->_obsolete = TRUE;
// Only a basic domain name is not required
$this->_basic_domain_name = FALSE;
// A domain literal domain is allowed
$this->_domain_literal = TRUE;
// Comments and folding white spaces are allowed
$this->_cfws = TRUE;
// Return the EmailAddressValidator object
return $this;
}
/**
* Either allow (true) or do not allow (false) a quoted string local part
*
* #access public
* #param boolean $allow
* #return EmailAddressValidator
*/
public function setQuotedString($allow = TRUE)
{
// Either allow (true) or do not allow (false) a quoted string local part
$this->_quoted_string = $allow;
// Return the EmailAddressValidator object
return $this;
}
/**
* Either allow (true) or do not allow (false) an obsolete local part
*
* #access public
* #param boolean $allow
* #return EmailAddressValidator
*/
public function setObsolete($allow = TRUE)
{
// Either allow (true) or do not allow (false) an obsolete local part
$this->_obsolete = $allow;
// Return the EmailAddressValidator object
return $this;
}
/**
* Either require (true) or do not require (false) a basic domain name
*
* #access public
* #param boolean $allow
* #return EmailAddressValidator
*/
public function setBasicDomainName($allow = TRUE)
{
// Either require (true) or do not require (false) a basic domain name
$this->_basic_domain_name = $allow;
// Return the EmailAddressValidator object
return $this;
}
/**
* Either allow (true) or do not allow (false) a domain literal domain
*
* #access public
* #param boolean $allow
* #return EmailAddressValidator
*/
public function setDomainLiteral($allow = TRUE)
{
// Either allow (true) or do not allow (false) a domain literal domain
$this->_domain_literal = $allow;
// Return the EmailAddressValidator object
return $this;
}
/**
* Either allow (true) or do not allow (false) comments and folding white spaces
*
* #access public
* #param boolean $allow
* #return EmailAddressValidator
*/
public function setCFWS($allow = TRUE)
{
// Either allow (true) or do not allow (false) comments and folding white spaces
$this->_cfws = $allow;
// Return the EmailAddressValidator object
return $this;
}
/**
* Return the regular expression for a dot atom local part
*
* #access private
* #return string
*/
private function _getDotAtom()
{
return "([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*";
}
/**
* Return the regular expression for a quoted string local part
*
* #access private
* #return string
*/
private function _getQuotedString()
{
return '"(?>[ !#-\[\]-~]|\\\[ -~])*"';
}
/**
* Return the regular expression for an obsolete local part
*
* #access private
* #return string
*/
private function _getObsolete()
{
return '([!#-\'*+\/-9=?^-~-]+|"(?>'
. $this->_getFWS()
. '(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*'
. $this->_getFWS()
. '")(?>'
. $this->_getCFWS()
. '\.'
. $this->_getCFWS()
. '(?1))*';
}
/**
* Return the regular expression for a domain name domain
*
* #access private
* #return string
*/
private function _getDomainName()
{
// Return the basic domain name format if required
if ($this->_basic_domain_name)
{
return '(?>' . $this->_getDomainNameLengthLimit()
. '[a-z\d](?>[a-z\d-]*[a-z\d])?'
. $this->_getCFWS()
. '\.'
. $this->_getCFWS()
. '){1,126}[a-z]{2,6}';
}
// Otherwise return the full domain name format
return $this->_getDomainNameLengthLimit()
. '([a-z\d](?>[a-z\d-]*[a-z\d])?)(?>'
. $this->_getCFWS()
. '\.'
. $this->_getDomainNameLengthLimit()
. $this->_getCFWS()
. '(?2)){0,126}';
}
/**
* Return the regular expression for an IPv6 address
*
* #access private
* #return string
*/
private function _getIPv6()
{
return '([a-f\d]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f\d][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?';
}
/**
* Return the regular expression for an IPv4-mapped IPv6 address
*
* #access private
* #return string
*/
private function _getIPv4MappedIPv6()
{
return '(?3)(?>:(?3)){5}:|(?!(?:.*[a-f\d]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?';
}
/**
* Return the regular expression for an IPv4 address
*
* #access private
* #return string
*/
private function _getIPv4()
{
return '(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?>\.(?6)){3}';
}
/**
* Return the regular expression for a domain literal domain
*
* #access private
* #return string
*/
private function _getDomainLiteral()
{
return '\[(?:(?>IPv6:(?>'
. $this->_getIPv6()
. '))|(?>(?>IPv6:(?>'
. $this->_getIPv4MappedIPv6()
. '))?'
. $this->_getIPv4()
. '))\]';
}
/**
* Return either the regular expression for folding white spaces or its backreference
*
* #access private
* #param boolean $define
* #return string
*/
private function _getFWS($define = FALSE)
{
// Return the backreference if $define is set to FALSE otherwise return the regular expression
if ($this->_cfws)
{
return !$define ? '(?P>fws)' : '(?<fws>(?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)';
}
}
/**
* Return the regular expression for comments
*
* #access private
* #return string
*/
private function _getComments()
{
return '(?<comment>\((?>'
. $this->_getFWS()
. '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?P>comment)))*'
. $this->_getFWS()
. '\))';
}
/**
* Return either the regular expression for comments and folding white spaces or its backreference
*
* #access private
* #param boolean $define
* #return string
*/
private function _getCFWS($define = FALSE)
{
// Return the backreference if $define is set to FALSE
if ($this->_cfws && !$define)
{
return '(?P>cfws)';
}
// Otherwise return the regular expression
if ($this->_cfws)
{
return '(?<cfws>(?>(?>(?>'
. $this->_getFWS(TRUE)
. $this->_getComments()
. ')+'
. $this->_getFWS()
. ')|'
. $this->_getFWS()
. ')?)';
}
}
/**
* Establish and return the valid format for the local part
*
* #access private
* #return string
*/
private function _getLocalPart()
{
// The local part may be obsolete if allowed
if ($this->_obsolete)
{
return $this->_getObsolete();
}
// Otherwise the local part must be either a dot atom or a quoted string if the latter is allowed
if ($this->_quoted_string)
{
return '(?>' . $this->_getDotAtom() . '|' . $this->_getQuotedString() . ')';
}
// Otherwise the local part must be a dot atom
return $this->_getDotAtom();
}
/**
* Establish and return the valid format for the domain
*
* #access private
* #return string
*/
private function _getDomain()
{
// The domain must be either a domain name or a domain literal if the latter is allowed
if ($this->_domain_literal)
{
return '(?>' . $this->_getDomainName() . '|' . $this->_getDomainLiteral() . ')';
}
// Otherwise the domain must be a domain name
return $this->_getDomainName();
}
/**
* Return the email address length limit
*
* #access private
* #return string
*/
private function _getEmailAddressLengthLimit()
{
return '(?!(?>' . $this->_getCFWS() . '"?(?>\\\[ -~]|[^"])"?' . $this->_getCFWS() . '){255,})';
}
/**
* Return the local part length limit
*
* #access private
* #return string
*/
private function _getLocalPartLengthLimit()
{
return '(?!(?>' . $this->_getCFWS() . '"?(?>\\\[ -~]|[^"])"?' . $this->_getCFWS() . '){65,}#)';
}
/**
* Establish and return the domain name length limit
*
* #access private
* #return string
*/
private function _getDomainNameLengthLimit()
{
return '(?!' . $this->_getCFWS() . '[a-z\d-]{64,})';
}
/**
* Check to see if the domain can be resolved to MX RRs
*
* #access private
* #param array $domain
* #return integer|boolean
*/
private function _verifyDomain($domain)
{
// Return 0 if the domain cannot be resolved to MX RRs
if (!checkdnsrr(end($domain), 'MX'))
{
return 0;
}
// Otherwise return true
return TRUE;
}
/**
* Perform the validation check on the email address's syntax and, if required, call _verifyDomain()
*
* #access public
* #param boolean $verify
* #return boolean|integer
*/
public function isValid($verify = FALSE)
{
// Return false if the email address has an incorrect syntax
if (!preg_match(
'/^'
. $this->_getEmailAddressLengthLimit()
. $this->_getLocalPartLengthLimit()
. $this->_getCFWS()
. $this->_getLocalPart()
. $this->_getCFWS()
. '#'
. $this->_getCFWS()
. $this->_getDomain()
. $this->_getCFWS(TRUE)
. '$/isD'
, $this->_email_address
))
{
return FALSE;
}
// Otherwise check to see if the domain can be resolved to MX RRs if required
if ($verify)
{
return $this->_verifyDomain(explode('#', $this->_email_address));
}
// Otherwise return 1
return 1;
}
}
FILTER_VALIDATE_EMAIL is not supporting PHP 5.2.14
There is a PHP class on google code for validating email addresses:
http://code.google.com/p/php-email-address-validation
You can use it like
include('EmailAddressValidator.php');
$validator = new EmailAddressValidator;
if ($validator->check_email_address('test#example.org')) {
// Email address is technically valid
} else {
// Email not valid
}
FILTER_VALIDATE_EMAIL can only tell you if the address is formatted correctly.
Consider these examples
// "not an email" is invalid so its false.
php > var_export(filter_var("not an email", FILTER_VALIDATE_EMAIL));
false
// "foo#a.com" looks like an email, so it passes even though its not real.
php > var_export(filter_var("foo#a.com", FILTER_VALIDATE_EMAIL));
'foo#a.com'
// "foo#gmail.com" passes, gmail is a valid email server,
// but gmail require more than 3 letters for the address.
var_export(filter_var("foo#gmail.com", FILTER_VALIDATE_EMAIL));
'foo#gmail.com'
So FILTER_VALIDATE_EMAIL is only good at telling you when it's completely wrong, not when it's right.
You will need to use a service like Real Email which can do indepth email address validation.
// foo#gmail.com is invalid because gmail require more than 3 letters for the address.
var_export(file_get_contents("https://isitarealemail.com/api/email/validate?email=foo#gmail.com"));
'{"status":"invalid"}'
// foobar#gmail.com is valid
var_export(file_get_contents("https://isitarealemail.com/api/email/validate?email=foobar#gmail.com"));
'{"status":"valid"}'
For a more see https://docs.isitarealemail.com/how-to-validate-email-addresses-in-php
I chose to use :
<?php
$email =$argv[1];$result= is_valid_email($email); echo $result;
function is_valid_email($email) { return preg_match('/^(([^<>()[\]\\.,;:\s#"\']+(\.[^<>()[\]\\.,;:\s#"\']+)*)|("[^"\']+"))#((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email); }
?>
in my forum software
https://github.com/neofutur/MyBestBB/blob/master/include/email.php#L39
but officialy it is :
http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html
( longer too)

what is the error in the XML response?

I have the following php code (getRout.php).. which response results in xml formats ... But I got this error :
XML Parsing Error: no element found
Location: http://127.0.0.1/direction2/getRout.php
Line Number 1, Column 1:
edit
You can see the xml response directly by requesting this url :
http://www.yournavigation.org/api/1.0/gosmore.php?format=kml&flat=52.215676&flon=5.963946&tlat=52.2573&tlon=6.1799&v=motorcar&fast=1&layer=mapnik
getRout.php
<? require_once"RESTclient.class.php";
$url="http://www.yournavigation.org/api/1.0/gosmore.php?format=kml&flat=52.215676&flon=5.963946&tlat=52.2573&tlon=6.1799&v=motorcar&fast=1&layer=mapnik";
$result=RestClient::get($url,$inputs);
header("Content-type:text/xml");
echo($result->getResponse());?>
RESTclient.class.php
<?
/**
* Class RestClient
* Wraps HTTP calls using cURL, aimed for accessing and testing RESTful webservice.
* By Diogo Souza da Silva <manifesto#manifesto.blog.br>
*/
class RestClient {
private $curl ;
private $url ;
private $response ="";
private $headers = array();
private $method="GET";
private $params=null;
private $contentType = null;
private $file =null;
/**
* Private Constructor, sets default options
*/
private function __construct() {
$this->curl = curl_init();
curl_setopt($this->curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($this->curl,CURLOPT_AUTOREFERER,true); // This make sure will follow redirects
curl_setopt($this->curl,CURLOPT_FOLLOWLOCATION,true); // This too
curl_setopt($this->curl,CURLOPT_HEADER,true); // THis verbose option for extracting the headers
}
/**
* Execute the call to the webservice
* #return RestClient
*/
public function execute() {
if($this->method === "POST") {
curl_setopt($this->curl,CURLOPT_POST,true);
curl_setopt($this->curl,CURLOPT_POSTFIELDS,$this->params);
} else if($this->method == "GET"){
curl_setopt($this->curl,CURLOPT_HTTPGET,true);
$this->treatURL();
} else if($this->method === "PUT") {
curl_setopt($this->curl,CURLOPT_PUT,true);
$this->treatURL();
$this->file = tmpFile();
fwrite($this->file,$this->params);
fseek($this->file,0);
curl_setopt($this->curl,CURLOPT_INFILE,$this->file);
curl_setopt($this->curl,CURLOPT_INFILESIZE,strlen($this->params));
} else {
curl_setopt($this->curl,CURLOPT_CUSTOMREQUEST,$this->method);
}
if($this->contentType != null) {
curl_setopt($this->curl,CURLOPT_HTTPHEADER,array("Content-Type: ".$this->contentType));
}
curl_setopt($this->curl,CURLOPT_URL,$this->url);
$r = curl_exec($this->curl);
$this->treatResponse($r); // Extract the headers and response
return $this ;
}
/**
* Treats URL
*/
private function treatURL(){
if(is_array($this->params) && count($this->params) >= 1) { // Transform parameters in key/value pars in URL
if(!strpos($this->url,'?'))
$this->url .= '?' ;
foreach($this->params as $k=>$v) {
$this->url .= "&".urlencode($k)."=".urlencode($v);
}
}
return $this->url;
}
/*
* Treats the Response for extracting the Headers and Response
*/
private function treatResponse($r) {
if($r == null or strlen($r) < 1) {
return;
}
$parts = explode("\n\r",$r); // HTTP packets define that Headers end in a blank line (\n\r) where starts the body
while(preg_match('#HTTP/1.[0-1] 100 Continue#',$parts[0]) or preg_match("#Moved#",$parts[0])) {
// Continue header must be bypass
for($i=1;$i<count($parts);$i++) {
$parts[$i - 1] = trim($parts[$i]);
}
unset($parts[count($parts) - 1]);
}
preg_match("#Content-Type: ([a-zA-Z0-9-]+/?[a-zA-Z0-9-]*)#",$parts[0],$reg);// This extract the content type
$this->headers['content-type'] = $reg[1];
preg_match("#HTTP/1.[0-1] ([0-9]{3}) ([a-zA-Z ]+)#",$parts[0],$reg); // This extracts the response header Code and Message
$this->headers['code'] = $reg[1];
$this->headers['message'] = $reg[2];
$this->response = "";
for($i=1;$i<count($parts);$i++) {//This make sure that exploded response get back togheter
if($i > 1) {
$this->response .= "\n\r";
}
$this->response .= $parts[$i];
}
}
/*
* #return array
*/
public function getHeaders() {
return $this->headers;
}
/*
* #return string
*/
public function getResponse() {
return $this->response ;
}
/*
* HTTP response code (404,401,200,etc)
* #return int
*/
public function getResponseCode() {
return (int) $this->headers['code'];
}
/*
* HTTP response message (Not Found, Continue, etc )
* #return string
*/
public function getResponseMessage() {
return $this->headers['message'];
}
/*
* Content-Type (text/plain, application/xml, etc)
* #return string
*/
public function getResponseContentType() {
return $this->headers['content-type'];
}
/**
* This sets that will not follow redirects
* #return RestClient
*/
public function setNoFollow() {
curl_setopt($this->curl,CURLOPT_AUTOREFERER,false);
curl_setopt($this->curl,CURLOPT_FOLLOWLOCATION,false);
return $this;
}
/**
* This closes the connection and release resources
* #return RestClient
*/
public function close() {
curl_close($this->curl);
$this->curl = null ;
if($this->file !=null) {
fclose($this->file);
}
return $this ;
}
/**
* Sets the URL to be Called
* #return RestClient
*/
public function setUrl($url) {
$this->url = $url;
return $this;
}
/**
* Set the Content-Type of the request to be send
* Format like "application/xml" or "text/plain" or other
* #param string $contentType
* #return RestClient
*/
public function setContentType($contentType) {
$this->contentType = $contentType;
return $this;
}
/**
* Set the Credentials for BASIC Authentication
* #param string $user
* #param string $pass
* #return RestClient
*/
public function setCredentials($user,$pass) {
if($user != null) {
curl_setopt($this->curl,CURLOPT_HTTPAUTH,CURLAUTH_BASIC);
curl_setopt($this->curl,CURLOPT_USERPWD,"{$user}:{$pass}");
}
return $this;
}
/**
* Set the Request HTTP Method
* For now, only accepts GET and POST
* #param string $method
* #return RestClient
*/
public function setMethod($method) {
$this->method=$method;
return $this;
}
/**
* Set Parameters to be send on the request
* It can be both a key/value par array (as in array("key"=>"value"))
* or a string containing the body of the request, like a XML, JSON or other
* Proper content-type should be set for the body if not a array
* #param mixed $params
* #return RestClient
*/
public function setParameters($params) {
$this->params=$params;
return $this;
}
/**
* Creates the RESTClient
* #param string $url=null [optional]
* #return RestClient
*/
public static function createClient($url=null) {
$client = new RestClient ;
if($url != null) {
$client->setUrl($url);
}
return $client;
}
/**
* Convenience method wrapping a commom POST call
* #param string $url
* #param mixed params
* #param string $user=null [optional]
* #param string $password=null [optional]
* #param string $contentType="multpary/form-data" [optional] commom post (multipart/form-data) as default
* #return RestClient
*/
public static function post($url,$params=null,$user=null,$pwd=null,$contentType="multipart/form-data") {
return self::call("POST",$url,$params,$user,$pwd,$contentType);
}
/**
* Convenience method wrapping a commom PUT call
* #param string $url
* #param string $body
* #param string $user=null [optional]
* #param string $password=null [optional]
* #param string $contentType=null [optional]
* #return RestClient
*/
public static function put($url,$body,$user=null,$pwd=null,$contentType=null) {
return self::call("PUT",$url,$body,$user,$pwd,$contentType);
}
/**
* Convenience method wrapping a commom GET call
* #param string $url
* #param array params
* #param string $user=null [optional]
* #param string $password=null [optional]
* #return RestClient
*/
public static function get($url,array $params=null,$user=null,$pwd=null) {
return self::call("GET",$url,$params,$user,$pwd);
}
/**
* Convenience method wrapping a commom delete call
* #param string $url
* #param array params
* #param string $user=null [optional]
* #param string $password=null [optional]
* #return RestClient
*/
public static function delete($url,array $params=null,$user=null,$pwd=null) {
return self::call("DELETE",$url,$params,$user,$pwd);
}
/**
* Convenience method wrapping a commom custom call
* #param string $method
* #param string $url
* #param string $body
* #param string $user=null [optional]
* #param string $password=null [optional]
* #param string $contentType=null [optional]
* #return RestClient
*/
public static function call($method,$url,$body,$user=null,$pwd=null,$contentType=null) {
return self::createClient($url)
->setParameters($body)
->setMethod($method)
->setCredentials($user,$pwd)
->setContentType($contentType)
->execute()
->close();
}
}
?>
There's no problem in the xml. the problem you see in your browser is due to the empty characters before the start of the xml tag.
If you do a var_dump you'll see something like:
string(5726) " <--- carriage return
<?xml version="1.0" encoding="UTF-8"?>
You should change the treatResponse() method on the class, I solved it like this:
private function treatResponse($r) {
....
for($i=1;$i<count($parts);$i++) {
if($i > 1) {
$this->response .= "\n\r";
}
$this->response .= trim($parts[$i]);
}
}
hope this helps
Note: that empty line comes from the HTTP protocol that says that there should be an empty line after the headers http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_message
There is a line break before the xml declaration in the output because RestClient::treatResponse($r) doesn't "treat" the response as it should ;-)
I'd rather set curl_setopt($this->curl,CURLOPT_HEADER, false) in the constructor and reduce treatResponse() to
private function treatResponse($r) {
$this->response = $r;
$this->headers['content-type'] = curl_getinfo($this->curl, CURLINFO_CONTENT_TYPE);
$this->headers['code'] = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
// ok, that's not exactly the same ....
$this->headers['message'] = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
}
Ran your code - only error I got was:
Notice: Undefined variable: inputs
Removing $inputs - no errors
This worked for me
<?php
require_once("RESTclient.class.php");
$url="http://www.yournavigation.org/api/1.0/gosmore.php?format=kml&flat=52.215676&flon=5.963946&tlat=52.2573&tlon=6.1799&v=motorcar&fast=1&layer=mapnik";
$result=RestClient::get($url); // removed $input as suggested by Dan J
header("Content-type:text/xml");
echo(trim($result->getResponse())); // added trim to remove blank line before
// xml declaration
?>

swift mailer error 'Swift_RfcComplianceException' on an email that actually works?

My swift mailer plugin has just thrown up an error because an email address it tried to send to isn't compliant. Problem is - the email is valid.
Basically, I don't want swift mailer to be checking whether or not the email is valid I'd like it send regardless. Is that possible?
here is the code which has the function which displays the error but I don't know if what I would need to change is in here or not (kinda a hack programmer :| )
//#require 'Swift/Mime/Headers/AbstractHeader.php';
//#require 'Swift/Mime/HeaderEncoder.php';
/**
* A Mailbox Address MIME Header for something like From or Sender.
* #package Swift
* #subpackage Mime
* #author Chris Corbyn
*/
class Swift_Mime_Headers_MailboxHeader extends Swift_Mime_Headers_AbstractHeader
{
/**
* The mailboxes used in this Header.
* #var string[]
* #access private
*/
private $_mailboxes = array();
/**
* Creates a new MailboxHeader with $name.
* #param string $name of Header
* #param Swift_Mime_HeaderEncoder $encoder
*/
public function __construct($name, Swift_Mime_HeaderEncoder $encoder)
{
$this->setFieldName($name);
$this->setEncoder($encoder);
$this->initializeGrammar();
}
/**
* Get the type of Header that this instance represents.
* #return int
* #see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* #see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_MAILBOX;
}
/**
* Set the model for the field body.
* This method takes a string, or an array of addresses.
* #param mixed $model
* #throws Swift_RfcComplianceException
*/
public function setFieldBodyModel($model)
{
$this->setNameAddresses($model);
}
/**
* Get the model for the field body.
* This method returns an associative array like {#link getNameAddresses()}
* #return array
* #throws Swift_RfcComplianceException
*/
public function getFieldBodyModel()
{
return $this->getNameAddresses();
}
/**
* Set a list of mailboxes to be shown in this Header.
* The mailboxes can be a simple array of addresses, or an array of
* key=>value pairs where (email => personalName).
* Example:
* <code>
* <?php
* //Sets two mailboxes in the Header, one with a personal name
* $header->setNameAddresses(array(
* 'chris#swiftmailer.org' => 'Chris Corbyn',
* 'mark#swiftmailer.org' //No associated personal name
* ));
* ?>
* </code>
* #param string|string[] $mailboxes
* #throws Swift_RfcComplianceException
* #see __construct()
* #see setAddresses()
* #see setValue()
*/
public function setNameAddresses($mailboxes)
{
$this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes);
$this->setCachedValue(null); //Clear any cached value
}
/**
* Get the full mailbox list of this Header as an array of valid RFC 2822 strings.
* Example:
* <code>
* <?php
* $header = new Swift_Mime_Headers_MailboxHeader('From',
* array('chris#swiftmailer.org' => 'Chris Corbyn',
* 'mark#swiftmailer.org' => 'Mark Corbyn')
* );
* print_r($header->getNameAddressStrings());
* // array (
* // 0 => Chris Corbyn <chris#swiftmailer.org>,
* // 1 => Mark Corbyn <mark#swiftmailer.org>
* // )
* ?>
* </code>
* #return string[]
* #throws Swift_RfcComplianceException
* #see getNameAddresses()
* #see toString()
*/
public function getNameAddressStrings()
{
return $this->_createNameAddressStrings($this->getNameAddresses());
}
/**
* Get all mailboxes in this Header as key=>value pairs.
* The key is the address and the value is the name (or null if none set).
* Example:
* <code>
* <?php
* $header = new Swift_Mime_Headers_MailboxHeader('From',
* array('chris#swiftmailer.org' => 'Chris Corbyn',
* 'mark#swiftmailer.org' => 'Mark Corbyn')
* );
* print_r($header->getNameAddresses());
* // array (
* // chris#swiftmailer.org => Chris Corbyn,
* // mark#swiftmailer.org => Mark Corbyn
* // )
* ?>
* </code>
* #return string[]
* #see getAddresses()
* #see getNameAddressStrings()
*/
public function getNameAddresses()
{
return $this->_mailboxes;
}
/**
* Makes this Header represent a list of plain email addresses with no names.
* Example:
* <code>
* <?php
* //Sets three email addresses as the Header data
* $header->setAddresses(
* array('one#domain.tld', 'two#domain.tld', 'three#domain.tld')
* );
* ?>
* </code>
* #param string[] $addresses
* #throws Swift_RfcComplianceException
* #see setNameAddresses()
* #see setValue()
*/
public function setAddresses($addresses)
{
return $this->setNameAddresses(array_values((array) $addresses));
}
/**
* Get all email addresses in this Header.
* #return string[]
* #see getNameAddresses()
*/
public function getAddresses()
{
return array_keys($this->_mailboxes);
}
/**
* Remove one or more addresses from this Header.
* #param string|string[] $addresses
*/
public function removeAddresses($addresses)
{
$this->setCachedValue(null);
foreach ((array) $addresses as $address)
{
unset($this->_mailboxes[$address]);
}
}
/**
* Get the string value of the body in this Header.
* This is not necessarily RFC 2822 compliant since folding white space will
* not be added at this stage (see {#link toString()} for that).
* #return string
* #throws Swift_RfcComplianceException
* #see toString()
*/
public function getFieldBody()
{
//Compute the string value of the header only if needed
if (is_null($this->getCachedValue()))
{
$this->setCachedValue($this->createMailboxListString($this->_mailboxes));
}
return $this->getCachedValue();
}
// -- Points of extension
/**
* Normalizes a user-input list of mailboxes into consistent key=>value pairs.
* #param string[] $mailboxes
* #return string[]
* #access protected
*/
protected function normalizeMailboxes(array $mailboxes)
{
$actualMailboxes = array();
foreach ($mailboxes as $key => $value)
{
if (is_string($key)) //key is email addr
{
$address = $key;
$name = $value;
}
else
{
$address = $value;
$name = null;
}
$this->_assertValidAddress($address);
$actualMailboxes[$address] = $name;
}
return $actualMailboxes;
}
/**
* Produces a compliant, formatted display-name based on the string given.
* #param string $displayName as displayed
* #param boolean $shorten the first line to make remove for header name
* #return string
* #access protected
*/
protected function createDisplayNameString($displayName, $shorten = false)
{
return $this->createPhrase($this, $displayName,
$this->getCharset(), $this->getEncoder(), $shorten
);
}
/**
* Creates a string form of all the mailboxes in the passed array.
* #param string[] $mailboxes
* #return string
* #throws Swift_RfcComplianceException
* #access protected
*/
protected function createMailboxListString(array $mailboxes)
{
return implode(', ', $this->_createNameAddressStrings($mailboxes));
}
// -- Private methods
/**
* Return an array of strings conforming the the name-addr spec of RFC 2822.
* #param string[] $mailboxes
* #return string[]
* #access private
*/
private function _createNameAddressStrings(array $mailboxes)
{
$strings = array();
foreach ($mailboxes as $email => $name)
{
$mailboxStr = $email;
if (!is_null($name))
{
$nameStr = $this->createDisplayNameString($name, empty($strings));
$mailboxStr = $nameStr . ' <' . $mailboxStr . '>';
}
$strings[] = $mailboxStr;
}
return $strings;
}
/**
* Throws an Exception if the address passed does not comply with RFC 2822.
* #param string $address
* #throws Exception If invalid.
* #access protected
*/
private function _assertValidAddress($address)
{
if (!preg_match('/^' . $this->getGrammar('addr-spec') . '$/D',
$address))
{
throw new Swift_RfcComplianceException(
'Address in mailbox given [' . $address .
'] does not comply with RFC 2822, 3.6.2.'
);
}
}
}
Any suggestions?
note: swiftmailer is working for most email addresses.
Ignoring the overall picture of your question, to turn off the RFC error in this code change _assertValidAddress() like this:
private function _assertValidAddress($address)
{
if (!preg_match('/^' . $this->getGrammar('addr-spec') . '$/D',
$address))
{
//throw new Swift_RfcComplianceException(
// 'Address in mailbox given [' . $address .
// '] does not comply with RFC 2822, 3.6.2.'
// );
}
}
Also, just to let you know, in the latest version, do the same but you need to declare getDefinition. This is the latest version of the code:
private function _assertValidAddress($address){
if (!preg_match('/^' . $this->getGrammar()->getDefinition('addr-spec') . '$/D',
$address))
{
//throw new Swift_RfcComplianceException(
// 'Address in mailbox given [' . $address .
// '] does not comply with RFC 2822, 3.6.2.'
// );
}
}
You also cannot remove the final if call to send the email. See the bottom of my code, the if call actually sends the email, remove the comments or comment them out if you wish to include this within another PHP file.
<?php
// Explosiveentertainment.co.uk //halal.cc
include_once "lib/swift_required.php";
/*
* Create the body of the message (a plain-text and an HTML version).
* $text is your plain-text email
* $html is your html version of the email
* If the reciever is able to view html emails then only the html
* email will be displayed
*/
$text = "Hi!\nHow are you?\n";
$html = <<<EOM
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
</p>
</body>
</html>
EOM;
// This is your From email address
$from = array('yourcompany#yourcompany.com' => 'Name To Appear');
// Email recipients
$to = array(
'destination1#example.com'=>'Destination 1 Name',
'destination2#example.com'=>'Destination 2 Name'
);
// Email subject
$subject = 'Example PHP Email';
// Login credentials
$username = 'yoursendgridusername';
$password = 'yourpassword';
// Setup Swift mailer parameters
$transport = Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587);
$transport->setUsername($username);
$transport->setPassword($password);
$swift = Swift_Mailer::newInstance($transport);
// Create a message (subject)
$message = new Swift_Message($subject);
// attach the body of the email
$message->setFrom($from);
$message->setBody($html, 'text/html');
$message->setTo($to);
$message->addPart($text, 'text/plain');
// send message
if ($recipients = $swift->send($message, $failures))
{
// This will let us know how many users received this message
echo 'Message sent out to '.$recipients.' users';
}
// something went wrong =(
else
{
echo "Something went wrong - ";
print_r($failures);
}

Categories