How to determine whether the URL is containing argument(s)? - php

I have two kind of URLs:
First:
localhost/search?q=arg1&s=arg2
Second:
localhost/search/arg1/arg2
Note: Sometimes arguments are containing ?. Like this:
localhost/search/ar?g1/arg2 // this is belong to second kind
Well, How can I detect ths URL is which kind?
Here is my code:
$FirstKind = strpos($_SERVER['REQUEST_URI'], '?') ? true : false;
But the above code returns true for the URL if one of arguments be containing ? (as you see in the Note above).

You can use parse_url for this:
$parsed = parse_url ( 'YourURL' );
The GET ‘arguments’ are now in $parsed['query']
See more about parse_url()

Here's a possible implementation:
<?php
function getArg($arg, $url) {
$result = '';
$urlData = explode('&', parse_url($url)['query']);
foreach ($urlData as $urlPair) {
if (strpos($urlPair, '=') !== false) {
list($k, $v) = explode('=', $urlPair);
if (trim($k) == $arg) {
$result = trim($v);
break;
}
}
}
if (empty($result)) {
$urlParts = explode('/', $url);
for ($i = 0; $i < sizeof($urlParts); $i++) {
if (trim($urlParts[$i]) == trim($arg)) {
if (isset($urlParts[$i+1])) {
$result = $urlParts[$i+1];
break;
}
}
}
}
return $result;
}
Usage:
$url1 = 'localhost/search?q=arg1&s=arg2';
$url2 = 'localhost/search/ar?g1/arg2';
echo "<pre>";
var_dump(getArg('q', $url1));
var_dump(getArg('ar?g1', $url2));
echo "<pre>";
Outputs:
string(4) "arg1"
string(4) "arg2"

Related

Extract some string from the URL

I have a URL, e.g:
https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/.
From the above URL, I want to extract my-product-name-display if this URL contains it, if not, I want the string after /ex/{BYADE3323} as below URL does not contain my-product-name-display.
https://www.example.com/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/
I have tried below code:
`$url_param = "https://www.example.com/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/";`
or
`$url_param = "https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/";`
$e_product_title = explode('.com/', $url_param);
if(isset($e_product_title)){
$product_title = $e_product_title[1];
//now explode the ex
$get_asin = explode('/ex/',$product_title);
$final_product_title = str_replace('-',' ',$get_asin[0]);
$get_asin_final = explode('/', $get_asin[1]);
$asin_v2 = $get_asin_final[0];
}
else{
$get_asin = explode('/ex/',$url_param);
print_r($get_asin);
}
echo $final_product_title." ".$asin_v2;
Thanks in advance.
You can explode() the string,
Check if my-product-name-display and BYADE3323 is in the array.
If present, find out BYADE3323's index.
Add 1 to it and check if the next element is present.
<?php
$str = 'https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/';
$str = str_replace('://', '__', $str);
$arr = explode('/', $str);
$return = '';
if (in_array('my-product-name-display', $arr) && in_array('BYADE3323', $arr)) {
$idx = array_search('BYADE3323', $arr);
$idx2 = $idx + 1;
if (! empty($idx) && ! empty($arr[$idx2])) {
$idx += 1;
$return = $arr[$idx2];
}
}
echo $return;
EDIT:
As per comments from OP, following is the program for array of urls and array of search strings.
<?php
$searchStrings = [];
$searchStrings[] = ['my-product-name-display', 'BYADE3323'];
$searchStrings[] = ['your-product-name-display', 'BYADE4434'];
$urls = [];
$urls[] = 'https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/';
$urls[] = 'https://www.example.com/your-product-name-display/ex/BYADE4434/wgsi?nfh3420000ooo2323nfnf/';
$urls[] = 'https://www.example.com/their-product-name-display/ex/TEST343/wgsi?nfh3420000ooo2323nfnf/';
$urls[] = 'https://www.example.com/my-product-name-display/ex/ANASDF33/wgsi?nfh3420000ooo2323nfnf/';
$urls[] = 'https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/';
$return = [];
if (! empty($urls)) {
foreach ($urls as $url) {
if (! empty($searchStrings)) {
foreach ($searchStrings as $searchString) {
$str = implode('/ex/', $searchString);
if (strpos($url, $str) !== false) {
$arr = explode('/', $url);
$idx = array_search('BYADE3323', $arr);
$idx2 = $idx + 1;
if (! empty($idx) && ! empty($arr[$idx2])) {
$idx += 1;
$return[] = $arr[$idx2];
}
}
}
}
}
}
echo '<pre>';
print_r($return);
echo '</pre>';
Output:
Array
(
[0] => wgsi?nfh3420000ooo2323nfnf
[1] => wgsi?nfh3420000ooo2323nfnf
)
Try this to fetch from URL values.
pass url to the function. You can extract it.
Here is the URL :
https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/
So when u want only BYADE3323 this value.
When you print $parts array, you can find every values after your Host name.
Where your host name is https://www.example.com.
function GetStringAfterSecondSlashInURL($the_url)
{
$parts = explode("/",$the_url,3);
if(isset($parts[2]))
return $parts[2];
}
Use parse_url() function this will help you definitely.
You can refer it from official PHP site: parse-url.
You can use strpos to identify weather 'my-product-name-display' is exist s in url or not and execute code accordingly.
strpos($url_param, 'my-product-name-display') !== false
Modified code:
function get_product_title($url_param) {
$get_asin = explode('/ex/', $url_param);
$get_asin_final = explode('/', $get_asin[1]);
$asin_v2 = $get_asin_final[0];
return $asin_v2;
}
$url_param = "https://www.example.com/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/";
$url_param = "https://www.example.com/my-product-name-display/ex/BYADE3323/wgsi?nfh3420000ooo2323nfnf/";
$product_name = '';
if (strpos($url_param, 'my-product-name-display') !== false) {
$e_product_title = explode('.com/', $url_param);
if (isset($e_product_title)) {
$product_title = $e_product_title[1];
//now explode the ex
$product_name = get_product_title($product_title);
}
echo "my product name display" . $product_name;
}
else {
$product_name = get_product_title($url_param);
echo $product_name;
}

match items inside curly braces and map them to a given string

I am trying to make a routing system in php which uses regex. What I need is to match the route specified in route collection and check if the url matches with it, and if it does, return the parameters in the route by matching with the url.
For example
$route="user/{username}/id/{id}/age/{age}/profile";
$url="user/joe/id/99/age/33/profile";
First thing is to check if the $url matches the $route pattern, return false if it doesn't.
Then I need to return an array containing
[
'username'=>'joe',
'id'=>'99',
'age'=>'33',
]
I'm not good at this at all, I had a clumsy go at it.
Here's my current code
<?php
$r="user/username/{name}/id/{id}/age/{age}/profile";
$u="user/username/joe/id/99/age/33/profile";
route::match($r, $u);
class route{
public static function match($route, $url)
{
if(strpos($route, '{')===FALSE)
{
if(strcmp($route, $url)==0)
{
return TRUE;
}
return FALSE;
}
$vars=[];
$umatches=[];
preg_match_all('/\{(.*?)\}/', $route, $matches);
preg_match('/(.*?)\{/', $route, $amatches);
preg_match_all('/\}(.*?)\{/', $route, $bmatches);
$a=preg_split(end($bmatches[1]), $route);
$b=preg_split('/\}(.*?)/', $a[1]);
array_push($umatches, $amatches[1]);
foreach ($bmatches[1] as $key => $value)
{
array_push($umatches, $value);
}
array_push($umatches, $b[1]);
$pattern="/".str_replace('/', '\/', $amatches[1])."/";
$split=preg_split($pattern, $url);
$i=0;
foreach ($umatches as $key => $value) {
$value=str_replace('/', '\/', $value);
$value='/'.$value.'/';
$r=preg_split($value, $url);
$url=$r[1];
if($i>0)array_push($vars, $r[0]);
$i++;
}
print_r($vars);
if(sizeof($matches[1])!=sizeof($vars)) return FALSE;
$params=[];
for ($i=0; $i < sizeof($matches[1]); $i++) {
$params[$matches[1][$i]]=$vars[$i];
}
print_r($params);
return $params;
}
}
Here I ran the code http://ideone.com/blljFM
Not a php guru here. So below is just a quick 2-step solution using
pseudo-code.
global $TemplateArray;
global $UrlArray;
function GetRoutParams ( $strUrlTemplate, $strUrl )
{
$TemplateArray = [];
$UrlArray = [];
// Step 1. Create the regex from the template
$strUrlRegex = preg_replace_callback('~\{([^{}]+)\}~',
function( $matches ){
$repl = '([^/]+)';
// push $matches[1] into a $TemplateArray
return $repl;
},
$strUrlTemplate);
// Step 2. Create the hash from the regex
if ( preg_match($strUrlRegex, $strUrl, $matches) )
{
// Peel off the matches
// (Or, make a hash)
for ( int $i = 0; $i < $matches.count; $i++ )
{
push $UrlArray, $TemplateArray[$i];
push $UrlArray, $matches[$i];
}
// (Or, make a hash)
// $UrlHash[ $TemplateArray[$i] ] = $matches[$i];
}
else
{
return false;
}
return true;
}
Check out this regex with global match against your string:
(user|id|age)\/([^\/]+) it matches the keyword, a '/' and the next path element (which must not contain ANY '/'). Also be aware that for example a "superuser/1/" string would also be matched.
Each match should give you a key-value pair. Looping over the matches you can build your arrays/dicts as you intend.
<?php
$r="user/username/{name}/id/{id}/age/{age}/profile";
$u="user/username/joe/id/99/age/33/profile";
route::match($r, $u);
class route{
public static function match($route, $url)
{
preg_match_all('/(username|id|age)\/([^\/]+)/', $url, $matches);
$params=[];
for ($i=0; $i < sizeof($matches[1]); $i++) {
$params[$matches[1][$i]]=$matches[2][$i];
}
print_r($params);
return $params;
}
}
A little bit more elaborate:
<?php
$r=":user/username/[^/]+/id/[^/]+/age/[^/]+/profile:";
$u="user/username/joe/id/99/age/33/profile";
$k="username|id|age"; # valid keys
print_r(route::match($r, $u, $k));
class route{
public static function match($route, $url, $valid_url_keys)
{
$number_of_expected_key_value_pairs = 3;
$number_of_matches = preg_match_all(":($valid_url_keys)/([^/]+):", $url, $matches);
if($number_of_matches == $number_of_expected_key_value_pairs)
{
$params=[];
for ($i=0; $i < sizeof($matches[1]); $i++) {
$params[$matches[1][$i]]=$matches[2][$i];
}
return $params;
}
else {
return FALSE;
}
}
}
Changed regex delimiter to colon, since the slash is a url-pattern, we need less escaping.
Only returns matches if they match the route specification.
Update: I've implemented sln's solution with a few fixes. Here's it
class Route
{
private static $tmp = array();
public static function GetRoutParams($strUrlTemplate, $strUrl)
{
$strUrlRegex = preg_replace_callback('~\{([^{}]+)\}~',
function ($matches)
{
$repl = '([^)]+)';
self::$tmp[] = $matches[1];
return $repl;
}
, $strUrlTemplate);
$UrlArray = array();
$matches = array();
$strUrlRegex = str_replace('/', '\/', $strUrlRegex);
if (preg_match("/^" . $strUrlRegex . "$/", $strUrl, $matches))
{
for ($i = 0; $i < count(self::$tmp); $i++)
{
$UrlArray[self::$tmp[$i]] = $matches[$i + 1];
}
self::$tmp = array();
return $UrlArray;
}
return false;
}
}
I've completed the code; though it feels inefficient. I'd be grateful if someone helps making the code more efficient.
<?php
$route = "user/{name}/id/{id}/age/{age}/ash";
$url = "user/joe/id/99/age/33/ash";
route::match($route, $url);
class route
{
public static function match($route, $url)
{
if (strpos($route, '{') === FALSE)
{
if (strcmp($route, $url) == 0)
{
return TRUE;
}
return FALSE;
}
$vars = [];
$umatches = [];
//get all parameters in curly braces in $route
preg_match_all('/\{(.*?)\}/', $route, $matches);
//get the string before first occurrence of { in $route
preg_match('/(.*?)\{/', $route, $amatches);
//get all strings between } and { in $route
preg_match_all('/\}(.*?)\{/', $route, $bmatches);
//get the string after last }
if (!empty($bmatches[1])){
$a = preg_split(end($bmatches[1]) , $route);
$b = preg_split('/\}(.*?)/', end($a));
}
else{
$a = preg_split('/' . str_replace('/', '\/', end($amatches)) . '/', $route);
$b = preg_split('/\}(.*?)/', end($a));
}
//push the matches into array $umatches
if (!empty($amatches[1])) array_push($umatches, $amatches[1]);
if (!empty($bmatches[1]))
{
foreach($bmatches[1] as $key => $value)
{
array_push($umatches, $value);
}
}
if (!empty($b[1])) array_push($umatches, $b[1]);
//check if the $url matches with $route template
$prev = - 1;
foreach($umatches as $key => $value)
{
$pos = strpos($url, $value);
if ($pos !== FALSE)
{
if ($prev > $pos) return FALSE;
$prev = $pos;
}
else return FALSE;
}
//push the parameter values in $url into $vars array
$i = 0;
foreach($umatches as $key => $value)
{
$value = str_replace('/', '\/', $value);
$value = '/' . $value . '/';
$r = preg_split($value, $url);
$url = $r[1];
if (!empty($r[0])) array_push($vars, $r[0]);
$i++;
}
if (!empty($r[1])) array_push($vars, $r[1]);
//map the values in $url with the parameters in $route template
$params = [];
for ($i = 0; $i < sizeof($matches[1]); $i++)
{
$params[$matches[1][$i]] = $vars[$i];
}
return $params;
}
}
The code now properly returns the parameters. The problems I had was the code was being preg_split by empty strings in some places. Also I didn't push the value if the parameter occurred in the end of string; for example - user/{username}, here {username} wasn't being pushed properly. Also the comparing the template with given url using sizeof() doesn't always give correct result.

how to find a value contained inside a value inside an array?

If I have the array:
$os = array("Mac", "NT", "Irix", "Linux");
I know that in_array() is what to use if I want to find "Mac" inside $os.
But what I have the array:
$os = array( [1] => "Mac/OSX", [2] => "PC/Windows" );
and I want to see if "Mac" is contained in $os?
Try:
$example = array("Mac/OSX","PC/Windows" );
$searchword = 'Mac';
$matches = array_filter($example, function($var) use ($searchword) { return preg_match("/\b$searchword\b/i", $var); });
You could also use array_map to do this. Take a look at the following code:
$array = array(
'Mac/OSX',
'PC/Windows',
);
$result = in_array(true, array_map(function ($word, $match, $char = "/") {
$words = explode('/', $word);
return in_array($match, $words) ? true : false;
}, $array, array('Mac')));
var_dump($result); // bool(true)
You can try this-
$os = array( "Mac/OSX", "PC/Windows" );
function findInArray($os){
foreach($os as $val){
if(strpos($val, $word_to_search) !== false){
return true;
}
}
return false;
}
Here is another solution:
array_map(function($v){
if (strpos($v, 'Mac') !== false) {
echo 'found';
exit;
}
},$os);
echo "Not found";
DEMO
You can simply use preg_grep function of PHP like as
$os = array( '1' => "Mac/OSX", '2' => "PC/Windows" );
print_R(preg_grep("/Mac/",$os));
Output:
Array ( [1] => Mac/OSX )
By using foreach and strpos
$os =array("Mac/OSX","PC/Windows" );
$string = "Mac";
foreach ($os as $data) {
//echo $data;
if (strpos($data,$string ) !== FALSE) {
echo "Match found";
}else{
echo "not found";
}
}
DEMO
function FindString($string, $os)
{
// put the string in between //
$preg = "/$string/";
// Match found
$found = false;
// loop each value
for($j = 0; $j < count($os); $j++)
{
// check with pattern
if(preg_match($preg,$os[$j]))
{
// set var to ture
$found = true;
// Break
break;
}
}
if($found == false)
{
die("Unable to found the string $string.");
}
echo "String $string found in array index $j and value is $os[$j]";
}
$where =array("Mac/OSX","PC/Windows" );
$what = "Mac";
FindString($what, $where);

PHP in_array and String contains

I have any array of data "example.com/imports", "example.com/var", "example.com/js" i want to remove all urls which contain this for sitemap.
Some of my url data is like the following
"example.com/imports/product.html",
"example.com/imports/product1.html",
"example.com/var/cache/5t46fdgdyg7644gfgfdgr",
"example.com/js/scripts.js"
I have this code
for ($i = 0; $i <= count($urls); $i++) {
$url = $urls[$i];
if (in_array($url, $remove_urls)) {
// found remove url
}else{
echo $url;
}
}
However this only removes if the url is exact match such as "example.com/imports" is there a way to check against start
Instead of in_array($url, $remove_urls) try to use strpos:
foreach ($urls as $url) {
$remove = false;
// loop $remove_urls and check if $url starts with any of them
foreach ($remove_urls as $remove_url) {
if (strpos($url, $remove_url) === 0) {
$remove = true;
break;
}
}
if ($remove) {
// remove url
} else {
echo $url;
}
}
You can use preg_grep function like that:
$urls = ['imports', 'var', 'js'];
$url_pattern = '/example.com\/(' . implode('|', $urls) . ')\/.*/';
$removed = preg_grep($url_pattern, $remove_urls);
here an example.

Build Array Tree from URLs

I need to build an tree (with arrays) from given urls.
I have the following list of urls:
http://domain.com/a/a.jsp
http://domain.com/a/b/a.jsp
http://domain.com/a/b/b.jsp
http://domain.com/a/b/c.jsp
http://domain.com/a/c/1.jsp
http://domain.com/a/d/2.jsp
http://domain.com/a/d/a/2.jsp
now i need an array like this:
domain.com
a
a.jsp
b
a.jsp
b.jsp
c.jsp
c
1.jsp
d
2.jsp
a
2.jsp
How can i do this with php?
i thought mark's solution was a bit complicated so here's my take on it:
(note: when you get to the filename part of the URI, I set it as both the key and the value, wasn't sure what was expected there, the nested sample didn't give much insight.)
<?php
$urls = array(
'http://domain.com/a/a.jsp',
'http://domain.com/a/b/a.jsp',
'http://domain.com/a/b/b.jsp',
'http://domain.com/a/b/c.jsp',
'http://domain.com/a/c/1.jsp',
'http://domain.com/a/d/2.jsp',
'http://domain.com/a/d/a/2.jsp'
);
$array = array();
foreach ($urls as $url)
{
$url = str_replace('http://', '', $url);
$parts = explode('/', $url);
krsort($parts);
$line_array = null;
$part_count = count($parts);
foreach ($parts as $key => $value)
{
if ($line_array == null)
{
$line_array = array($value => $value);
}
else
{
$temp_array = $line_array;
$line_array = array($value => $temp_array);
}
}
$array = array_merge_recursive($array, $line_array);
}
print_r($array);
?>
$urlArray = array( 'http://domain.com/a/a.jsp',
'http://domain.com/a/b/a.jsp',
'http://domain.com/a/b/b.jsp',
'http://domain.com/a/b/c.jsp',
'http://domain.com/a/c/1.jsp',
'http://domain.com/a/d/2.jsp',
'http://domain.com/a/d/a/2.jsp'
);
function testMapping($tree,$level,$value) {
foreach($tree['value'] as $k => $val) {
if (($val == $value) && ($tree['level'][$k] == $level)) {
return true;
}
}
return false;
}
$tree = array();
$i = 0;
foreach($urlArray as $url) {
$parsed = parse_url($url);
if ((!isset($tree['value'])) || (!in_array($parsed['host'],$tree['value']))) {
$tree['value'][$i] = $parsed['host'];
$tree['level'][$i++] = 0;
}
$path = explode('/',$parsed['path']);
array_shift($path);
$level = 1;
foreach($path as $k => $node) {
if (!testMapping($tree,$k+1,$node)) {
$tree['value'][$i] = $node;
$tree['level'][$i++] = $level;
}
$level++;
}
}
echo '<pre>';
for ($i = 0; $i < count($tree['value']); $i++) {
echo str_repeat(' ',$tree['level'][$i]*2);
echo $tree['value'][$i];
echo '<br />';
}
echo '</pre>';

Categories