Downloading a file, but sending a POST to initiate it - php

I have a button on a page with an onClick I dynamically set via Jquery.
That button starts the download of a file.
I'm using mod_rewrite to turn http://somesite.com/blah1/blah2/blah3/blah4 into index.php&q=$1
Then I access q, split on / and I get any user requested path as an array.
Works great except I can't send an encoded path as one of my variables:
<?php
$html = '<button onClick="window.location = \'' . SITE_URL . 'downloadLog/' . urlencode($some_path) . ">Click me</button>';
Looked into AllowEncodedSlashes On for Apache.
Tried it.. Always end up with either %2Fvar%2Fadm%2Fmessages even after urldecode() or rawurldecode(), or apache attempting to go somewhere that doesn't exist even with my mod_rewrite on / converting these to q=.
So.. the new idea is I'll just create a form onClick and submit that. POST will have no problem with my urlencoded path as a parameter.
Since this is destined to go in an onClick, and my onClick= uses double quotes (this is part of another huge piece of code I can't easily change right now) I'm having trouble getting the escaping correct I think. Broke down and didn't use quotes around my id/name as a last resort, still no dice.
So here is what I came up with. This does not error in firebug, but I don't see a POST happening either.
function get_inline_post($a) {
$output .= 'this_form = $(\'<form submit=' . SITE_URL . $a['submit'] . ' ></form>\').html(\'\')';
unset($a['submit']);
foreach ( $a as $key => $value ) {
$output .= '.append(\'<input id=' . $key . ' name=' . $key . ' type=hidden>\')';
}
$output .= ';';
foreach ($a as $key => $value ) {
$output .= '$(\'#' . $key . '\').val(\'' . rawurlencode($value) . '\');';
}
$output .= 'this_form.submit();';
return $output;
}
Which given the right variables ends up building this to go in my onClick:
<button class="ui-corner-all"
onClick="
this_form = $('<form submit=/downloadHostLog/messages></form>').html('').append('<input id=link_hcmdb_id name=link_hcmdb_id type=hidden >').append('<input id=added_path name=added_path type=hidden >');
$('#link_hcmdb_id').val('046345D4771C4D3FBD2EF33CBE038028');$('#added_path').val('var%2Fadm');this_form.submit();
"
title="Kill me now" type="button">
<span class="ui-icon ui-icon-copy"></span>
</button>
Remember,I'm trying to initiate a download here so answers with .post() are useless. Thank you.
Edit:
I'm open to using the original idea of just urlencoding it in the window.location script, but I've wasted all day on it already. Actually made a table and tried every variation of:
single urlencoding, double urlencoding encoding,Different levels of encoding going in versus coming out.
rawurlencode vs urlencode,
AllowEncodedSlashes On/Off
At this point I'm guessing that my combination of using mod_rewrite, splitting on / to generate the original query path as an array, and AllowEncodedSlashes just may not work together.
I'm also eliminating the fact that the buttons are sent to the user via ajax, and this button actually ends up in a jqgrid.
This is part of the reason I want to simply inline the onClick on generation instead of doing
$().click(function(){blah});
for every single result row as every row has 5 different parameters other than what I show here that are unique to every row for security purposes... so I end up calling the bind 50-500 times anyway which was painfully slow.
What I was doing previously was just generating a uid for each row, storing that in a session variable, and dereferencing it back when the user visited /downloadLog/UID. That worked as well, but I like to keep my session information under 4k for performance reasons and doing this took it to 16k easily.
Simply replacing / with | before encoding and changing it back after worked but I refused to resort to building in a bug like that.
EDIT: #dqhendricks My current mod_rewrite statement:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)? index.php?q=$1 [L,QSA]
The corresponding php that processes that:
foreach ( preg_split('/\//',$_GET['q']) as $key => $value)
{
$g[$key] = urldecode($value);
}
Given the above I tried AllowEncodedSlashes On and Off. Neither one allowed /blah/blah/%2F%var%2Fadmin/blah to be even directed into index.php. Got 404.

Don't quote me on this, but I believe frameworks like Zend just redirect everything to index.php (no GET request variables), then gets the request data from something like $_SERVER['ORIG_PATH_INFO']*. This gives you the request data prior to decoding the url. You can then split the request string, and decode each variable yourself.
*Unsure exactly, but something like this. Would have to look into Zend Framework's routing class to be sure.
EDIT
Dug up the code that gets the request uri from zend framework. Part of the Zend_Controller_Request_Http class, but you get the idea.
public function setRequestUri($requestUri = null)
{
if ($requestUri === null) {
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
$requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
} elseif (
// IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
isset($_SERVER['IIS_WasUrlRewritten'])
&& $_SERVER['IIS_WasUrlRewritten'] == '1'
&& isset($_SERVER['UNENCODED_URL'])
&& $_SERVER['UNENCODED_URL'] != ''
) {
$requestUri = $_SERVER['UNENCODED_URL'];
} elseif (isset($_SERVER['REQUEST_URI'])) {
$requestUri = $_SERVER['REQUEST_URI'];
// Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
$schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost();
if (strpos($requestUri, $schemeAndHttpHost) === 0) {
$requestUri = substr($requestUri, strlen($schemeAndHttpHost));
}
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
$requestUri = $_SERVER['ORIG_PATH_INFO'];
if (!empty($_SERVER['QUERY_STRING'])) {
$requestUri .= '?' . $_SERVER['QUERY_STRING'];
}
} else {
return $this;
}
} elseif (!is_string($requestUri)) {
return $this;
} else {
// Set GET items, if available
if (false !== ($pos = strpos($requestUri, '?'))) {
// Get key => value pairs and set $_GET
$query = substr($requestUri, $pos + 1);
parse_str($query, $vars);
$this->setQuery($vars);
}
}
$this->_requestUri = $requestUri;
return $this;
}

Related

Parsing closed brackets in URL and http_build_query with it inserts number in closed bracket

may not have explained this properly but here we go.
I have a URL that looks like http://www.test.co.uk/?page=2&area[]=thing&area[]=thing2
Multiple "area"s can be added or removed from the URL via links on the site. on each addition of n "area" I wanted to remove the "page" part of the URL. so it can be reset to page1. I used parse_url to take that bit out.
Then I built an http query so it could generate the URL properly without "page"
this resulted in "area%5B0%5D=" "area%5B1%5D=" instead of "area[]="
When I use urldecode, now it shows "area[0]=" and "area[1]="
I need it to be "[]" because when using a link to remove an area, it checks for the "[]=" - when it's [0] it doesn't recognise it. How do I keep it as "[]="?
See code below.
$currentURL = currentURL();
$parts = parse_url($currentURL);
parse_str($parts['query'], $query);
unset($query['page']);
$currenturlfinal = http_build_query($query);
urldecode($currenturlfinal);
$currentURL = "?" . urldecode($currenturlfinal);
This is what I've done so far - it fixes the visual part in the URL - however I don't think I've solved anything as I've realised that what represents 'area' and 'thing' is not recognised as $key or $val as a result of what I think is parsing or reencoding the url in accordance with the code below. So I still can't remove 'areas' using the links
$currentURL_with_QS2 = currentURL();
$parts = parse_url($currentURL_with_QS2);
parse_str($parts['query'], $query);
unset($query['page']);
$currenturlfinal = http_build_query($query);
$currenturlfinal = preg_replace('/%5B[0-9]+%5D/simU', '[]', $currenturlfinal);
urldecode($currenturlfinal);
$currentURL_with_QS = "?" . $currenturlfinal;
$numQueries = count(explode('&', $_SERVER['QUERY_STRING']));
$get = $_GET;
if (activeCat($val)) { // if this category is already set
$searchString = $key . '[]= ' . $val; // we build the query string to remove
I'm using Wordpress as well may I add - maybe there's a way to reset the pagination through Wordpress. of course even then - when I go to page 2 on any page it still changes the "[]" to "5b0%5d" etc....
EDIT: this is all part of a function that refers to $key (the area/category) and $val (name of area or category) which is echoed in the link itself
EDIT2: It works now!
I don't know why but I had to use the original code and make the adjustments I did before again and now it works exactly how I want it to! Yet I couldn't see any visible differences in both codes afterwards. Strange...
As far as I know, there is no built-in way to do this.
You could try with:
$currenturlfinal = http_build_query($query);
Where $query is querystring part w/o area parameters and then:
foreach ($areas as $area) {
$currenturlfinal .= '&area[]='.$area;
}
UPD:
you could try with:
$query = preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', $query);
just place it right after http_build_query call.

PHP Auto-correcting URLs

I dont wan't reinvent wheel, but i couldnt find any library that would do this perfectly.
In my script users can save URLs, i want when they give me list like:
google.com
www.msn.com
http://bing.com/
and so on...
I want to be able to save in database in "correct format".
Thing i do is I check is it there protocol, and if it's not present i add it and then validate URL against RegExp.
For PHP parse_url any URL that contains protocol is valid, so it didnt help a lot.
How guys you are doing this, do you have some idea you would like to share with me?
Edit:
I want to filter out invalid URLs from user input (list of URLs). And more important, to try auto correct URLs that are invalid (ex. doesn't contains protocol). Ones user enter list, it should be validated immediately (no time to open URLs to check those they really exist).
It would be great to extract parts from URL, like parse_url do, but problem with parse_url is, it doesn't work well with invalid URLs. I tried to parse URL with it, and for parts that are missing (and are required) to add default ones (ex. no protocol, add http). But parse_url for "google.com" wont return "google.com" as hostname but as path.
This looks like really common problem to me, but i could not find available solution on internet (found some libraries that will standardize URL, but they wont fix URL if it is invalid).
Is there some "smart" solution to this, or I should stick with my current:
Find first occurrence of :// and validate if it's text before is valid protocol, and add protocol if missing
Found next occurrence of / and validate is hostname is in valid format
For good measure validate once more via RegExp whole URL
I just have feeling I will reject some valid URLs with this, and for me is better to have false positive, that false negative.
I had the same problem with parse_url as OP, this is my quick and dirty solution to auto-correct urls(keep in mind that the code in no way are perfect or cover all cases):
Results:
http:/wwww.example.com/lorum.html => http://www.example.com/lorum.html
gopher:/ww.example.com => gopher://www.example.com
http:/www3.example.com/?q=asd&f=#asd =>http://www3.example.com/?q=asd&f=#asd
asd://.example.com/folder/folder/ =>http://example.com/folder/folder/
.example.com/ => http://example.com/
example.com =>http://example.com
subdomain.example.com => http://subdomain.example.com
function url_parser($url) {
// multiple /// messes up parse_url, replace 2+ with 2
$url = preg_replace('/(\/{2,})/','//',$url);
$parse_url = parse_url($url);
if(empty($parse_url["scheme"])) {
$parse_url["scheme"] = "http";
}
if(empty($parse_url["host"]) && !empty($parse_url["path"])) {
// Strip slash from the beginning of path
$parse_url["host"] = ltrim($parse_url["path"], '\/');
$parse_url["path"] = "";
}
$return_url = "";
// Check if scheme is correct
if(!in_array($parse_url["scheme"], array("http", "https", "gopher"))) {
$return_url .= 'http'.'://';
} else {
$return_url .= $parse_url["scheme"].'://';
}
// Check if the right amount of "www" is set.
$explode_host = explode(".", $parse_url["host"]);
// Remove empty entries
$explode_host = array_filter($explode_host);
// And reassign indexes
$explode_host = array_values($explode_host);
// Contains subdomain
if(count($explode_host) > 2) {
// Check if subdomain only contains the letter w(then not any other subdomain).
if(substr_count($explode_host[0], 'w') == strlen($explode_host[0])) {
// Replace with "www" to avoid "ww" or "wwww", etc.
$explode_host[0] = "www";
}
}
$return_url .= implode(".",$explode_host);
if(!empty($parse_url["port"])) {
$return_url .= ":".$parse_url["port"];
}
if(!empty($parse_url["path"])) {
$return_url .= $parse_url["path"];
}
if(!empty($parse_url["query"])) {
$return_url .= '?'.$parse_url["query"];
}
if(!empty($parse_url["fragment"])) {
$return_url .= '#'.$parse_url["fragment"];
}
return $return_url;
}
echo url_parser('http:/wwww.example.com/lorum.html'); // http://www.example.com/lorum.html
echo url_parser('gopher:/ww.example.com'); // gopher://www.example.com
echo url_parser('http:/www3.example.com/?q=asd&f=#asd'); // http://www3.example.com/?q=asd&f=#asd
echo url_parser('asd://.example.com/folder/folder/'); // http://example.com/folder/folder/
echo url_parser('.example.com/'); // http://example.com/
echo url_parser('example.com'); // http://example.com
echo url_parser('subdomain.example.com'); // http://subdomain.example.com
It's not 100% foolproof, but a 1 liner.
$URL = (((strpos($URL,'https://') === false) && (strpos($URL,'http://') === false))?'http://':'' ).$URL;
EDIT
There was apparently a problem with my initial version if the hostname contain http.
Thanks Trent

php get all url variables

I'm trying to make links to include the current _GET variables.
Example link: Page 2
The current url is: http://example.com/test.php?id=2&a=1
So if someone clicks on the link of page 2 it will take them to:
http://example.com/test.php?id=2&a=1&page=2
Currently if they click on the link it takes them to:
http://example.com/test.php?page=2
As you can see, I need a way to get the current _GET variables in the url and add them to the link. Advice?
The superglobal entry $_SERVER['QUERY_STRING'] has the query string in it. You could just append that to any further links.
update: The alternate response on this page using http_build_query is better because it lets you add new variables to the query string without worrying about extraneous ?s and such. But I'll leave this here because I wanted to mention that you can access the literal query string that's in the current address.
$new_query_string = http_build_query(array_merge($_GET,array('page' => 2)));
Make use of #extract($_GET). So you can access them directly as variables.
Try this may help you......
function get_all_get()
{
$output = "?";
$firstRun = true;
foreach($_GET as $key=>$val) {
if($key != $parameter) {
if(!$firstRun) {
$output .= "&";
} else {
$firstRun = false;
}
$output .= $key."=".$val;
}
}
return $output;
}
As for the question above how to include the name of php file as well in the url, using Your Common Sense's perfect method and adding a question mark worked for me:
echo "<a href='?".$url."'>link</a>"

Weird file_get_contents() options

We are currently performing searches on a Database and returning results in JSON format to use on a Google Maps. The file that we call is named getvenues.php and works great on the server. It accepts a number of parameters and returns the results based on the query.
We then have a separate file that checks to see if there's a JSON file on the server which contains the results, matches its age against a setting, and then returns the data either from the cache file, or builds a new cache file if it's too old.
Since there are several thousand possible search options, we only cache single searches (either on a County, Region or Type). The JavaScript always calls our search_cache_builder.php file. If there is more than one search parameter, the file simply gets the contents returned by getvenues.php and serves it up without any caching.
Everything works great except for one particular combination. If a search is run for venue_type=Castle / Fort and venue_name=Leeds Castle, the search_cache_builder.php returns an empty array, even though accessing getvenues.php directly returns the required data.
Here's a sample of the getvenues.php working with this data > http://dev.weddingvenues.com/lincweb/getvenues.php?type=Castle%20/%20Fort&venue_name=Leeds%20Castle
And here's what the search_cache_builder.php script returns with an identical search (the address we are sending to is correct) > http://www.weddingvenues.com/search_cache_builder.php?type=castle%20/%20fort&venue_name=Leeds%20Castle
Here's the code for the search_cache_builder.php file, which relates to this particular query:
$get_string = '?';
foreach($_GET as $key => $value)
{
if($get_string === '?')
{
$get_string .= $key . '=' . $value;
}
else
{
$get_string .= '&' . $key . '=' . $value;
}
}
//$get_string = str_replace(' ', '', $get_string);
// Otherwise, we need to serve up the page as is:
$file_url = GET_VEN_URL . $get_string;
echo file_get_contents($file_url);
Can anyone offer an explanation as to why the search_cache_builder.php file is returning an empty array?
You should urlencode() your parameter values.
In fact, while your getvenues.php receives parameters directly from a browser it behaves OK, 'cause they are correctly urlencoded.
I tried what follows in my computer towards your service and it works:
define ("GET_VEN_URL", "http://www.weddingvenues.com/getvenues.php");
$get_string = '?';
foreach($_GET as $key => $value)
{
if($get_string === '?')
{
$get_string .= $key . '=' . urlencode($value);
}
else
{
$get_string .= '&' . $key . '=' . urlencode($value);
}
}
$file_url = GET_VEN_URL . $get_string;
echo "<pre>";
echo $file_url;
echo "<pre>";
echo file_get_contents($file_url);
Because $get_string === '?' is ALWAYS false, change it to ==, ? is not a boolean.
I would not recommend using GET parameters, &,? as part of the file name.
Beside this, it will quickly hit into 5k (or 4k, can not recall) limit for a file name.
You can do a sort by $GET, md5 (or hash) the array to a random string.
As long you ensure the hashing mechanism is consistent, you can easily retrieve the cache file.
First try to urldecode values, then use http_build_query to generate your get_string, your problem must be the special chars in values (like /).
Edit:
If you change the order it works: http://www.weddingvenues.com/search_cache_builder.php?venue_name=Leeds%20Castle&type=castle%20/%20fort

Persistent HTTP GET variables in PHP

Let's say I have some code like this
if(isset($_GET['foo']))
//do something
if(isset($_GET['bar']))
//do something else
If a user is at example.com/?foo=abc and clicks on a link to set bar=xyz, I want to easily take them to example.com/?foo=abc&bar=xyz, rather than example.com/?bar=xyz.
I can think of a few very messy ways to do this, but I'm sure there's something cleaner that I don't know about and haven't been able to track down via Google.
Here's one way....
//get passed params
//(you might do some sanitizing at this point)
$params=$_GET;
//morph the params with new values
$params['bar']='xyz';
//build new query string
$query='';
$sep='?';
foreach($params as $name=>$value)
{
$query.=$sep.$name.'='.urlencode($value);
$sep='&';
}
If you are updating the query string you need ot make sure you don't do something like
$qs="a=1&b=2";
$href="$qs&b=4";
$href contains "a=1&b=2&b=4"
What you really want to do is overwrite the current key if you need to .
You can use a function like this. (disclaimer: Off the top of my head, maybe slightly bugged)
function getUpdateQS($key,$value)
{
foreach ($_GET as $k => $v)
{
if ($k != $key)
{
$qs .= "$k=".urlencode($v)."&"
}
else
{
$qs .= "$key=".urlencode($value)."&";
}
}
return $qs
}
View report
Just set the link that changes bar to xyz to also have foo=abc if foo is already set.
$link = ($_GET['foo'] == 'abc') ? 'foo=abc&bar=xyz' : 'bar=xyz';
?>
Click Me
You would have to render out the links with the proper URL querystring to make that happen. This is a design decision that you would need to make on your end depending on how your system is setup.
I have some sites that have this issue, and what I do is setup a querystring global variable that sets the current page data the top of the page request.
Then when I am rendering the page, if I need to make use of the current query string I do something like:
echo '<a href="myurl.php' . querystring . '&bar=foo';
It's not the cleanest, but it all depends on how your system works.
Save some code and use the built-in http_build_query. I use this wrapper in one of my projects:
function to_query_string($array) {
if(is_scalar($array)) $query = trim($array, '? \t\n\r\0\x0B'); // I could split on "&" and "=" do some urlencode-ing here
else $query = http_build_query($array);
return '?'.$query;
}
Also, though it isn't often used, you can have $_GET on the left-hand side of an assignment:
$_GET['overriden_or_new'] = 'new_value';
echo 'Yeah!';
Other than that, just do what Paul Dixon said.

Categories