I'm running HHVM 3.2.0 and trying to get access to GET and POST request parameters. The problem is, HHVM doesn't support access to PHP superglobals ($_GET, $_POST, $_SERVER, etc).
The only other way I know of getting access to request parameters in PHP is via the filter_input function, but is that really best practice (if I'm just using the raw filter)? It seems as though HHVM should support something cleaner than that. (What about Hack?)
HHVM absolutely supports superglobals in PHP code -- they're a really key part of PHP! The docs page you've linked to is simply wrong, and I've filed a bug to get it fixed.
In strict mode Hack code, superglobals are not supported; this cookbook example shows how you can access them via partial mode.
Seems like they added HH\global_get() to get global variables.
https://docs.hhvm.com/hack/reference/function/HH.global_get/
To put everything together
use namespace \Facebook\TypeSpec;
// get $_GET using global_get
function global_get_get(): darray<arraykey, mixed> {
$spec = TypeSpec\darray(
TypeSpec\arraykey(),
TypeSpec\mixed(),
);
return $spec->assertType(\HH\global_get("_GET"));
}
Related
I have a central PHP script I use for handling many requests from my page, using XMLHttpRequest() calls from JavaScript, using the GET method. My server PHP is currently 5.6, and yes, I'm avoiding synchronous calls.
It all works well, however there are cases where I'd prefer NOT to have the request remain in browser history, or even be displayed in the URL. So based on the MDN reference on this call, I thought I could simply switch to the POST method, keeping my existing requests (such as "http://myscript.php?cmd=dothis&data=somedata"). then all I'd have to do is add some code to my PHP script, so I could gather the passed data either way...
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
if(isset($_GET['cmd'])) $cmd = $_GET['cmd'];
if(isset($_GET['data'])) $data = $_GET['data'];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if(isset($_POST['cmd'])) $cmd = $_POST['cmd'];
if(isset($_POST['data'])) $data = $_POST['data'];
}
Well obviously i was dead wrong. What I found was...
Neither of the variables shown in this example are seen by the script within the $_POST array, when I switch to the POST method.
Switching from the $_POST array to the $_REQUEST array works fine (eg: "if(isset($_REQUEST['cmd'])) $cmd = $_REQUEST['cmd']);" ), BUT....
Just the act of issuing my XMLHttpRequest() calls with the POST method, results in errors like this in my log:
PHP Deprecated: Automatically populating $HTTP_RAW_POST_DATA is
deprecated and will be removed in a future version. To avoid this
warning set 'always_populate_raw_post_data' to '-1' in php.ini and use
the php://input stream instead. in Unknown on line 0
So obviously This is a dead end. Doing my best to research what is going on here, in the PHP manual reference to POST I read this right on top...
$_POST $HTTP_POST_VARS [deprecated]
So if I'm understanding this right, the reason I can only obtain the POST variables using the $_REQUEST array is because my requests are still formatted as if I were still using GET, which (apparently?) is a deprecated method. Therefore, "coaxing" it to work is just moving the problem to the future.
Incidentally, I can see by calling the phpinfo.php on my server that despite the ERROR I see in my logs, "always_populate_raw_post_data" is indeed already set to "-1". So all the "solutions" I've found recommending I "JUST" make this setting in my PHP.INI file do not help.
And even if it DID "hide" the error, doing so seems irrelevant to me. Am I wrong in saying that even if I simply gather my passed PHP vars from the $_REQUEST array when using the POST method, AND figure out a way to suppressing the "deprecated" warnings in my LOG, the whole scheme would still fall apart (and make my POST requests fail), the day I finally migrate to PHP 7.x.?
I apologize for asking here, but I have really tried to search every reference I could find for both doing XMLHttpRequests using POST method, AND the deprecated error messages I get in my logs. There is so much obsolete info out there, I can't find any clear discussion on how to PROPERLY alter or re-format my XMLHttpRequests so that I can use the POST method. In fact, I can't even positively determine whether doing so will be possible beyond PHP.5.6. Any help will be very much appreciated.
PHP made a mistake of naming $_GET and $_POST after the default place that a web browser will put data in an HTML form where the method attribute is set to GET or POST.
$_GET gets data from the query string, even if the request method was POST.
The request body is determined by the argument you pass to send. Data you put in the query string remains in the query string.
const url = 'http://myscript.php'
const form_data = new FormData();
form_data.append("cmd", "dothis");
form_data.append("data", "somedata");
cost xhr = new XMLHttpRequest;
xhr.open("POST", url);
xhr.addEventListener('load', function () { console.log(this.response); });
xhr.send(form_data);
Full disclosure: I'm not a PHP programmer, rather a Javascript/Node programmer, but I'm trying to help a friend fix a fatal PHP error on their site.
To wit,
Fatal error: Call to undefined function import_request_variables()
I've looked it up and import_request_variables() is deprecated.
The relevant piece of code is this -- I noticed that the developer seems to have tried out the more modern form (?) and abandoned it.
import_request_variables("pgc", "re_");
//extract($_GET, EXTR_PREFIX_ALL, "pgc");
//extract($_POST, EXTR_PREFIX_ALL, "pgc");
//extract($_GET, EXTR_PREFIX_ALL, "re_");
//extract($_POST, EXTR_PREFIX_ALL, "re_");
I found a solution on Stack Overflow here Php import_request_variable stopped working, that suggests using that same extract method
extract($_GET, EXTR_PREFIX_ALL, 'p');
extract($_POST, EXTR_PREFIX_ALL, 'p');
Is this the correct method to follow? I've read in other posts (e.g. here) that this could lead to security errors, as does the PHP documentation here
Warning
Do not use extract() on untrusted data, like user input (e.g. $_GET, $_FILES).
and that it's best to import the variables specifically, but I'm not sure that I'm adept enough at PHP to go through all the code and figure out where each variable is being used...
What's the best way to solve this issue swiftly and securely?
Thanks for any help!
EDIT:
This is the code where the variables are used, for what it's worth
if ($re_sub && $re_sec) { $content="./$re_sec/$re_sub.php";}
else if ($re_sec) { $content="./$re_sec/index.php";}
else { $content="./home.php";}
Wow. import_request_variables went away in PHP5, that was a LONG time ago... hope you are upgrading to 7!
Anyway, it seems that you are basically trying to form POST and the content of the post determine the URL the user is sent to. Since you can't trust user input (or shouldn't anyway) you check what is sent in the $_POST array against a whitelist. Depending on how many sections and sub-sections you have, that whitelist can be hard coded, kept in a separate include file, stored in a database, etc.
Given a structure like
home
sec1
sec1sub1
sec1sub2
sec1sub3
sec2
sec2sub1
sec2sub2
sec2sub3
sec3
sec3sub1
sec3sub2
sec3sub3
You can do something like loop through your whitelist and see if a matching POST variable was sent, if so add it to the URL.
$url="/";
$whitelist=array();
$whitelist['cars']=array("compact","sedan","sportscar");
$whitelist['trucks']=array("diesel","4x4");
$whitelist['suvs']=array("crossovers","domestic","import");
foreach($whitelist as $k=>$v){
if(isset($_POST[$k])){
$url=$url."/".$k;
foreach($v as $subv){
if(isset($_POST[$subv])){
$url=$url."/".$subv;
}
}
}
}
header("location :".$url);
I have a very old client who is now having issues with security because of the MYSQL Injection. This client does not have enough money to change his PHP database functions to PDO or MYSQLI. Nevertheless, he suggested that he wants a function that prevents mysql injuction. He is fully aware that the function is not perfect. But, he does not have any other temporary way right now. the function that I wrote for him is called safe();. Here comes my question. How can I apply the function to all POSTs and REQUESTs in his site. His site has many files, it will take hours to change. is there anything that I can add in the Header of every file that applies my function to all POSTs and REQUESTs variables?
something that maybe looks like this :
$_POST[*] = safe($_POST[*]);
Of course, the above code does not work. but I hope you get the idea.
You can use array_map, but I doubt it'll be perfect solution:
$final = array_map( "mysql_real_escape_string", $_POST );
In the end $_POST and $_GET are just arrays.
You could do a foreach like
foreach ($_POST as $key => $value) {
safe($value);
}
if they have old php servers etc. So if you have a general file that is included over the whole website and the "normal" functions aren't an option, this could be the back-up plan.
You are describing the infamous Magic Quotes, which are still available if the server is older than PHP/5.4.0 (which I presume is the case).
Please note that they affect all POST data, including that which is not going to be injected in a SQL query.
If you prefer your safe() function, you can simply write a simple script that makes the change and call it via auto_prepend_file.
Possible duplicate of https://stackoverflow.com/questions/15664021/php-escaping-vars-posted-through-var-and-got-by-postvari-with-a-meth
As I was told, there's no universal method, but you can give it a try through foreaching the $_POST array
I'm using Kohana 3.2, and I want to be able to call another script (unrelated to Kohana, outside of its 'jurisdiction') that returns a application/json response.
When I tried using:
$response = json_decode(Request::factory('/scripts/index.php?id=json')->execute()->body());
It errors out saying there's no route to scripts/index.php. So I tried using Request_Client_External
Request_Client_External::factory()->execute(Request::factory('/scripts/index.php?page=s'))->body();
Gives me Request_Exception [ 0 ]: Error fetching remote /scripts/index.php?page=s [ status 0 ] Could not resolve host: scripts; Host not found. It appears it need a full flagged URL using http/https, but how to avoid the overhead of it doing a real external request?
Doing a
Request::factory(url::site('/scripts/index.php?page=s', 'http'))->execute()
works but is it considered "external"?
The short answer to your question is that the only way to use Request::factory()->execute() to achieve that is to use pass it the full url (with whatever "overhead" that entails, which shouldn't be too much: your server's probably quite good at talking to itself).
Otherwise, ideally you'd put the functionality of scripts into a library and call that from Kohana. However it sounds like that's not an option for you. If you have to leave /scripts/index.php untouched and insist on an 'internal' request, you could use PHP's output buffering, as illustrated below. But there are a bunch of caveats so I wouldn't recommend it: the best way is passing a full url.
// Go one level deeper into output buffering
ob_start();
// Mimic your query string ?id=json (see first caveat below)
$_GET = $_REQUEST = array('id' => 'json');
// Get rid of $_POST and $_FILES
$_POST = $_FILES = array();
// Read the file's contents as $json
include('/scripts/index.php');
$json = ob_get_clean();
$response = json_decode($json);
Some caveats.
Firstly, the code changes $_GLOBALS. You probably don't use these in your Kohana code (you use $this->request->get() like a good HMVCer, right?). But in case you do, you should 'remember' and then restore the values, putting $old_globals = $GLOBALS; etc. before the above code, and $GLOBALS = $old_globals; after.
Sessions: if your /scripts/index.php uses `session_start() this will cause a warning if you've already started a session at this point in Kohana.
Note that all variables set in scripts/index.php will remain set in the context you're in. If you want to avoid possible conflicts with that context, you'd start a new context, i.e. wrap the above into its own function.
Finally, you'd also need to make sure that /scripts/index.php doesn't do anything like Kohana::base_url = 'something_else', or touch any other static attributes, or do something catastrophic using this.
i'm stuck with using $_GET variables with CodeIgniter, anyone can help me please?
CodeIgniter comes with three helper
functions that let you fetch POST,
COOKIE or SERVER items. The main
advantage of using the provided
functions rather than fetching an item
directly ($_POST['something']) is that
the functions will check to see if the
item is set and return false (boolean)
if not. This lets you conveniently use
data without having to test whether an
item exists first. In other words,
normally you might do something like
this:
if (!isset($_GET['something'])){
$something = FALSE;
} else {
$something = $_GET['something'];
}
With CodeIgniter's built in functions you can
simply do this:
$something = $this->input->get('something');
Taken from here.
$this->input->get() or $this->input->get_post()
use Input::get():
echo $this->input->get('your_field');
There's no reason that you would be able to use $this->input->get() and not $_GET.
You may be running an older version (less than 2.0.1) that does not have real $_GET "support". Old versions intentionally unset the $_GET array, assuming because it made things "difficult" for the developers. There is a query strings setting in version 1.7.2 that is very confusing and does not do what you'd expect. Newer versions support $_GET as expected.
Please see here for more information if this is the case:
CodeIgniter Enabling Query Strings
I think you must enable 'enable_query_strings = true' first