I am about to make a system that automaticly puts &pni=something behind an URL. It would be easy if the url just was http://t.co/something.php with "?pni=...." but users can also have http://t.co/something.php?myown=paramater and then the system should add & instead of ?
How can I put the pni parameter behind the URL and to be valid every time? I've tried this without luck.
<?php
function nice($in){
$out = parse_url($in);
return $out['scheme'] . "://" . $out['host'] . $out['path'] . "?" . $out['query'];
}
$urls = array(
"http://t.co/something.php?w=23&",
"http://t.co/something.php?w=23&dfdf=",
"http://t.co/something.php?",
"http://t.co/something.php",
"http://t.co/something",
"http://t.co/something.php?w=23&dfdf=34&hvem",
);
foreach ( $urls as $url):
echo print_r(nice($url)) . "<br/>";
endforeach;
?>
function nice($in) {
$out = parse_url($in);
if ($out['query'] != "") {
$out['query'] = "pni=something&".$out['query'];
}
else {
$out['query'] = "pni=something";
}
return $out['scheme'] . "://" . $out['host'] . $out['path'] . "?" . $out['query'];
}
check if there is any "?" in the url and concat the pni=something to it accordingly.
function nice($url){
if(strpos($url,"?")!==false){
return $url."&pni=something";
}else{
return $url."?pni=something";
}
}
You can access the query string specifically using
$_SERVER['QUERY_STRING']
If it is empty you can use
$url .= '?arg=val';
If query string is ! empty
$url .= '&arg=val';
Related
Good Day,
Below I have provided 2 codes, which I did not write but grabbed from a forum. I really need to learn the solution to this new mystery. Both make use of the urlencode(). They are nearly the same code.
I notice that, only the 1st code's output is normal and not encoded while the 2nd one's output is encoded. Why ?
Since both are making use of the urlencode() then shouldn't both their outputs be in encoded format ? This has been greatly puzzling me for days now. I give-up. What's the mystery behind this ?
1st Code:
$url = 'http://nogdog.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=12';
echo prepare_url($url) . "\n";
function prepare_url($url) {
$url_parts = parse_url($url);
if($url_parts === false or empty($url_parts['host'])) {
return false;
}
$url_out = preg_match('/^https?/i', $url_parts['scheme']) ? strtolower($url_parts['scheme']) : 'https';
$url_out .= "://{$url_parts['host']}{$url_parts['path']}";
if(!empty($url_parts['query'])) {
parse_str($url_parts['query'], $query_parts);
foreach($query_parts as $q_key => $q_value) {
$query_string_parts[] = urlencode($q_key).'='.urlencode($q_value);
}
$url_out .= '?'.implode('&', $query_string_parts);
}
return $url_out;
}
2nd Code:
function prepare_url2($url) {
$url_parts = parse_url($url);
if($url_parts === false or empty($url_parts['host'])) {
return false;
}
// re-assemble the start of url string
$url_start = preg_match('/^https?/i', $url_parts['scheme']) ? strtolower($url_parts['scheme']) : 'https';
$url_start .= "://{$url_parts['host']}{$url_parts['path']}";
// rawurlencode the start of url string
$url_out = rawurlencode($url_start);
if(!empty($url_parts['query'])) {
parse_str($url_parts['query'], $query_parts);
foreach($query_parts as $q_key => $q_value) {
// assemble and check if value is numeric
$query_string_parts[] = urlencode($q_key).'='.(is_numeric($q_value) ? intval($q_value) :urlencode($q_value));
}
$url_out .= '?'.implode('&', $query_string_parts);
}
return $url_out;
}
$url = 'http://zorg.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=13';
echo prepare_url2($url);
NOTE
The difference between the two codes are that, the 1st one defines the $url and calls the prepare_url() function at the top. (Before the prepare_url() function's code).
$url = 'http://nogdog.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=12';
echo prepare_url($url) . "\n";
While, the 2nd one defines the $url and calls the prepare_url() function at the bottom. (After the prepare_url() function's code).
$url = 'http://zorg.com/cat/subcat?var 1=value 1&var2=2&this other=thing&number is=13';
echo prepare_url($url);
Apart from that, both codes are the same.
So, if both the codes are the same (so to speak), then why does the 1st code output like this:
http://nogdog.com/cat/subcat?var_1=value+1&var2=2&this_other=thing&number_is=12
And, why does the 2nd code output like this:
http%3A%2F%2Fzorg.com%2Fcat%2Fsubcat?var_1=value+1&var2=2&this_other=thing&number_is=13
I need create a function that checks a parsed value to see if it matches a few other values and then return that match. For example I am trying to match video urls correctly. So if it's youtube do this or if it's vimeo do this or if it's nothing do this. I know how to create a function but I'm not sure what to use for the parse, would it be parse_url?
For my test cases I need to send in the right parameter and then see that the returned values are matching what I want them to be.
Here's what I've tried so far:
function get_video_embed_string($videostring) {
$video_url_parse = parse_url( $videostring, PHP_URL_HOST ); //get the input string ready to parse
$returnstring = ""; //default return string to empty string
if ($video_url_parse === 'vimeo.com') {
$returnstring = str_replace( 'vimeo.com', 'player.vimeo.com', $video_url_parse );
} else if ($video_url_parse === 'youtube.com') {
$returnstring = str_replace( 'youtube.com', 'youtube.com/embed/', $video_url_parse );
} else {
//do nothing
}
return $returnstring;
}
parse_str($returnstring);
//now setup your test cases and see what echos out of the above method
if ($returnstring === 'player.vimeo.com') {
echo "vimeo: <" . get_video_embed_string ("https://vimeo.com/abcdefg123") . ">";
} else if ($returnstring === 'youtube.com/embed/'){
echo "youtube: <" . get_video_embed_string ("https://youtube.com/abcdefg123") . ">";
} else if($returnstring === '' ){
echo "nothing: <" . get_video_embed_string ("https://abc123.com/abcdefg123") . ">";
} else {
echo "empty:< " . get_video_embed_string ("") . ">";
}
I think you're on the right track using parse_url, but I have a couple suggestions for improvement:
instead of the run-on if/elseif chain, use a switch
the str_replace isn't working well as is because you're replacing the parsed host, so why spend the overhead searching again for the string to replace when you've already found it.
in the user comments for parse_url, there's an excellent example to reconstruct the parsed url. this will avoid string replacements where the host name is also part of the url (www.youtube.com/youtubevideo123)
simplify your test cases by just calling your function for each case instead of another if/else chain check.
function get_video_embed_string($videostring) {
$video_url_parse = parse_url($videostring); //get the input string ready to parse
switch ($video_url_parse['host']) {
case 'vimeo.com':
$video_url_parse['host'] = 'player.vimeo.com';
return unparse_url($video_url_parse);
case 'youtube.com':
$video_url_parse['host'] = 'youtube.com/embed';
return unparse_url($video_url_parse);
default:
return unparse_url($video_url_parse);
}
}
function unparse_url($parsed_url) {
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass#" : '';
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
}
//now setup your test cases and see what echos out of the above method
echo "vimeo: <" . get_video_embed_string ("https://vimeo.com/abcdefg123") . ">\n";
echo "youtube: <" . get_video_embed_string ("https://youtube.com/abcdefg123") . ">\n";
echo "nothing: <" . get_video_embed_string ("https://abc123.com/abcdefg123") . ">\n";
echo "empty:< " . get_video_embed_string ("") . ">\n";
This will result in the following output in source:
vimeo: <https://player.vimeo.com/abcdefg123>
youtube: <https://youtube.com/embed/abcdefg123>
nothing: <https://abc123.com/abcdefg123>
empty:< >
parse_url() is very good for parsing URLs and - in your case - extract the host name from it.
Your example is a little messed up. $returnstring is not defined outside of your function. You should turn error reporting on, so you will see NOTICE messages on this kind of errors.
I assume, your function should return the video embed url, not only the host name. So you should do your replace on $videostring, not $video_url_parse:
function get_video_embed_string($videostring) {
$video_url_parse = parse_url( $videostring, PHP_URL_HOST ); //get the input string ready to parse
$returnstring = ""; //default return string to empty string
if ($video_url_parse === 'vimeo.com') {
$returnstring = str_replace( 'vimeo.com', 'player.vimeo.com', $videostring );
} else if ($video_url_parse === 'youtube.com') {
$returnstring = str_replace( 'youtube.com', 'youtube.com/embed', $videostring );
} else {
//do nothing
}
return $returnstring;
}
This will give you this output:
echo get_video_embed_string("https://vimeo.com/abcdefg123"); // https://player.vimeo.com/abcdefg123
echo get_video_embed_string("https://youtube.com/abcdefg123"); // https://youtube.com/embed/abcdefg123
echo get_video_embed_string("https://abc123.com/abcdefg123"); // <empty string>
[For a more robust approach, I would probably try to extract the video ID from all known valid URL schemes using regexp and just insert this ID in the embed url.]
I am a beginner in PHP and currently, to post variables in uri addresses I use:
echo "<form method='POST' action='".$_SERVER['REQUEST_URI']."&myvar=".$myvar."'>";
but it does not work when the URI is just something like wwww.mysite.com/index because there is no parameters yet (and so no ? after the main address). So how to pass the php parameters in the address in a generic way ?
You can use a combination of parse_url, parse_str, and http_build_query:
// build URL with query
function q($url, array $params) {
return parse_url($url, PHP_URL_PATH) . '?' . http_build_query($params);
}
// build URL and expand query
function qe($url, array $new_params, $overwrite = true) {
parse_str(parse_url($url, PHP_URL_QUERY), $params);
if ($overwrite) {
$new_params = $new_params + $params;
} else {
$new_params = $params + $new_params;
}
return q($url, $new_params);
}
$url = qe($_SERVER['REQUEST_URI'], array('myvar' => $myvar));
echo "<form method='POST' action='".htmlspecialchars($url, ENT_QUOTES)."'>";
Just check for the existance of any chars first. E.g.
$link = $_SERVER['REQUEST_URI'];
if (substr_count($link, '?') == 0) {
$link .= '?';
}
echo "<form method='POST' action='".$link."&myvar=".$myvar."'>";
I'm working on a little project and I've gone brain dead, so I'm hoping someone here can help me defeat my coders block.
I'm trying to create a page using php that changes its content display depending on what (if any) value is passed to the page (Locations). I have created a safelist array which I've stored the different locations. First I check any value passed against the safe list, if its a match I display one set of content.
If it doesn't match I'm running a similarity test to check if theres maybe a simple typo and can still navigate people to the page I think they wanted but this is where I'm getting stuck.
I'm hoping that someone could type
www.example.co.uk/location.php <---- to load a generic location page
www.example.co.uk/location.php?loc=Bishops-Stortford <---- to load a targeted location page
www.example.co.uk/location.php?loc=Bishop-Stortford <---- to load a targeted location page despite mispelling providing its a 90% or more match
www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?> ---- hopefully my system will disarm nasty code injection
I'll post my code below so you can see what I've got.
<?php
$loc = "";
$safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware",
"Essex", "Hertfordshire");
if(isset($_GET["loc"])) {
/* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
$loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
}
/* Is word in safelist */
if (in_array($loc, $safelist)) {
/* Yes */
if (($loc == "Essex") or ($loc == "Hertfordshire")) {
$county = True;
} else {
$county = False;
}
if ($county == False) {
echo "\"" . $loc . "\" is not a county";
}else{
echo "\"" . $loc . "\" is a county";
}
} else {
/* No, Is string 90% similar to any entry within the safelist? */
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
}
}
?>
I can't think what to do for the if ($percent >=90). I know I want to exit the loop and get the result from the first 90% or more match I find but am not 100% sure how to do this.
Also whats the best way to deal with code injection like www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?>
I think this is what you want:
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
$loc = $safeword;
$county = true;
break;
}
}
As long as you don't call eval() on user input, you don't have to worry about them injecting PHP statements. When you echo something, it's sent to the browser, it's not executed again by PHP. However, you should still sanitize the output, because it might contain HTML markup, perhaps even Javascript, which could hijack the user's browser. When displaying output on the page, use htmlentities() to encode it:
echo "Greetings, " . htmlentities($first_name);
To answer the second part of your question, I use htmlentities to output data directly to the screen from input and something like this function on the data before a save to a database:
function escape_value($value)
{
if($this->real_escape_string_exists)
{
if($this->magic_quotes_active){$value = stripslashes($value);}
$value = mysql_real_escape_string($value);
}
else
{
if(!$this->magic_quotes_active){$value = addslashes($value);}
}
return $value;
}
I think I would restructure it, something like this:
$loc = "";
$safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware",
"Essex", "Hertfordshire");
if(isset($_GET["loc"])) {
/* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
$loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
}
$good = '';
if (in_array($loc, $safelist)) {
$good = $loc;
} else {
foreach ($safelist as $safeword) {
similar_text($safeword, $loc, $percent);
echo $safeword . " " . $loc . " " . $percent . "<br />";
if ($percent >= 90) {
$good = $safeword;
}
}
}
if ( ! empty($good)){
/* Yes */
if (($good == "Essex") or ($good == "Hertfordshire")) {
$county = True;
} else {
$county = False;
}
if ($county == False) {
echo "\"" . $good . "\" is not a county";
}else{
echo "\"" . $good . "\" is a county";
}
//And whatever else you want to do with the good location...
}
Like Barmar said, since you're not doing anything with the input value except for comparing it to an array, there's no risk of an attack in that way.
I'm using the jquery address plugin to build an ajax driven site, and i've got it working! Yay! For the purposes of this question we can use the test site:
http://www.asual.com/jquery/address/samples/crawling
http://www.asual.com/download/jquery/address
(I had to remove two calls to urlencode() to make the crawling example work.)
I'm encountering a problem with the $crawling->nav() call. It basically uses js and php to load parts of an xml file into the dom. I (mostly) understand how it works, and I would like to modify the example code to include sub pages.
For example, I would like to show 'subnav-project.html' at '/!#/project' and '/!#/project/blue', but not at '/!#/contact'. To do this, I figure php should 'know' what page the user is on, that way I can base my logic off of that.
Is this crazy? Can php ever know the current state of the site if I'm building it this way? If not, how does one selectively load html snippets, or modify what links are shown in navigation menus?
I've never gotten too crazy with ajax before, so any feedback at all would be helpful.
EDIT
This is the crawling class.
class Crawling {
const fragment = '_escaped_fragment_';
function Crawling(){
// Initializes the fragment value
$fragment = (!isset($_REQUEST[self::fragment]) || $_REQUEST[self::fragment] == '') ? '/' : $_REQUEST[self::fragment];
// Parses parameters if any
$this->parameters = array();
$arr = explode('?', $fragment);
if (count($arr) > 1) {
parse_str($arr[1], $this->parameters);
}
// Adds support for both /name and /?page=name
if (isset($this->parameters['page'])) {
$this->page = '/?page=' . $this->parameters['page'];
} else {
$this->page = $arr[0];
}
// Loads the data file
$this->doc = new DOMDocument();
$this->doc->load('data.xml');
$this->xp = new DOMXPath($this->doc);
$this->nodes = $this->xp->query('/data/page');
$this->node = $this->xp->query('/data/page[#href="' . $this->page . '"]')->item(0);
if (!isset($this->node)) {
header("HTTP/1.0 404 Not Found");
}
}
function base() {
$arr = explode('?', $_SERVER['REQUEST_URI']);
return $arr[0] != '/' ? preg_replace('/\/$/', '', $arr[0]) : $arr[0];
}
function title() {
if (isset($this->node)) {
$title = $this->node->getAttribute('title');
} else {
$title = 'Page not found';
}
echo($title);
}
function nav() {
$str = '';
// Prepares the navigation links
foreach ($this->nodes as $node) {
$href = $node->getAttribute('href');
$title = $node->getAttribute('title');
$str .= '<li><a href="' . $this->base() . ($href == '/' ? '' : '?' . self::fragment . '=' .html_entity_decode($href)) . '"'
. ($this->page == $href ? ' class="selected"' : '') . '>'
. $title . '</a></li>';
}
echo($str);
}
function content() {
$str = '';
// Prepares the content with support for a simple "More..." link
if (isset($this->node)) {
foreach ($this->node->childNodes as $node) {
if (!isset($this->parameters['more']) && $node->nodeType == XML_COMMENT_NODE && $node->nodeValue == ' page break ') {
$str .= '<p><a href="' . $this->page .
(count($this->parameters) == 0 ? '?' : '&') . 'more=true' . '">More...</a></p>';
break;
} else {
$str .= $this->doc->saveXML($node);
}
}
} else {
$str .= '<p>Page not found.</p>';
}
echo(preg_replace_callback('/href="(\/[^"]+|\/)"/', array(get_class($this), 'callback'), $str));
}
private function callback($m) {
return 'href="' . ($m[1] == '/' ? $this->base() : ($this->base() . '?' . self::fragment . '=' .$m[1])) . '"';
}
}
$crawling = new Crawling();
You won't be able to make server-side decisions using the fragment-identifier (i.e., everything to the right of the # character). This is because browsers don't send fragment-identifiers to the server. If you're going to want to make server-side decisions, you'll need to use some JavaScript assistance (including AJAX) to communicate what the current fragment-identifier is.