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.
I am trying to install laravel-referer-redirector taking referance from the url listed below. But its not working.
http://www.wallogit.com/composer/type/3.library/appstract/135193.laravel-referer-redirector
Installation goes well but after that when running the below command it throws error
php artisan vendor:publish --provider="Appstract\RefererRedirector\RefererRedirectorServiceProvider"
Error =>
php artisan vendor:publish
--provider="Appstract\RefererRedirector\RefererRedirectorServiceProvider"
{"error":{"type":"Symfony\Component\Debug\Exception\FatalThrowableError","message":"Class
'Appstract\RefererRedirector\RefererRedirectorServiceProvider::class'
not
found","file":"/var/www/html/wyskill/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php","line":157}}
ProvderRepository.php =>
<?php namespace Illuminate\Foundation;
use Illuminate\Filesystem\Filesystem;
class ProviderRepository {
/**
* The filesystem instance.
*
* #var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* The path to the manifest.
*
* #var string
*/
protected $manifestPath;
/**
* Default manifest structure.
*
* #var array
*/
protected $default = array('when' => array());
/**
* Create a new service repository instance.
*
* #param \Illuminate\Filesystem\Filesystem $files
* #param string $manifestPath
* #return void
*/
public function __construct(Filesystem $files, $manifestPath)
{
$this->files = $files;
$this->manifestPath = $manifestPath;
}
/**
* Register the application service providers.
*
* #param \Illuminate\Foundation\Application $app
* #param array $providers
* #return void
*/
public function load(Application $app, array $providers)
{
$manifest = $this->loadManifest();
// First we will load the service manifest, which contains information on all
// service providers registered with the application and which services it
// provides. This is used to know which services are "deferred" loaders.
if ($this->shouldRecompile($manifest, $providers))
{
$manifest = $this->compileManifest($app, $providers);
}
// If the application is running in the console, we will not lazy load any of
// the service providers. This is mainly because it's not as necessary for
// performance and also so any provided Artisan commands get registered.
if ($app->runningInConsole())
{
$manifest['eager'] = $manifest['providers'];
}
// Next, we will register events to load the providers for each of the events
// that it has requested. This allows the service provider to defer itself
// while still getting automatically loaded when a certain event occurs.
foreach ($manifest['when'] as $provider => $events)
{
$this->registerLoadEvents($app, $provider, $events);
}
// We will go ahead and register all of the eagerly loaded providers with the
// application so their services can be registered with the application as
// a provided service. Then we will set the deferred service list on it.
foreach ($manifest['eager'] as $provider)
{
$app->register($this->createProvider($app, $provider));
}
$app->setDeferredServices($manifest['deferred']);
}
/**
* Register the load events for the given provider.
*
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #param array $events
* #return void
*/
protected function registerLoadEvents(Application $app, $provider, array $events)
{
if (count($events) < 1) return;
$app->make('events')->listen($events, function() use ($app, $provider)
{
$app->register($provider);
});
}
/**
* Compile the application manifest file.
*
* #param \Illuminate\Foundation\Application $app
* #param array $providers
* #return array
*/
protected function compileManifest(Application $app, $providers)
{
// The service manifest should contain a list of all of the providers for
// the application so we can compare it on each request to the service
// and determine if the manifest should be recompiled or is current.
$manifest = $this->freshManifest($providers);
foreach ($providers as $provider)
{
$instance = $this->createProvider($app, $provider);
// When recompiling the service manifest, we will spin through each of the
// providers and check if it's a deferred provider or not. If so we'll
// add it's provided services to the manifest and note the provider.
if ($instance->isDeferred())
{
foreach ($instance->provides() as $service)
{
$manifest['deferred'][$service] = $provider;
}
$manifest['when'][$provider] = $instance->when();
}
// If the service providers are not deferred, we will simply add it to an
// of eagerly loaded providers that will be registered with the app on
// each request to the applications instead of being lazy loaded in.
else
{
$manifest['eager'][] = $provider;
}
}
return $this->writeManifest($manifest);
}
/**
* Create a new provider instance.
*
* #param \Illuminate\Foundation\Application $app
* #param string $provider
* #return \Illuminate\Support\ServiceProvider
*/
public function createProvider(Application $app, $provider)
{
return new $provider($app);
}
/**
* Determine if the manifest should be compiled.
*
* #param array $manifest
* #param array $providers
* #return bool
*/
public function shouldRecompile($manifest, $providers)
{
return is_null($manifest) || $manifest['providers'] != $providers;
}
/**
* Load the service provider manifest JSON file.
*
* #return array
*/
public function loadManifest()
{
$path = $this->manifestPath.'/services.json';
// The service manifest is a file containing a JSON representation of every
// service provided by the application and whether its provider is using
// deferred loading or should be eagerly loaded on each request to us.
if ($this->files->exists($path))
{
$manifest = json_decode($this->files->get($path), true);
return array_merge($this->default, $manifest);
}
}
/**
* Write the service manifest file to disk.
*
* #param array $manifest
* #return array
*/
public function writeManifest($manifest)
{
$path = $this->manifestPath.'/services.json';
$this->files->put($path, json_encode($manifest, JSON_PRETTY_PRINT));
return $manifest;
}
/**
* Create a fresh manifest array.
*
* #param array $providers
* #return array
*/
protected function freshManifest(array $providers)
{
list($eager, $deferred) = array(array(), array());
return compact('providers', 'eager', 'deferred');
}
/**
* Get the filesystem instance.
*
* #return \Illuminate\Filesystem\Filesystem
*/
public function getFilesystem()
{
return $this->files;
}
}
Please guide accordingly. I am using Laravel 4.2.
I have try to create a Custom REST POST plugin in my Drupal 8.3.2 for get an external JSON and then create an article from that.
I have follow that guide: How to create Custom Rest Resources for POST methods in Drupal 8
And this is my code:
<?php
namespace Drupal\import_json_test\Plugin\rest\resource;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\node\Entity\Node;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Psr\Log\LoggerInterface;
/**
* Provides a resource to get view modes by entity and bundle.
*
* #RestResource(
* id = "tio_rest_json_source",
* label = #Translation("Tio rest json source"),
* serialization_class = "Drupal\node\Entity\Node",
* uri_paths = {
* "canonical" = "/api/custom/",
* "https://www.drupal.org/link-relations/create" = "/api/custom"
* }
* )
*/
class TioRestJsonSource extends ResourceBase {
/**
* A current user instance.
*
* #var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* Constructs a new TioRestJsonSource object.
*
* #param array $configuration
* A configuration array containing information about the plugin
instance.
* #param string $plugin_id
* The plugin_id for the plugin instance.
* #param mixed $plugin_definition
* The plugin implementation definition.
* #param array $serializer_formats
* The available serialization formats.
* #param \Psr\Log\LoggerInterface $logger
* A logger instance.
* #param \Drupal\Core\Session\AccountProxyInterface $current_user
* A current user instance.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
array $serializer_formats,
LoggerInterface $logger,
AccountProxyInterface $current_user) {
parent::__construct($configuration, $plugin_id,
$plugin_definition, $serializer_formats, $logger);
$this->currentUser = $current_user;
}
/**
* {#inheritdoc}
*/
public static function create(ContainerInterface $container, array
$configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->getParameter('serializer.formats'),
$container->get('logger.factory')->get('import_json_test'),
$container->get('current_user')
);
}
/**
* Responds to POST requests.
*
* Returns a list of bundles for specified entity.
*
* #param $data
*
* #param $node_type
*
* #return \Drupal\rest\ResourceResponse
*
* #throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function post($node_type, $data) {
// 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();
}
$node = Node::create(
array(
'type' => $node_type,
'title' => $data->title->value,
'body' => [
'summary' => '',
'value' => $data->body->value,
'format' => 'full_html',
],
)
);
$node->save();
return new ResourceResponse($node);
}
}
Now if i try to test this without passing a payload and modifing the return value in this way:
return new ResourceResponse(array('test'=>'OK'));
It's working!
But if i send a custom payload like this using my custom code above:
{
"title": [{
"value": "Test Article custom rest"
}],
"type": [{
"target_id": "article"
}],
"body": [{"value": "article test custom"}]
}
I recieve a 400 Error with: Symfony\Component\HttpKernel\Exception\BadRequestHttpException: The type link relation must be specified. in Drupal\rest\RequestHandler->handle() (line 103 of core/modules/rest/src/RequestHandler.php).
What's going Wrong?
Thx.
I have find a solution:
I have removed the annotation:
* serialization_class = "Drupal\node\Entity\Node",
Then i take care just for data in my post function:
/**
* Responds to POST requests.
*
* Returns a list of bundles for specified entity.
*
* #param $data
*
*
* #return \Drupal\rest\ResourceResponse
*
* #throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function post($data) {
// 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();
}
return new ResourceResponse(var_dump($data));
The important thing is, when you use postman for example, is to add an header with Content-Type -> application/json:
Instead of Content-Type -> application/hal+json
With this configuration i can post any type of JSON and then manage it as i prefer.
Bye!
I'm trying to make a custom redirect function. I have created a custom route function in a new file (helpers.php) that works fine:
if (! function_exists('cms_route')) {
/**
* Generate a URL to a named route with predefined cms path.
*
* #param string $name
* #param array $parameters
* #param bool $absolute
* #param \Illuminate\Routing\Route $route
* #return string
*/
function cms_route($name, $parameters = [], $absolute = true, $route = null)
{
return app('url')->route(config('constants.cms_path').'.'.$name, $parameters, $absolute, $route);
}
}
I'm trying to call this function with redirect()->cms_route('name') instead of redirect()->route('name')
So when the cms path is changed everything keeps working.
How would I accomplish this?
Added as quick fix:
if (! function_exists('cms_redirect')) {
/**
* Get an instance of the redirector.
*
* #param string $name
* #param array $parameters
* #param bool $absolute
* #param \Illuminate\Routing\Route $route
* #return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
*/
function cms_redirect($name, $parameters = [])
{
return redirect()->route(config('constants.cms_path').'.'.$name, $parameters);
}
}
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