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.
Related
I have a list of domains (array)
sub1.dom1.tld1
sub2.dom2.tld2
sub1.sub2.dom1.tld1
sub3.dom1.tld3
I want to achieve the following:
dom1.tld1
-> sub1.dom1.tld1
-> sub2.dom1.tld1
--> sub1.sub2.dom1.tld1
dom2.tld2
-> sub2.dom2.tld2
dom1.tld3
-> sub3.dom1.tld3
I have tried to adapt this, but it doesn't really fit:
How to alphabetically sort a php array after a certain character in a string
I would appreciate any kind of help.
I've had to attack a similar headache before. In the short term I flip the order of the domain components and use a hidden sorting column in a table/view:
$sortstring = implode('.',array_reverse(explode('.', $domain)));
In the long term I saved the reverse format of the domain records before saving changes to the DB into a computed field/column so that it didn't have to be re-computed every time the domain list is viewed.
If you don't want that sub-domain, just remove the last element of the array after the flip....
You can proceed like this:
$array=array(
'sub1.dom1.tld1',
'sub2.dom2.tld2',
'sub1.sub2.dom1.tld1',
'sub2.sub2.dom1.tld1',
'sub3.sub2.dom1.tld1',
'sub3.dom1.tld3');
function cmp($a,$b){
$a=array_reverse(explode('.',$a));
$b=array_reverse(explode('.',$b));
$ca=count($a);
$cb=count($b);
$string='';;
for($i=0,$c=min($ca,$cb);$i<$c;$i++){
$result=strnatcmp($a[$i],$b[$i]);
if($result!==0) return $result;
}
return $result;
}
usort($array,'cmp');
print_r($array);
and the output is:
Array
(
[0] => sub1.dom1.tld1
[1] => sub1.sub2.dom1.tld1
[2] => sub2.sub2.dom1.tld1
[3] => sub3.sub2.dom1.tld1
[4] => sub2.dom2.tld2
[5] => sub3.dom1.tld3
)
Here is an approach similar to #Elementary answer combine to #CBO one:
$domains = [
'sub.bbb.com',
'www.aaa.com',
'*.zzz.com',
'aaa.com',
'*.sub.bbb.com',
'zzz.com',
'beta.bbb.com',
'bbb.com',
'aaa.fr',
];
// #see https://stackoverflow.com/a/61461912/1731473
$computeDomainToSort = static function (string $domain): string {
return \implode(
'.',
array_reverse(
explode('.', $domain,
// Keep the base domain.tld collapsed for comparison.
substr_count($domain, '.')
)
)
);
};
\usort($this->domains, static function (string $domain1, string $domain2) use ($computeDomainToSort): int {
$domain1 = $computeDomainToSort($domain1);
$domain2 = $computeDomainToSort($domain2);
return strnatcmp($domain1, $domain2);
});
That way, given domains will be sorted like this:
aaa.com
www.aaa.com
aaa.fr
bbb.com
beta.bbb.com
sub.bbb.com
*.sub.bbb.com
zzz.com
*.zzz.com
The main difference is on the $computeDomainToSort lambda function, where I keep the base domain.tld onto one piece to have a more natural sorting.
I have this bit of PHP code which strips - the dash from the incoming string. The array key may or may not have a - between each word. So if the string has spaces or dashes, the string is still matched to the key.
Now I need to expand this a little to have a partial match locate the key in the array.
Here's what I have so far.
My array
$pages = array(
'Administrator' => array(
'network-administrator' => array('title' => 'Network '.$li_1, 'description' => 'Network '.$li_1.' '.$temp_content, 'post' => '<p>Network '.$li_1.' '.$temp_content.'.</p>'),
'database administrator' => array('title' => 'Database '.$li_1, 'description' => 'Database '.$li_1.' '.$temp_content, 'post' => '<p>Database '.$li_1.' '.$temp_content.'.</p>'),
),
'Analyst' => array(
'business systems analyst' => array('title' => 'Business Systems '.$li_2, 'description' => 'Business Systems '.$li_2.' '.$temp_content, 'post' => '<p>Business Systems '.$li_2.' '.$temp_content.'.</p>'),
'data-analyst' => array('title' => 'Data '.$li_2, 'description' => 'Data '.$li_2.' '.$temp_content, 'post' => '<p>Data '.$li_2.' '.$temp_content.'.</p>'),
),
);
PHP foreach loop
$t_keys = array();
foreach ($pages as $k => $arr2) {
foreach (array_keys($arr2) as $a) {
$new_key = str_replace("-", " ", $a);
$t_keys[$new_key] = array( $k, $a );
}
}
$str = str_replace(array('-', ' and '), ' ', strtolower($position));
if (array_key_exists($str, $t_keys)) {
$target = $pages[ $t_keys[$str][0] ][ $t_keys[$str][1] ];
}
$t_keys[$str][0] accesses the key Administrator and $t_keys[$str][1] accesses sub-key network-administrator.
What I need to do is match incoming strings from the query string in the URL to find matches in the sub-keys of the array.
Example partial match strings that are coming in are oracle database administrator. That key is not in my array, but oracle administrator is, as well as database administrator.
So how could I match strings coming in to the sub-keys in the array if similar words exist?
Here is a small list of incoming partial match strings coming in my error log.
it
apple
css
.net developer
desktop
.net
python
apple
data center
phone technician
sql database developer
jquery
delphi
css
python
pc
software
xml
webmaster
research development
python programming
computer technician or pc technician
.net
c
in some cases, the above partial matches don't exist anywhere in the array. I am just doing a redirect on those. But others such as data center and python programming just as an example are in the array.
Example for the string data center, the nearest match in the array would be data center technician and the nearest match for string python programming would be python developer.
All help appreciated!
EDIT
Just to be clear, here is some more info about partial matching that will be an issue.
yes I know that some matches will be more trickier than others. In my array, there is no key called programming but there is a key called developer so string python programming could be placed to sub key python developer as that is a sub key of the developer key.
Others such as the string data center it will be trickier because there are several sub keys of main keys that have the word data center.
Let's take for example the string computer technician or pc technician. That is no longer a sub-key in my array. but there are sub keys called computer technician as well as pc technician. Which one to partial match if both sub keys exist in the string?
If I can get something basic for now that will atleast take care of some of these partial matches, then I'm on the right track.
EDIT 2
Here's another example of a string business analyst. There is a sub key in my array called business systems analyst. The word business and analyst are both words in the sub key. So I need to create something that I can continue to add onto every time a new string comes in that isn't matching properly in the array.
EDIT 3
After thinking for a few minutes, I think the best way will be to manually add each partial string that comes in to an array and reference those to the sub key of my choosing.
oes that make sense?
So I need to create a php snippet that I keep adding to the array container of partial match strings that point to the key in the array. How can I do that?
I wrote a little single word match based on your requirements. So network will match against network whatever stuff goes here because it contains network, etc... I'm not sure if it's what you want, but maybe it'll help you.
class PageWalker{
public $pages = null;
public function __construct($pages){
return $this->pages = $pages;
}
public function clean_str($str){
return strtolower(preg_replace('/[-_\~\!##\$\%\^\&\*\(\)]/', ' ', $str));
}
public function get_results($input=false){
$results = array();
foreach($this->pages as $page => $arr):
foreach($arr as $i => $v):
if(in_array($this->clean_str($input), explode(' ', $this->clean_str($i)))):
$results[$i] = $v;
endif;
endforeach;
endforeach;
return $results;
}
}
$walk = new PageWalker($pages);
print_r($walk->get_results('network'));
Here's an eval.in example
I'm working with CakePHP v2.3.x and on an edit page I need to dynamically update the page with search results...
I'm making an AJAX call from one of my Views/Tests/admin_edit.php view page to a specific action in my QuestionsController.php.
Here's the action (so far) that handles the request:
public function admin_search() {
if ($this->request->is('post')) {
$searchdata = $this->request->data;
$r = $this->Question->find('all', array('conditions' => array('Question.id' => $searchdata['id'])));
echo json_encode($r);
exit;
}
}
It currently only returns questions whose IDs match the one entered by the user, but the finished version will search several different fields. I know how to do this by adding additional key/value pairs to the conditions array. However, I don't know how to make those fields optional. What if the user enters the question name, but NOT the id, or visa versa? Is there a configuration so that CakePHP will ignore any empty field conditions?
Similarly, is there a way to set the operator so that, for example, I could match substrings or integer ranges? Update: I found this in the docs.
I would just remove any empty entries yourself first.
So let's say you have a $searchdata array with three optional fields, one of which is blank. First build your conditions array:
$searchdata = array("id" => 1, "name" => "", "type" => "foo");
$conditions = array('Question.id' => $searchdata['id'], 'Question.name' => $searchdata['name'], "Question.type" => $searchdata['type']);
(Or if you want to get fancy)
foreach($searchdata AS $key => $value) $conditions['Question.' . $key] = $value;
Now clean up $conditions, get rid of empty values:
$conditions = array_filter($conditions);
Tada:
$r = $this->Question->find('all', array('conditions' => $conditions));
See http://3v4l.org/JN6PA
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.
Im trying to implement pagination using multiple searching criteria.
Supposed I Have student table. I also use pagination when the list of student displayed.
The pagination link is. site_url . '/student/page/'; so I use $config['uri_segment'] = 1;
so the pagination link will be
1
2
and son.
After that I wanna search student data using 3 searching criteria implemented using textfield.
id name address.
user can search by id or name or address or combination of the three criteria.
the url become
http://mysite/index.php/student/page/0
href=http://mysite/index.php/student/page/1
and son.
but I use get method for searching. and while trying to search using the search criteria field the url become
href="http://mysite/index.php/student/page/1?id=1&name=a&address=b
the problem occurred when I try create pagination based on criteria. because the pagination link have contain query string
i don't know how to create become
href="http://mysite/index.php/student/page/0?id=1&name=a&address=b
href="http://mysite/index.php/student/page/1?id=1&name=a&address=b
or do you have a best practice to solve this problem ?
To solve that problem, I try using $this->uri->uri_to_assoc(). First I create array asocc for pagination link.
$array = array('id' => '001', 'name' => 'a', 'address' => 'canada');
the url become
id/001/name/a/address/canada. I use $this->uri->uri_to_assoc() function to get key and value of the segment.
array (
id => 001,
name=>a,
address=>canada
)
but while there some searching criteria that not included while searching. let say, the user only search by name and address. the array become
$array = array('id' => '', 'name' => 'a', 'address' => 'canada'); and the url id/name/a/address/canada
the assoc array become
array (
id => name,
a=>address,
canada=>
)
the assoc array is not disorganized again. so I can't get the right value of the assoc array.
I think i will set the identifier to the searching criteria if not included. supposed i put #.
if isset($_GET['id']) then
$id = '#'
else
$id = $_GET['id']
$array = array('id' => $id, 'name' => 'a', 'address' => 'canada');
How about that ... ? or if there are another best practice ?
Thanks
I've always found it somewhat a pain to deal with uri's in ci.
Is there a way you can set a default of some kind for your values if the user doesn't include that as part of their search? or even not include the key? so it would return something like
id/10/name/false/address/canada
or
id/10/address/canada
then you can
$uri = $this->uri->uri_to_assoc();
$id = array_key_exists("id", $uri) ? $uri['id'] : false;
$id = $id == 'false' ? false : $id;
$query .= $id ? "AND id = $id" : "";
etc...
When I use uri_to_assoc, I always have a default array, so in my application, I can always get the required parameter, even if it missing from the uri
$param_default = array('cat','page');
$param_array = $this->uri->ruri_to_assoc(3, $param_default);
Now I can safely access $param_array['cat'] and $param_array['page'] even when uri doesn't contain that parameter.
I always user ruri_to_assoc and ruri_segment, so the extra parameter always start in 3rd uri segment.