CakePHP routes regular expression for unicode - regex

I want to do the following change in CakePHP routes. Any word or group of words (separated by hyphen) after a website URL like example.com/someword or example.com/some-word should be redirected to controller => posts, action => view. But my problem is that the word(s) should be in unicode. I have tried this regular expression for URL text, but it does not work.
Router::connect ( '/:link', array ('controller' => 'posts', 'action' => 'view' ), array ('pass' => array ('link'), 'link' => '/^['.json_decode('"\u0531"').'-'.json_decode('"\u0587"').'-]+$/u' ) );
I want to mention though, that my regex
'/^['.json_decode('"\u0531"').'-'.json_decode('"\u0587"').'-]+$/u',
works just fine if I am about to do some usual preg_match like
$regg = '/^['.json_decode('"\u0531"').'-'.json_decode('"\u0587"').'-]+$/u';
if (preg_match($regg, "my unicode string", $match)) {
var_dump($match); // outputs string as expected
}
die;
EDIT
I end up having this code
Router::connect ( '/:link', array ('controller' => 'posts', 'action' => 'view' ), array ('pass' => array ('link'), 'link' => '((?![a-zA-Z]).)+' ) );
like making my url to contain everything, but English letters, but this is not the thing I need, if I have 2 or more different languages than English - this method won't work. So, I want to send each language's word into separate action.
cake version 2.x
EDIT 2
There are alternative solutions, like in answers below, to bypass the question, but I am looking for the exact way of doing what I need.
Thanks

From http://en.wikipedia.org/wiki/Query_string at URL encoding paragraph you can't use these chars on a url query string:
In particular, encoding the query string uses the following rules:
Letters (A–Z and a–z), numbers (0–9) and the characters '.','-','~' and '_' are left as-is
SPACE is encoded as '+' or "%20" [8]
All other characters are encoded as %HH hex representation with any non-ASCII characters first encoded as UTF-8 (or other specified
encoding)
If you have two (or more) languages you can consider add on posts table one slug field for each language, for example with english and russian:
posts
id
title_eng
title_rus
slug_eng
slug_rus
On Post.php beforeValidate or beforeSave:
if(isset($this->data['Post']['title_eng'])){
$this->data['Post']['slug_eng'] = Inflector::slug(strtolower($this->data['Post']['title_eng']), '-');
}
if(isset($this->data['Post']['title_rus'])){
$this->data['Post']['slug_rus'] = Inflector::slug(strtolower($this->data['Post']['title_rus']), '-');
}
The link inside a view:
echo $this->Html->link($post['Post']['title_eng'], array('controller' => 'posts', 'action' => 'view', 'slug_eng' => $post['Post']['slug_eng']));
echo $this->Html->link($post['Post']['title_rus'], array('controller' => 'posts', 'action' => 'view', 'slug_rus' => $post['Post']['slug_rus']));
The route:
Router::connect('/posts/:slug_eng', array('controller' => 'posts','action' => 'view', 'eng'), array('pass' => array('slug_eng'), 'slug_eng' => '[a-zA-Z0-9]+'));
Router::connect('/ru/posts/:slug_rus', array('controller' => 'posts','action' => 'view', 'rus'), array('pass' => array('slug_rus'), 'slug_rus' => '[a-zA-Z0-9]+'));
The controller Posts:
public function view($locale, $slug){
....
validate and sanitize here
...
$post = $this->Post->find('first', array('conditions' => array('slug_' . $locale => $slug)));
....
}

I suggest to use wildcard
Router::connect('/*', array('controller' => 'posts', 'action' => 'view'));
Any other routes can be added before this line, for example
Router::connect('/:digits', array('controller' => 'posts', 'action' => 'view'), array('pass' => array('digits'), 'digits' => '/d+');
Router::connect('/*', array('controller' => 'posts', 'action' => 'view'));

Related

notepad++ regular expression result deleted ()

I'm trying to add a prefix to the string:
array(
'id'=>'page-comment',
'type' => 'switch',
'title' => 'Show Comment Form on Page',
'default' => '0',
'on' => 'Yes',
'off' => 'No',
),
Replace: 'title' => '(.*)'
to: 'title' => __('\1\9', 'venedor')
result
'title' => __'Show Comment Form on Page', 'venedor',
I need to characters () remained the same.
Line should look like result
'title' => __('Show Comment Form on Page', 'venedor'),
You're close, you have to escape the parenthesis even in the replacement part:
'title' => __\('$1', 'venedor'\)
It' a Npp "feature"

CakePHP - Router::url doesn't build pretty URLs when there's a regex match in the Router::connect

In my CakePHP, my routes.php file looks like this:
Router::connect('/premios/:category',
array('controller' => 'prizes', 'action' => 'category'),
array(
'category' => '\bmarcas|restaurantes|combustibles|peluqueria\b',
));
This way whenever a user enters the /premios url, the next parameter is matched with the "category" regex. This works perfect.
The problem is that when I want to generate a pretty url for the category, let's say, "peluqueria", using this line of code generates a "non-pretty" url:
Router::url(array('controller' => 'prizes', 'action' => 'category', 'peluqueria')); ?>
Instead of generating a pretty URL (/premios/peluqueria) it generates a non pretty url (/prizes/category/peluqueria).
What am I doing wrong? Or is this a limitation of the Router::url function?
A workaround would be to define every connect, avoiding the regex, but it isn't a pretty as the current solution plus it would get annoying when the categories count start to grow.
Any ideas?
You have to actually name the category parameter in Router::url, like this
Router::url(array('controller' => 'prizes',
'action' => 'category',
'category' => 'peluqueria'));
And you'd probably want to pass that "category" parameter to the category action in Prizes, so you're missing something
Router::connect(
'/premios/:category',
array('controller' => 'prizes', 'action' => 'category'),
array(
'pass' => array('category'),
'category' => '\bmarcas|restaurantes|combustibles|peluqueria\b'
)
);
Look this part of the docs with more detention :)

How to exclude characters from a RegEx pattern with category property codes?

There is a number of category property codes (see part "Unicode character properties"), that can be used for a Perl-compatible Regular Expression (PCRE)
I defined a regex pattern (named subpattern), that should match letters (\p{L}), numbers (\p{N}), the space separator (\p{Zs}), but also the punctuation (\p{P}).
(?<sport>[\p{L}\p{N}\p{Zs}\p{P}]*)
Since I'm using that for URL routing, the slashes should be excluded. How can I do that?
EDIT:
Addtitional information about the context: The pattern is used for a route definition in a Zend Framework 2 module.
/Catalog/config/module.config.php
<?php
return array(
...
'router' => array(
'routes' => array(
...
'sport' => array(
'type' => 'MyNamespace\Mvc\Router\Http\UnicodeRegex',
'options' => array(
'regex' => '/catalog/(?<city>[\p{L}\p{Zs}]*)/(?<sport>[\p{L}\p{N}\p{Zs}\p{P}]*)',
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-courses',
),
'spec' => '/catalog/%city%/%sport%',
),
'may_terminate' => true,
'child_routes' => array(
'courses' => array(
'type' => 'segment',
'options' => array(
'route' => '[/page/:page]',
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-courses',
),
),
'may_terminate' => true,
),
)
),
),
),
...
);
You can use negative look-ahead to exclude some character from your character set. For your example:
(?<sport>(?:(?!/)[\p{L}\p{N}\p{Zs}\p{P}])*)
Basically, you will check that the next character is not / with negative look-ahead (?!/), before proceeding to check whether that character belongs to the character set [\p{L}\p{N}\p{Zs}\p{P}].
PCRE doesn't have set intersection or set difference feature, so this is the work-around for that.
Since you use it for URL parsing:
According to RFC 1738 only $-_.+!*'(), are allowed unencoded in an URL¹, so instead of using \pP (yes that is allowed instead of \p{P}), I suggest you use these characters directly in your regex.
Edit: But if that's not an option, this should be a starting point
(?:([\p{L}\p{N}\p{Zs}\p{P}]+?)(?=/|\?|#|$))
kind regards,
Tom
¹: Not entirely true, but /##;?&= are only allowed unencoded if they should have their special meaning.

cakephp route to not allow file extension

I need a cakephp route which will catch all urls if not matched in previous routes that do not contain file extensions.
Current route for catch all below
Router::connect('/*', array('controller' => 'frontend', 'action' => 'display',null));
I need the above route modified to not all urls with file extensions to be caught
What I have donr in my app based on CakePHP 1.2 to add extension to dynamic generated images is as follows:
Router::connect('/postImage/*', array('controller' => 'posts','action' => 'postImage', 'url' => array('ext' => 'png')));
The above code makes both the folloing url are accesible:
http://myhost.com/posts/postImage/125
and
http://myhost.com/posts/postImage/125.png
I think that the same will going with CakePHP 1.3 and I hope that It helps you.
I don't understand very well your demand, but you can do this:
Router::parseExtensions('html');
Router::connect('/*/:title', array('controller' => 'frontend', 'action' => 'display',null),
array(
'pass' => array('title')
)
);
And the link:
$html->link('Title', array('controller' => 'frontend', 'action' => 'display', 'title' => Inflector::slug('text to slug', '-'), 'ext' => 'html'))
I hope this will help you. good luck

ZF routing - url with extension with Nth params

Similar to this question, I have accomplished passing the format with the url extension, but you have have to declare the parameters passed upfront. Example:
new Zend_Controller_Router_Route_Regex(
'([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)(\.(\w+))?',
array(
'module' => 'Default',
'controller' => 'index',
'action' => 'index',
),
array(
1 => 'module',
2 => 'controller',
3 => 'action',
4 => 'extension',
5 => 'format'
)
);
But what if I want /:module/:controller/:action/*.:format???
So that no matter how many parameters I pass through the url, the '.whatever' will be the format parameter? Basically, I'm trying to take the default router and add extension as the 'format param'.
Edit:
The issue isn't grabbing the extension, the issue is adding other params. For example
/blogs/posts/view/post/500/foo/bar/format/html
will translate into:
array('module'=>'blogs','controller'=>'posts', 'action' => 'view', 'post'=>500, 'format' => 'html', 'foo' => 'bar');
But I want to be able to represent the format the same route like so:
/blogs/post/view/post/500/foo/bar.html
No matter how many parameters are declared between the action and the format.
Your whatever you can specify with .* expression.
To match it - simply: (.*)
If you want not to grab for example extension, use ?:
(.*?)(\.(\w+))