I have this URL :
dev.local.co/fr/admin/quoteManag/addquote/numberModel/123456/5
when I want to get the parameter numberModel.
On var_dump I get just "123456", not "123456/5"
You can use urlencode
$parameter = urlencode('123456/5'); // 123456%2F5
echo urldecode($_GET['numberModel']); // 123456/5
Or in your router, create a regex that will accept the slash as part of the parameter.
$route = new Zend_Controller_Router_Route_Regex("numberModel/([0-9\/]*)", array("module" => "MODULE", "controller" => "CONTROLLER", "action" => "ACTION"), array(1 => "numberModel"));
Not 100% but if this was me, I would get the url, explode it using /
Get the last 2 from the array, implode them.
But it depends on how you get the url, do you have a rewrite rule?
If so then I would look in that and you need to just sharpen it up slightly.
Related
Hi I want to append the uri in laravel route function.
e.g we have /search?type=listing
//how do i can achieve this with
route('search',['type'=>'listing'])
Once the we are on the search. I want to have all the variable appended to search like
type=listing&query=blah blah
If I get you right, you want to save all query parameters. Use Request::query() to get it and then merge with your new parameters.
route('search', array_merge(\Request::query(), ['type' => 'listing'])));
If you have a named route and want to generate url with query params then:
route('route_name', ['param1' => 'value', 'param2' => 'value']);
In your case you can do this with
route('search',['type'=>'listing','subject' => ['blah'],[....]])
I am using CakePHP 2.4
I have a url for e.g. /sent?note=123&test=abc
I want to remove the note parameter while giving me the rest of the url back. i.e.
/sent?test=abc
I have a piece of code that works but only for query parameters. I would like to find out how to improve my code so that it works with:
named parameters
passed parameters
hashtag
E.g.
/sent/name1:value1?note=123&test=abc#top
This is the code I have written so far. https://github.com/simkimsia/UtilityComponents/blob/master/Controller/Component/RequestExtrasHandlerComponent.php#L79
UPDATE PART III:
Let me illustrate with more examples to demonstrate what I mean by a more generic answer.
The more generic answer should assume no prior knowledge about the url patterns.
Assuming given this url
/sent/name1:value1?note=123&test=abc
I want to get rid of only the query parameter note and get back
/sent/name1:value1?test=abc
The more generic solution should work to give me back this url.
Another example. This time to get rid of named parameters.
Assuming given this url again
/sent/name1:value1?note=123&test=abc
I want to get rid of name1 and get back:
/sent?note=123&test=abc
Once again, the more generic solution should be able to accomplish this as well.
UPDATE PART II:
I am looking for a more generic answer. Assuming the web app does not know the url is called sent. You also do not know if the query parameters contain the word note or test. How do I still accomplish the above?
I want to be able to use the same code for any actions. That way, I can package it into a Component to be reused easily.
UPDATE PART I:
I understand that hashtag will not be passed to PHP. So please ignore that.
Clues on how to get the values from the hashtag:
https://stackoverflow.com/a/7817134/80353
https://stackoverflow.com/a/940996/80353
What about using mod_rewrite ?
You can handle your URLS in an other way :
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^/sent/name:(.*)?note=(.*)&test=([az-AZ])(#(.*))$ /sent/name:$1/note:$2/test:$3$4
</IfModule>
I'm not sure about the regex, but this may pass variables to cakePHP in a clean way (but I haven't tested it, though)
[EDIT]
But if you want to work without knowing urls patterns, then you can use the $this->request array : with an URL like
action/id:10/test:sample?sothertest=othersample&lorem=ipsum
I can get all the arguments using this in my controller :
// In your controller's method
$arguments= array_merge_recursive($this->request->named,$this->request->query);
Then, $arguments will be an array containing both named and passed params :
array(
'id' => '10',
'test' => 'sample',
'sothertest' => 'othersample',
'lorem' => 'ipsum'
)
Is it better ?
[EDIT 2]
If you know which parameter you have to get rid of, and directly redirect to the new URL, this should work:
action/id:10/test:sample?knownParam=value&lorem=ipsum
or with
action/id:10/knownParam:value?othertest=othersample&lorem=ipsum
In your controller/appController action:
// Name of the known param
$knownParam = 'knownParam';
// Arguments
$arguments = array_merge_recursive($this->request->named, $this->request->query);
if (key_exists($knownParam, $arguments)) {
// Unset in named params:
unset($arguments[$knownParam]);
// Creating url:
$url = array(
'admin' => $this->request->params['prefix'],
'plugin' => $this->request->params['plugin'],
'controller' => $this->request->params['controller'],
'action' => $this->request->params['action']
);
// Adding args
foreach ($arguments as $k => $v) {
$url[$k] = $v;
}
// Redirect
$this->redirect($url);
}
This will redirect both urls to
action/id:10/param1:value1/param2:value2
without the "know param"...
Let us say you have created the following routes:
Router::connect('/projects/:id/quotations/:quotation_id/*',
array(
'controller' => 'quotations',
'action' => 'get_all_by_project', "[method]" => "GET"),
array(
'pass' => array('id', 'quotation_id'),
'id' => '[0-9]+',
'quotation_id' => '[0-9]+'
),
array(
'named' => array(
'name1',
'name2',
'name3'
)
)
);
In this route:
Passed parameters will be the compulsory parameters id and quotation_id obeying the order as the first and second passed parameter
Named parameters will be the optional parameters name1, name2, and name3.
Query parameters will, of course, be optional as well and depend on what you actually have in the url.
you need the asterisk at the end so that the named parameters can pass through
Let us assume the following pretty url and the ugly url of the same action:
/projects/1/quotations/23/name2:value2/name3:value3/name1:value1?note=abc&test=123 (pretty)
/quotations/get_all_by_project/1/23/name2:value2/name3:value3/name1:value1?note=abc&test=123 (ugly)
First part of the answer:
Let us consider only the scenario of removing the query parameter note.
We should get back
/projects/1/quotations/23/name2:value2/name3:value3/name1:value1?test=123 (pretty)
/quotations/get_all_by_project/1/23/name2:value2/name3:value3/name1:value1?test=123 (ugly)
The following Component method will work. I have tested it on both the ugly and pretty urls.
public function removeQueryParameters($parameters, $here = '') {
if (empty($here)) {
$here = $this->controller->request->here;
}
$query = $this->controller->request->query;
$validQueryParameters = array();
foreach($query as $param=>$value) {
if (!in_array($param, $parameters)) {
$validQueryParameters[$param] = $value;
}
}
$queryString = $this->_reconstructQueryString($validQueryParameters);
return $here . $queryString;
}
protected function _reconstructQueryString($queryParameters = array()) {
$queryString = '';
foreach($queryParameters as $param => $value) {
$queryString .= $param . '=' . $value . '&';
}
if (strlen($queryString) > 0) {
$queryString = substr($queryString, 0, strlen($queryString) - 1);
$queryString = '?' . $queryString;
}
return $queryString;
}
This is how you call the Component method.
$newUrl = $this->RequestExtrasHandler->removeQueryParameters(array('note'));
RequestExtrasHandler is the name of Component I wrote that has the above method.
Second part of the answer:
Let us consider only the scenario of removing the named parameter name2.
We should get back
/projects/1/quotations/23/name3:value3/name1:value1?test=123 (pretty)
/quotations/get_all_by_project/1/23/name3:value3/name1:value1?test=123 (ugly)
The following Component method will work. I have tested it on both the ugly and pretty urls.
public function removeNamedParameters($parameters, $here = '') {
if (empty($here)) {
$here = $this->controller->request->here;
}
$query = $this->controller->request->query;
$named = $this->controller->request->params['named'];
$newHere = $here;
foreach($named as $param=>$value) {
if (in_array($param, $parameters)) {
$namedString = $param . ':' . $value;
$newHere = str_replace($namedString, "", $newHere);
}
}
$queryString = $this->_reconstructQueryString($query);
return $newHere . $queryString;
}
This is how you call the Component method.
$newUrl = $this->RequestExtrasHandler->removeNamedParameters(array('name2'));
RequestExtrasHandler is the name of Component I wrote that has the above method.
Third part of the answer:
After I realized that passed parameters are compulsory, I found that there is no real business need to remove passed parameters if at all.
Another problem is that unlike named parameters and query parameters, passed parameters tend not to have the keys present in the $this->controller->request->params['pass']
$this->controller->request->params['pass'] is usually in the form of a numerically indexed array.
Hence, there is huge challenge to take out the correct passed parameters.
Because of that, I will not create any method to remove passed parameters.
Check out the code here in details:
https://github.com/simkimsia/UtilityComponents/blob/d044da690c7b83c72a50ab97bfa1843c14355507/Controller/Component/RequestExtrasHandlerComponent.php#L89
maybe simple php functions can do what you want
$url = '/sent?note=123&test=abc'; //for example
$unwanted_string = substr($url, 0,strrpos($url,'&') + 1);
$unwanted_string = str_replace('/sent?', '', $unwanted_string);
$url = str_replace($unwanted_string, '', $url);
I have this string that may contain some urls that I need to grab. For instance, if the user does:
www.youtube ...
or
www.vimeo ...
or
http://www.youtube ...
or
HttP://WwW.viMeo
I need to grab it (until he finds a space perhaps). and store it on a already created array.
The need is to separate the vimeo links from the youtube ones and place each of those on the appropriate video object.
I'm not sure if this is possible, I mean, if the URL coming from the browser could be used to be placed on a predefined video object. If it is, then this is the way to go (so I believe).
If all this is feasible, can I have your help in order to build such a rule?
Thanks in advance
This matches the links you need, and store them in a 2D array by site name:
$video_links = array();
if (preg_match_all("'(http://)?(www[.])?(youtube|vimeo)[^\s]+'is",$str,$n)) {
foreach ($n[3] as $key => $site)
{
$video_links[$site][] = $n[0][$key];
}
}
What does this do?
This match separates 3 + 1 parts of the needed urls in $str, which is your string:
Part 0: the whole match (your video link)
Part 1: http:// (optional)
Part 2: www. (optional)
Part 3: vimeo or youtube
preg_match_all returns a 2D array with the above part numbers at first level, and every match inside is the part of each match. So you iterate part 3 of the match ($n[3]), and use the array keys to reference part 0 ($n[0][$key]), and arrange them in a nice 2D array like this:
$video_links = array (
'vimeo' => array (
0 => 'vimeo link 1',
1 => 'vimeo link 2',
// ...
),
'youtube' => array (
0 => 'youtube link 1',
1 => 'youtube link 2',
// ...
)
);
What you should do is first replace all instance of http:// and www. with nothing, and then prepend it back on to the string, this makes the string consistent
str_replace(array("http://www.","http://"),"",$url);
$url = "http://" . $url;
then you can use parse_url to check the data like so
$Data = parse_url($url);
Then just check your values accordingly.
switch(strtolower($Data['host']))
{
case "youtube.com":
// :)
break;
case "vimeo.com":
// :)
break;
case "something.tld":
// :)
break;
}
The dump of $Data would output something like so:
[scheme] => http
[host] => youtube.com
[user] =>
[pass] =>
[path] => /watch
[query] => v=r8FVAHuQvjc&feature=topvideos
[fragment] =>
you can now just go
$lastSegment = $Data["path"] . "?" . $Data["query"];
which would return something like /watch?v=r8FVAHuQvjc&feature=topvideos
if you wanted individual items from the query such as the video id you can then go:
parse_str($Data["query"],$result);
echo $result["v"];
which would just output the video id.
I am working on the routing or uri's in my PHP app. Currently I have an array with a regex => url map like this...
<?php
$uri_routes = array(
//users/account like http://mysite.com/users/324 (any digit)
'users/friends/page-(\d+)' => 'modules/users/friends/page-$1',
'users/friends/' => 'modules/users/friends/',
'users/online' => 'modules/users/online/' ,
'users/online/page-(\d+)' => 'modules/users/online/page-$1',
'users/create' => 'modules/users/create',
'users/settings' => 'modules/users/settings',
'users/logout(\d+)' => 'modules/users/logout',
'users/login' => 'modules/users/login',
'users/home' => 'modules/users/home',
//forums
'forums/' => 'modules/forums/index',
'forums/viewthread/(\d+)' => 'modules/forums/viewthread/$1',
'forums/viewforum/(\d+)' => 'modules/forums/viewforum/$1',
'forums/viewthread/(\d+)/page-(\d+)' => 'modules/forums/viewthread/$1/page-$2',
'forums/viewforum/(\d+)/page-(\d+)' => 'modules/forums/viewforum/$1/page-$2'
//blog routes coming soon
//mail message routes coming soon
//various other routes coming soon
);
?>
I can then cycle through my $uri_routes map array and match a uri with preg_match() like this...
<?php
//get url from URL
$uri = isset($_GET['uri']) ? $_GET['uri'] : null;
//runs our function and returns an array
// $uri['module'] this will be the class/module/section
// $uri['method'] this will be the page in that section or method in that class
// $uri['urifragments'] this will either page a user ID, or an item ID or a page number for paging
$uri = get_route($_GET['uri'],$uri_routes);
function get_route($uri,$uri_routes)
{
foreach($uri_routes as $rUri => $rRoute)
{
if(preg_match("#^{$rUri}$#Ui",$uri))
{
$uri = preg_replace("#^{$rUri}$#Ui",$rRoute,$uri);
break;
}
}
$uri = explode('/',$uri);
$return['module'] = $uri['1'];
$return['method'] = $uri['2'];
$return['urifragments'] = $uri['3'];
$return['urifragments2'] = $uri['4'];
return $return;
}
I am open to an suggestion to improve this in any way. Right now I am stuck as there is 4 possible array key/values returned. If array key 3 or key 4 contains the word "page-" followed by a number, I would like to assign it to a $page variable. But if key 3 or key 4 contains just a number with no "page-" word, then I can assume it is a user ID, blog ID, forum ID, etc and assign it to an $id variable.
If you know a good approach to this, please help.
UPDATE
to simplify things, in addition to having "page-" in front of page numbers, I could have "id-" in front of id numbers
Instead of using $1 and $2 to match our routes try using named captures.
5.2.2 Named subpatterns now accept the syntax (?) and (?'name') as
well as (?P). Previous versions
accepted only (?P).
Source : preg_match
Also when you are doing a preg_replace you use \[0-99] where \0 is the whole string and \1 through \99 are the matches.
But if you are going to be using named captures you can assign an array to the $replacement parameter with the name capture (e.g. if you capture ?P<page> then you would pass an array('page'=>"new value of page")).
Hope that helps.
I have a problem with reverse for regex routes, my config file is below:
routes.route1.type = "Zend_Controller_Router_Route_Regex"
routes.route1.route = "([^\,]+)([^p]*)(?:\,page_[0-9]+)?\.html"
routes.route1.defaults.controller = "index"
routes.route1.defaults.action = "find"
routes.route1.map.1 = "url_path"
routes.route1.map.2 = "url"
routes.route1.map.3 = "options"
routes.route1.map.4 = "page"
routes.route1.reverse = "%s%s,page_%d.html"
the url will be http://www.site.com/cat1/cat2/cat3/cat4/cat5/title-id1_id2,page_1.html
the number of categories is unspecified
current regex works fine, and gets all the categories at once, but the reverse formats all forward slashes to html format: %2F
does anyone know how I can keep the forward slashes? I need the reverse for pagination and all the html entities look just plain ugly.
thx :)
If you're using the URL helper, set the fourth parameter to false to disable the encoding (which is on by default). So something like:
<?=$this->url(array(
'url_path' => 'whatever',
'url' => 'something'
'options' => 'foo',
'page' => 'bar'
), 'route1', false, false)?>