PHP: Build a URL encoded while a value exists in multi array - php

My goal is:
If a value in those arrays match with an extention of a file, then I can builds a nice URL encoded string which I can append to a url using the http_build_query() function. If no match is found, it return nothing.
I have tried it every possible way and it doesn't work, as the code below. can you check on which part is wrong ?.
$name = 'myfile.mp4';
$list = array(
'video' => array('3gp', 'mkv', 'mp4'),
'photo' => array('jpg', 'png', 'tiff')
);
// File Ext Check
$ext = (strpos($name, '.') !== false) ? strtolower(substr(strrchr($name, '.'), 1)) : '';
$type = null;
$find = $ext;
array_walk($list, function ($k, $v) use ($find, &$type)
{
if (in_array($find, $k))
{
$type = $v;
$data = array();
switch ($type)
{
case 'video':
$data['title'] = 'video';
$data['description'] = 'my video';
break;
case 'photo':
$data['title'] = 'photo';
$data['description'] = 'my photo';
break;
}
}
else {
echo "not both!.";
exit;
{
});
if ($type == 'video') {
$link = 'https://www.video.com' . http_build_query($data);
}
else
if ($type == 'photo') {
$link = 'https://www.photo.com' . http_build_query($data);
}
echo $link;
Thank you...

You $data is set in the array_walk() scope, but out of the array_walk() scope is not defined. So in the http_build_query($data), here $data has not defined.
You may referende the $data in the use(), then after the array_walk(), you can use its value. In your code you use in_array() to check the file type in a list, for performance I recomend you to see this post.

Related

PHP: Systems path to actual URL

Before i make my question I wanna say that I have tried every related post I found from stackoverflow such as PHP - Convert File system path to URL and nothing worked for me, meaning I did not get the Url I was looking for.
I need a
function PathToUrl($path)
{
...
}
which returns the actual Url of the $path
Example usage: echo PathToUrl('../songs'); should output http://www.mywebsite.com/files/morefiles/songs.
Note: The problem with the functions i found on stackoverflow is that they dont work with path that contains ../ for example on echo PathToUrl('../songs'); i would get something similar to http://www.mywebsite.com/files/morefiles/../songs which is not what i am looking for.
Here you go, I made this function and it works perfectly:
function getPath($path)
{
$url = "http".(!empty($_SERVER['HTTPS'])?"s":"").
"://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
$dirs = explode('/', trim(preg_replace('/\/+/', '/', $path), '/'));
foreach ($dirs as $key => $value)
if (empty($value)) unset($dirs[$key]);
$parsedUrl = parse_url($url);
$pathUrl = explode('/', trim($parsedUrl['path'], '/'));
foreach ($pathUrl as $key => $value)
if (empty($value)) unset($pathUrl[$key]);
$count = count($pathUrl);
foreach ($dirs as $key => $dir)
if ($dir === '..')
if ($count > 0)
array_pop($pathUrl);
else
throw new Exception('Wrong Path');
else if ($dir !== '.')
if (preg_match('/^(\w|\d|\.| |_|-)+$/', $dir)) {
$pathUrl[] = $dir;
++$count;
}
else
throw new Exception('Not Allowed Char');
return $parsedUrl['scheme'].'://'.$parsedUrl['host'].'/'.implode('/', $pathUrl);
}
Example:
Let's say your current location is http://www.mywebsite.com/files/morefiles/movies,
echo getPath('../songs');
OUTPUT
http://www.mywebsite.com/files/morefiles/songs
echo getPath('./songs/whatever');
OUTPUT
http://www.mywebsite.com/files/morefiles/movies/songs/whatever
echo getPath('../../../../../../');
In this case it will throw an exception.
NOTE
I use this regex '/^(\w|\d|\.| |_|-)+$/' to check the path directories which mean that only digit, word characters, '.', '-', '_' and ' ' are allowed. An exception will be trown for others characters.
The path .///path will be corrected by this function.
USEFUL
explode
implode
array_pop
parse_url
trim
preg_match
preg_replace
I see an answer was already posted, however I will post my solution which allows for direct specification of the URL :
echo up('http://www.google.ca/mypage/losethisfolder/',1);
function up($url, $howmany=1) {
$p = explode('/', rtrim($url, '/'));
if($howmany < count($p)) {
$popoff = 0;
while($popoff < $howmany) {
array_pop($p);
$popoff++;
}
}
return rtrim(implode('/', $p), '/') . '/';
}
Following is a much more elegant solution for virtual paths :
$path = '/foo/../../bar/../something/../results/in/skipthis/../this/';
echo virtualpath($path);
function virtualpath($path = null) {
$loopcount = 0;
$vpath = $path;
if(is_null($vpath)) { $vpath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); }
$vpath = rtrim($vpath,'/') . '/';
while(strpos($vpath,'../') !== false ) {
if(substr($vpath,0,4) == '/../') { $vpath = '/'. substr($vpath,4); }
$vpath = preg_replace('/(\/[\w\d\s\ \-\.]+?\/\.\.\/)/', '/', $vpath );
}
return $vpath;
}

Creating a function from a variable

I am attempting to run a function named from a variable. There is no syntax error. Temperature is not returned. I don't know for certain if the problem is with the function itself or the eval. Variations on the eval theme have not worked so far.
function getBtemp($lum, $sub){
$tempsB = array(
"V" => array( 30000, 25400, ... ),
"III" => array( 29000, 24000, ... ),
"I" => array( 26000, 20800, ... ) );
if($lum == "VI"){ $lum = "V"; }
else if($lum == "IV"){ $lum = "III"; }
else if($lum == "II" || $lum == "Ib" || $lum == "Ia" ){ $lum = "V"; }
return $tempsB['$lum']['$sub']; }
// Variables:
$spectralclass = "B";
$luminosityclass = "V";
$subclass = 5;
// Needed:
$temp = getBtemp($luminosityclass, $subclass);
// Functions are named from spectral class, e.g. get.$spectralclass.temp()
// Attempt:
$str = "$temp = get".$spectralclass."temp($luminosityclass, $subclass);";
eval($str);
Try doing this:
$func = 'get'.$spectralclass.'temp';
$temp = $func($luminosityclass, $subclass);
You might be better off doing something like
$functionName = 'get' . $spectralclass . 'temp';
$temp = $functionName($luminosityclass, $subclass);
This is what the PHP manual calls a "variable function". In most cases PHP lets you treat a string variable as a function name, and doing so is a bit safer (more restrictive, less error-prone) than eval.
You need to pass parameters after set function name. See a sample:
function getAtemp($a = 'default') {
echo $a;
}
$name = 'Trest';
$function = 'A';
$temp = 'get' . $function . 'temp';
echo($temp('teste'));
Additionally, read from Eric Lippert: Eval is Evil
Replace the following line:
$str = "$temp = get".$spectralclass."temp($luminosityclass, $subclass);";
by
$str = '$temp = get'.$spectralclass.'temp($luminosityclass, $subclass);';
or
$str = "\$temp = get".$spectralclass."temp(\$luminosityclass, \$subclass);";
See http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.double

Searching through an Array and replacing some of its values

I have a preg_match_all that is generating an array of urls from a string. The array resembles:
$url[0] = "http://www.siteone.com";
$url[1] = "http://www.sitetwo.com";
$url[2] = "http://www.sitethree.com/example1";
$url[3] = "http://www.sitefour.com";
$url[4] = "http://www.sitethree.com/example2";
$url[5] = "http://www.sitefive";
$url[6] = "http://www.sitesix";
$url[7] = "http://www.siteseven";
$url[8] = "http://www.sitethree.com/example3";
However, I need to be able to search through the #url array to change the value when it contains "http://www.sitethree.com" and set this particular value in the array to "no value". So that once this process was applied,, it would the array would look like this:
$url[0] = "http://www.siteone.com";
$url[1] = "http://www.sitetwo.com";
$url[2] = "no value";
$url[3] = "http://www.sitefour.com";
$url[4] = "no value";
$url[5] = "http://www.sitefive";
$url[6] = "http://www.sitesix";
$url[7] = "http://www.siteseven";
$url[8] = "no value";
I have tried numerous variations of preg_match_all and if statements within loops but just couldn't get it. Any help would be greatly appreciated.
$url = array_map(function($v) {
return strpos($v, 'http://www.sitethree.com') === false ? $v : 'no value';
}, $url);
foreach ($url as &$value) {
if (strpos($value, 'http://www.sitethree.com') === 0) {
$value = 'no value';
}
}
foreach($url as $id => $link){
if(strstr($link, 'sitethree.com')){
$url[$id] = 'no value';
}
}
print_r($url);
A simple way of doing it is this:
foreach($url as $key => $value)
{
if(stristr($value, "http://www.sitethree.com"))
{
$url[$key] = "no value";
}
}

Dynamically update variables into an existing file?

I'm trying to build a small CMS using CodeIgniter, and I need to be able to dynamically update some variables within the application/config.php
So far I did:
private function update_file ($file, $var, $var_name) {
$start_tag = "<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n";
if (file_exists($file)) {
require_once ($file);
$updated_array = array_merge($$var_name, $var);
$data = $start_tag."\$".$var_name." = ".var_export($updated_array, true).";";
file_put_contents($file, $data);
} else {
return false;
}
}
Everything works just fine! The result in the config.php file will be:
<?php ...;
$config = array (
'base_url' => '',
...
...
);
But what if I would like to maintain the original config.php file format with comments, spaces and
separated declared $config['key'] = 'value' ... ?
Is that possible ?
EDIT:
Thank you for your answers, very precious.
I found a slightly different solution for my needs, performing a preg_replace on the return of file_get_contents() and then write back on the file the new resulting string. File maintains the exact original clean format.
private function update_file ($file, $var, $var_name) {
if (file_exists($file)) {
require_once ($file);
$contents = file_get_contents($file);
$updated_array = array_merge($$var_name, $var);
$search = array();
$replace = array();
foreach($$var_name as $key => $val) {
$pattern = '/\$'.$var_name.'\[\\\''.$key.'\\\'\]\s+=\s+[^\;]+/';
$replace_string = "\$".$var_name."['".$key."'] = ".var_export($updated_array[$key], true);
array_push($search, $pattern);
array_push($replace, $replace_string);
}
$new_contents = preg_replace($search, $replace, $contents);
write_file($file, $new_contents);
}
Maybe it requires some slight performance improvements. But this is my baseline idea.
create the keys with empty values
$config['base_url'] = '';
then set them inside any of your controllers.
This works best if you store the values in the db, and initialize them in MY_Controller.
$this->config->set_item('base_url', 'value');
It is possible. I can't find the code , but once i have written something like that. Whole idea was based on tokenizing template file and substitute values in an array, preserving key order, line numbers and comments from the template.
[+] Found it. It's purpose was to fill values from template that looked like this (it was much bigger of course):
<?php
$_CFG = array(
// DB section
'db_host' => 'localhost',
'db_user' => 'root',
'db_pass' => '',
'db_name' => 'test',
// Site specific
'lang' => array('pl','en'),
'admin' => 'admin#example.com',
);
And the code that was doing all the magic:
$tokens = token_get_all(file_get_contents('tpl/config.php'));
$level = -1;
$buffer = '';
$last_key = 0;
$iteration = 0;
foreach($tokens as $t){
if($t === ')'){
$iteration = 0;
$last_key = 0;
$level--;
}
if(is_array($t)){
if($t[0] == T_ARRAY && strtolower($t[1]) === 'array')
$level++;
if($t[0] == T_CONSTANT_ENCAPSED_STRING){
if($last_key){
if($level){
if(isset($new_config[$last_key][$iteration])){
$buffer .= var_export($new_config[$last_key][$iteration], TRUE);
}
else
$buffer .= 'null';
$iteration++;
}
else{
if(isset($new_config[$last_key]))
$buffer .= var_export($new_config[$last_key], TRUE);
else
$buffer .= 'null';
$last_key = 0;
}
}
else{
$buffer .= $t[1];
$last_key = trim($t[1],"'");
}
}
else
$buffer .= $t[1];
}
else
$buffer .= $t;
}
file_put_contents('config.php',$buffer);

PHP: building a URL path

I have a few strings to combine to build a full path. e.g.
$base = "http://foo.com";
$subfolder = "product/data";
$filename = "foo.xml";
// How to do this?
$url = append_url_parts($base, $subfolder, $filename); ???
String concatenation won't do, that would omit the necessary forward slashes.
In Win32 I'd use PathCombine() or PathAppend(), which would handle adding any necessary slashes between strings, without doubling them up. In PHP, what should I use?
Try this:
$base = "http://foo.com";
$subfolder = "product/data";
$filename = "foo.xml";
function stripTrailingSlash(&$component) {
$component = rtrim($component, '/');
}
$array = array($base, $subfolder, $filename);
array_walk_recursive($array, 'stripTrailingSlash');
$url = implode('/', $array);
when it comes down to something like this I like to use a special function with unlimited parameters.
define('BASE_URL','http://mysite.com'); //Without last slash
function build_url()
{
return BASE_URL . '/' . implode(func_get_args(),'/');
}
OR
function build_url()
{
$Path = BASE_URL;
foreach(func_get_args() as $path_part)
{
$Path .= '/' . $path_part;
}
return $Path;
}
So that when I use the function I can do
echo build_url('home'); //http://mysite.com/home
echo build_url('public','css','style.css'); //http://mysite.com/public/css/style.css
echo build_url('index.php'); //http://mysite.com/index.php
hope this helps you, works really well for me especially within an Framework Environment.
to use with params you can append the url like so for simplicity.
echo build_url('home') . '?' . http_build_query(array('hello' => 'world'));
Would produce: http://mysite.com/home?hello=world
not sure why you say string concat won't do, because something like this is basically similar to a string concat. (untested semi-pseudo)
function append_url_parts($base, $subf, $file) {
$url = sprintf("%s%s%s", $base, (($subf)? "/$subf": ""), (($file)? "/$file": ""));
return $url;
}
with string concat, we'd have to write a slightly longer block like so:
function append_url_parts($base, $subf, $file) {
$subf = ($subf)? "/$subf": "";
$file = ($file)? "/$file": "";
$url = "$base$subf$file";
return $url;
}
I usually go simple:
<?
$url = implode('/', array($base, $subfolder, $filename));
Either that or use a framework, and then use whatever route system it has.
There are a few considerations first.
Are you interested in getting the current path of the script or some other path?
How flexible do you need this to be? Is it something that is going to change all the time? Is it something an admin will set once and forget?
You want to be careful not to include the slash bug where your document has a slash added at the end because you were too lazy to figure out how to separate directory vars from the file var. There will only be one file and one base per URL and unknown number of directories in each path, right? :)
If you want to make sure there are no duplicate slashes within the resultant path, I like this little function...simply pass it an array of path part you want combined and it will return a formatted path - no need to worry whether any of the parts contain a slash alerady or not:
function build_url($arr)
{
foreach ( $arr as $path ) $url[] = rtrim ( $path, '/' );
return implode( $url, '/' );
}
This should work on all versions of PHP too.
Not my code, but a handy function which takes an absolute URL and a relative URL and combines the two to make a new absolute path.
The function has been modified to ignore an absolute URL passed as relative ( basically anything that includes a schema ).
$url = "http://www.goat.com/money/dave.html";
$rel = "../images/cheese.jpg";
$com = InternetCombineURL($url,$rel);
public function InternetCombineUrl($absolute, $relative) {
$p = parse_url($relative);
if(isset($p["scheme"]))return $relative;
extract(parse_url($absolute));
$path = dirname($path);
if($relative{0} == '/') {
$cparts = array_filter(explode("/", $relative));
}
else {
$aparts = array_filter(explode("/", $path));
$rparts = array_filter(explode("/", $relative));
$cparts = array_merge($aparts, $rparts);
foreach($cparts as $i => $part) {
if($part == '.') {
$cparts[$i] = null;
}
if($part == '..') {
$cparts[$i - 1] = null;
$cparts[$i] = null;
}
}
$cparts = array_filter($cparts);
}
$path = implode("/", $cparts);
$url = "";
if($scheme) {
$url = "$scheme://";
}
if(isset($user)) {
$url .= "$user";
if($pass) {
$url .= ":$pass";
}
$url .= "#";
}
if($host) {
$url .= "$host/";
}
$url .= $path;
return $url;
}
I wrote this function for all cases to combine url parts with no duplicate slashes.
It accepts many arguments or an array of parts.
Some parts may be empty strings, that does not produce double slashes.
It keeps starting and ending slashes if they are present.
function implodePath($parts)
{
if (!is_array($parts)) {
$parts = func_get_args();
if (count($parts) < 2) {
throw new \RuntimeException('implodePath() should take array as a single argument or more than one argument');
}
} elseif (count($parts) == 0) {
return '';
} elseif (count($parts) == 1) {
return $parts[0];
}
$resParts = [];
$first = array_shift($parts);
if ($first === '/') {
$resParts[] = ''; // It will keep one starting slash
} else {
// It may be empty or have some letters
$first = rtrim($first, '/');
if ($first !== '') {
$resParts[] = $first;
}
}
$last = array_pop($parts);
foreach ($parts as $part) {
$part = trim($part, '/');
if ($part !== '') {
$resParts[] = $part;
}
}
if ($last === '/') {
$resParts[] = ''; // To keep trailing slash
} else {
$last = ltrim($last, '/');
if ($last !== '') {
$resParts[] = $last; // Adding last part if not empty
}
}
return implode('/', $resParts);
}
Here is a check list from unit test. Left array is input and right part is result string.
[['/www/', '/eee/'], '/www/eee/'],
[['/www', 'eee/'], '/www/eee/'],
[['www', 'eee'], 'www/eee'],
[['www', ''], 'www'],
[['www', '/'], 'www/'],
[['/www/', '/aaa/', '/eee/'], '/www/aaa/eee/'],
[['/www', 'aaa/', '/eee/'], '/www/aaa/eee/'],
[['/www/', '/aaa/', 'eee/'], '/www/aaa/eee/'],
[['/www', 'aaa', 'eee/'], '/www/aaa/eee/'],
[['/www/', '/aaa/'], '/www/aaa/'],
[['/www', 'aaa/'], '/www/aaa/'],
[['/www/', 'aaa/'], '/www/aaa/'],
[['/www', '/aaa/'], '/www/aaa/'],
[['/www', '', 'eee/'], '/www/eee/'],
[['www/', '/aaa/', '/eee'], 'www/aaa/eee'],
[['/www/', '/aaa', ''], '/www/aaa'],
[['', 'aaa/', '/eee/'], 'aaa/eee/'],
[['', '', ''], ''],
[['aaa', '', '/'], 'aaa/'],
[['aaa', '/', '/'], 'aaa/'],
[['/', 'www', '/'], '/www/'],
It can be used as implodePath('aaa', 'bbb') or implodePath(['aaa', 'bbb'])

Categories