If I have the following url:
http://URL/products/38/293/bannana_cake/
or
htp://URL/products/38/293/fruit_cake/
How can I isolate just bannana_cake and fruit_cake from the examples above?
<?php
$url = 'http://username:password#hostname/path?arg=value#anchor';
print_r(parse_url($url));
echo parse_url($url, PHP_URL_PATH);
?>
And then use explode() on the 'path' element.
For example:
<?php
$url = 'http://URL/products/38/293/bannana%5Fcake/';
$a = parse_url($url);
$p = explode('/', $a['path']);
echo $p[4];
?>
Probably the easiest way, which only applies to your special case and is not something for production, is to use the basename-function:
<?php
echo basename("http://url/products/38/293/banana_cake/"); // Produces "banana_cake"
?>
This only works because "banana_cake" is the last part of the url and there is nothing behind the last slash.
It is definately not a desirable solution and Luca Matteis' answer will get my vote, because the slightest change in the query string order will break things.
it will be a $_GET variable as what you're looking at is just a mod_rewrite version of a query string
try this to see what the variable name is:
<pre>
<?php print_r($_GET);?>
</pre>
You can see the URL that has been requested by looking at the $_SERVER[] array (Google that to find the exact entry). They you can split the string into an array on '/', then the [3] index will be the part of the URL you're interested in.
Split the url on the slashes and retrieve the last part:
$parts = explode('/', $url);
echo $parts[sizeof($parts) - 2];
Only problem, you need to have the trailing slash in the url. You could make a check for that like this:
$parts = explode('/', $url);
echo ($parts[sizeof($parts) - 1])
? $parts[sizeof($parts) - 1]
: $parts[sizeof($parts) - 2];
My answer will be slightly longer. It looks like you want to do something similar to using URI Templates, so here's a snippet of two functions from a class (called xs_Breakdown) I have that does these things. It could easily be extended to include wildcards and conditional behaviour (on the todo list for a time in the future I'm suffering from too little to do). First, and example of setting up and use ;
$br = new xs_Breakdown ( '{first}/{second}/{third}/{fourth}/{fifth}/{andsoon}' ) ;
// Pick out the template variable called 'third'
$third = $br->third ;
The code (just the basics which should be enough to kick up some of your own dust; all the code would be too long to post here. Pop me a message if you'd like the whole shebang with three nested property / Java Bean-like classes) ;
// Static variable to hold our tokens
$_tokens = null ;
// Input path (set in constructor)
$_path = null ;
// Results here
$values = array() ;
function parse ( $schema = '' ) {
// Sanitize input data : Regular Expression
$regexp = '/[^a-z0-9 +\-\/!$*_=|.:]/i' ;
// Break our path into little bits
$break = explode ( '/', $this->_path ) ;
// Find the tokens used from our schema template
$this->_tokens = $this->getSubStrs ( "{","}", $schema ) ;
// Loop through the path elements
foreach ( $break as $key => $value ) {
// Sanitize the value of the element
$value = urldecode ( trim ( preg_replace ( $regexp, '', $value ) ) ) ;
// Element not blank? (Meaning, real text)
if ( $value != '' )
// Index it!
#$this->values[$this->_tokens[$key]] = $value ;
}
}
function getSubStrs ( $from, $to, $str, &$result = array () ) {
if ( strpos ( $str, $from ) !== false ) {
$start = strpos ( $str, $from ) + 1 ;
$end = strpos ( $str, $to ) - 1 ;
$item = substr ( $str, $start, $end - $start + 1 ) ;
$rest = substr ( $str, $end + 2 ) ;
$result[] = $item ;
$this->getSubStrs ( $from, $to, $rest, $result ) ;
}
return $result ;
}
Related
I have a pretty large array that I would need to parse, but the request changes depending on enabled/disabled parameters.
For example:
$array['a'][1]['b'][1]['c'][1] = 'asd';
$str = $array['a'][1];
dd($str);
This would give me:
Array
(
[b] => Array
(
[1] => Array
(
[c] => Array
(
[1] => asd
)
)
)
)
Which, of course, is correct. But now, if I know, that I need also the next parameter, I would need to add that like $str = $array['a'][1]['b'];.
But since there are way too many combinations, I wondered, if I can construct the call manually, something like this":
$str = $array['a'][1];
if ($b) {
$str .= ['b'][1];
}
if ($c) {
$str .= ['c'][1];
}
dd($str);
Any hints will be appreciated.
PS: I know I can do this with eval, but was really looking for a better solution:
eval("\$str = \$array$str;");
dd($str);
It can be done with Reference
$string = "['a'][1]['b'][1]";
// Maybe, not optimal, but it's not the point of the code
preg_match_all('/\[\'?([^\]\']+)\'?\]/', $string, $steps);
// "Root" of the array
$p = &$array;
foreach($steps[1] as $s) {
// Next step with current key
if (isset($p[$s]) && is_array($p)) $p = &$p[$s];
else throw new Exception("No such item");
}
// Target value
$str = $p;
demo
This may be able to be accomplished with a regular expression but I have no idea. What I am trying to accomplish is being able to parse a string with a given delimiter but when it sees a set of brackets it parses differently. As I am a visual learning let me show you an example of what I am attempting to achieve. (PS this is getting parsed from a url)
Given the string input:
String1,String2(data1,data2,data3),String3,String4
How can I "transform" this string into this array:
{
"String1": "String1",
"String2": [
"data1",
"data2",
"data3"
],
"String3": "String3",
"String4": "String4
}
Formatting doesn't have to be this strict as I'm just attempting to make a simple API for my project.
Obviously things like
array explode ( string $delimiter , string $string [, int $limit = PHP_INT_MAX ] )
Wouldn't work because there are commas inside the brackets as well. I've attempted manual parsing looking at each character at a time but I fear for the performance and it doesn't actually work anyway. I've pasted the gist of my attempt.
https://gist.github.com/Fudge0952/24cb4e6a4ec288a4c492
While you could try to split your initial string on commas and ignore anything in parentheses for the first split, this necessarily makes assumptions about what those string values can actually be (possibly requiring escaping/unescaping values depending on what those strings have to contain).
If you have control over the data format, though, it would be far better to just start with JSON. It's well-defined and well-supported.
You can either build an ad-hoc parser like (mostly untested):
<?php
$p = '!
[^,\(\)]+ # token: String
|, # token: comma
|\( # token: open
|\) # token: close
!x';
$input = 'String1,String2(data1,data2,data3,data4(a,b,c)),String3,String4';
preg_match_all($p, $input, $m);
// using a norewinditerator, so we can use nested foreach-loops on the same iterator
$it = new NoRewindIterator(
new ArrayIterator($m[0])
);
var_export( foo( $it ) );
function foo($tokens, $level=0) {
$result = [];
$current = null;
foreach( $tokens as $t ) {
switch($t) {
case ')':
break; // foreach loop
case '(':
if ( is_null($current) ) {
throw new Exception('moo');
}
$tokens->next();
$result[$current] = foo($tokens, $level+1);
$current = null;
break;
case ',':
if ( !is_null($current) ) {
$result[] = $current;
$current = null;
}
break;
default:
$current = $t;
break;
}
}
if ( !is_null($current) ) {
$result[] = $current;
}
return $result;
}
prints
array (
0 => 'String1',
'String2' =>
array (
0 => 'data1',
1 => 'data2',
2 => 'data3',
'data4' =>
array (
0 => 'a',
1 => 'b',
2 => 'c',
),
),
1 => 'String3',
2 => 'String4',
)
(but will most certainly fail horribly for not-well-formed strings)
or take a look at lexer/parser generator like e.g. PHP_LexerGenerator and PHP_ParserGenerator.
This is a solution with preg_match_all():
$string = 'String1,String2(data1,data2,data3),String3,String4,String5(data4,data5,data6)';
$pattern = '/([^,(]+)(\(([^)]+)\))?/';
preg_match_all( $pattern, $string, $matches );
$result = array();
foreach( $matches[1] as $key => $val )
{
if( $matches[3][$key] )
{ $add = explode( ',', $matches[3][$key] ); }
else
{ $add = $val; }
$result[$val] = $add;
}
$json = json_encode( $result );
3v4l.org demo
Pattern explanation:
([^,(]+) group 1: any chars except ‘,’ and ‘(’
(\(([^)]+)\))? group 2: zero or one occurrence of brackets wrapping:
└──┬──┘
┌──┴──┐
([^)]+) group 3: any chars except ‘,’
I am currently working on clean URL and stuck with this issue.
URL: http://localhost:8080/Pumps/Piston-pumps
$request_path = explode('?', $_SERVER['REQUEST_URI']);
$path_info = array_values($request_path);
echo str_replace('/',' ',$request_path[0]);
print_r($path_info);
above code gives below output :
Pumps Piston-pumps
Array ( [0] => /Pumps/Piston-pumps )
Is there a way I can convert the above array into:
Array ( [0] => Pumps [1] => piston-pumps )
I need this to add onto my URL
Thanks in advance
Here it is
<?php
$getUrl = "http://localhost:8080/Pumps/Piston-pumps"; // in your case it is $_SERVER['REQUEST_URI'];
$request_path = explode('?', str_ireplace(array("http://","https://"),"",$getUrl));
$expSlashes = explode("/", $request_path[0]);
$resultArr = array_slice($expSlashes, 1, count($expSlashes));
print_r($resultArr);
?>
use of explode and array_slice would result you with your required output.
explode is used to split a string with a needle sub-string
array_slice is used to create another array with limited and required number of array content
Try following code.
$new_array = ();
foreach($array as $k=>$v){
//This u split by upper case
$g = preg_split('/(?=[A-Z])/', $v);
$new_array[] = $g[0];
$new_array[] = strtolower($g[1]);
}
Use explode http://php.net/manual/en/function.explode.php
explode('/', '/Pumps/Piston-pumps');
I have a string like this,
sidePanel[]=1&sidePanel[]=2&sidePanel[]=4
And if I need to add another value to the string I do this:
$sidePanel = explode('&', $_SESSION['sidePanel']);
array_push($sidePanel, 'sidePanel[]=3');
$sidePanel = implode('&', $sidePanel);
Which returns this:
sidePanel[]=1&sidePanel[]=2&sidePanel[]=4&sidePanel[]3
Now how can I make it so that it will always insert after the array 'sidePanel[]=2' when I explode it at &?
I do not want it in numerical order although this example will return it in numerical order, as the string can change to be in any order.
I cannot use array_splice as I understand this uses the key of the array, and as the position of sidePanel[]=2 can change it will not always be the same.
You can indeed use array_splice, but you have to find the position of your insertion point first:
$sidePanelArr = explode( '&', $_SESSION['sidePanel'] );
// find the position of 'sidePanel[]=2' in array
$p = array_search( 'sidePanel[]=2', $sidePanelArr );
// insert after it
array_splice( $sidePanelArr, p+1, 0, 'sidePanel[]=3' );
$sidePanelSt = implode( '&', $sidePanelArr );
You could also splice the string right into your original string without exploding and re-imploding.
The function substr_replace() is your friend:
$sidePanelSt = $_SESSION['sidePanel'];
// find the position of 'sidePanel[]=2' in string
// (adding '&' to the search string makes sure that 'sidePanel[]=2' does not match 'sidePanel[]=22')
$p = strpos( $sidePanelSt.'&', 'sidePanel[]=2&') + strlen('sidePanel[]=2' );
// insert after it (incl. leading '&')
$sidePanelSt = substr_replace( $sidePanelSt , '&sidePanel[]=3' , $p, 0 );
See : http://codepad.org/5AOXcHPk
<?php
$str = "sidePanel[]=1&sidePanel[]=2&sidePanel[]=4";
$sidePanelArr = explode('&', $str);
$newVal = 'sidePanel[]=3';
$insertAt = 2 ;
$newArr = array_merge(array_slice($sidePanelArr, 0,$insertAt),
array($newVal),
array_slice($sidePanelArr,$insertAt)
);
$sidePanel = implode('&', $newArr);
echo $sidePanel,PHP_EOL ;
?>
You could turn it into an array using parse_str and locate the value you want to insert it after:
// Turn it into an array
$url = parse_str($_SESSION['sidePanel']));
// What value do we want to insert it after
$insert_after = 2;
// The value you want to insert
$sidePanel = 3;
// Find the position of $insert_after
$offset = array_search($insert_after, $url['sidePanel']);
// Slice the array up (based on the value)
$url['sidePanel'] = array_merge(array_slice($url['sidePanel'], 0, $offset),
array($sidePanel),
array_slice($url['sidePanel'], $offset));
// Turn it back into a string
echo http_build_query($url);
How can I get the following code to work?
$a = explode('s', $str)[0];
I only see solutions looking like this:
$a = explode('s', $str); $a=$a[0];
As others have said, PHP is unlike JavaScript in that it can't access array elements from function returns.
The second method you listed works. You can also grab the first element of the array with the current(), reset(), or array_pop() functions like so:
$a = current( explode( 's', $str ) ); //or
$a = reset( explode( 's', $str ) ); //or
$a = array_pop ( explode( 's', $str ) );
If you would like to remove the slight overhead that explode may cause due to multiple separations, you can set its limit to 2 by passing two after the other arguments. You may also consider using str_pos and strstr instead:
$a = substr( $str, 0, strpos( $str, 's' ) );
Any of these choices will work.
EDIT Another way would be to use list() (see PHP doc). With it you can grab any element:
list( $first ) = explode( 's', $str ); //First
list( ,$second ) = explode( 's', $str ); //Second
list( ,,$third ) = explode( 's', $str ); //Third
//etc.
That not your style? You can always write a small helper function to grab elements from functions that return arrays:
function array_grab( $arr, $key ) { return( $arr[$key] ); }
$part = array_grab( explode( 's', $str ), 0 ); //Usage: 1st element, etc.
EDIT: PHP 5.4 will support array dereferencing, so you will be able to do:
$first_element = explode(',','A,B,C')[0];
You are correct with your second code-block. explode, and other functions can't return a fully formed array for immediate use,and so you have to set a temporary variable. There may be code in the development tree to do that, but the only way to get the elements you need for now, is the temporary variable.
use current
$a = current(explode('s', $str));
but I found is ugly
You can use this:
$a = array_shift(array_slice(explode("s", $str), 0, 1)));
This is the best way I have found to get a specific element from an array from explode.
Breakdown:
Explode returns an array on delimiter
array_slice($arrayname, $offset, $length) gives you a new array with all items from offset, lenght
array_shift($array) gives you the first (and in this case, the only) item in the array passed to it.
This doesen't look pretty, but does the same as:
$a = explode('s', $str)[0];
There must be a better way to do this, but I have not found it.
Update:
I was investigating this because I wanted to extract a portion of a URL, so i did the following tests:
function urlsplitTest()
{
$url = 'control_panel/deliveryaddress/188/edit/';
$passes = 1000000;
Timer::reset();
Timer::start();
$x =0;
while ($x<$passes) {
$res = array_shift(array_slice(explode("/", $url), 2, 1));
$x++;
}
Timer::stop();
$time = Timer::get();
echo $res.'<br />Time used on: array_shift(array_slice(explode("/", $url), 2, 1)):'.$time;
Timer::reset();
Timer::start();
$x =0;
while ($x<$passes) {
$res = array_get(explode("/", $url), 2);
$x++;
}
Timer::stop();
$time = Timer::get();
echo $res.'<br />Time used on: array_get(explode("/", $url), 2): '.$time;
Timer::reset();
Timer::start();
$x =0;
while ($x<$passes) {
$res = substr($url, 30, -6);
$x++;
}
Timer::stop();
$time = Timer::get();
echo $res.'<br />Time used on: substr($url, 30, -6): '.$time;
}
function array_get($array, $pos) {return $array[$pos];}
The results were as following:
Time used on: array_shift(array_slice(explode("/", $url), 2, 1)):7.897379
Time used on: array_get(explode("/", $url), 2): 2.979483
Time used on: substr($url, 30, -6): 0.932806
In my case i wanted to get the number 188 from the url, and all the rest of the url was static, so i ended up using the substr method, but for a dynamic version where lenth may change, the array_get method above is the fastets and cleanest.