May 7, 2013

How exactly is PHP creating superglobal $_POST, $_GET, $_COOKIE and $_REQUEST?

Furicane’s Questions:

I’m sorry for confusing title of the question, I’ll try to clarify what the issue is.

I’m doing some work with Mongrel2 server and I’m writing a PHP handler that has access to raw HTTP request data. Because I have PHP behind Mongrel2, there is no automatic creation of $_POST, $_GET, $_COOKIE and $_REQUEST variables.

The question is – is there a way that I can send the raw HTTP request to a PHP function (or anything) that will produce the superglobal variables that are usually available when using Apache + PHP?

Note: I could parse the HTTP request manually and create those variables myself, but I wasn’t able to find any documentation on how exactly PHP does this HTTP parsing and importing into superglobals. If possible, I’d like to automate this process of superglobal creation without having to parse HTTP requests myself.

Thank you for any input.

Creating these variables is handled deep within the guts of PHP, in main/php_variables.c, in the php_auto_globals_create_get() and similar functions. From PHP 5.4.3:

static zend_bool php_auto_globals_create_get(const char *name, uint name_len TSRMLS_DC)
{
        zval *vars;

        if (PG(variables_order) && (strchr(PG(variables_order),'G') || strchr(PG(variables_order),'g'))) {
                sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
                vars = PG(http_globals)[TRACK_VARS_GET];
        } else {
                ALLOC_ZVAL(vars);
                array_init(vars);
                INIT_PZVAL(vars);
                if (PG(http_globals)[TRACK_VARS_GET]) {
                        zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
                }
                PG(http_globals)[TRACK_VARS_GET] = vars;
        }

        zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
        Z_ADDREF_P(vars);

        return 0; /* don't rearm */
}

This ends up calling directly into the SAPI (e.g, Apache module / CGI / FastCGI / whatever) to fetch variables. I don’t think there’s any way you can alter the way this works if you’re in a weird environment where GET/POST/etc variables aren’t where PHP expects them to be.

I am trying to contribute to this question with the knowledge I know.

Sending a HTTP Request with such headers can duplicate POST variable

POST /somepage.php HTTP/1.1
Host: www.domain.com
User-Agent: Mozilla/12.0
Content-Length: 31
Content-Type: application/x-www-form-urlencoded

parameter=value&testcode=value1

Also you might want to check the HttpRequest libray of PHP. [Start here]. For POST data you can override the previous POST content using HttpRequest::setPostFields() and set your own data for it.

HttpRequest::setPostFields(array(
    "parameter" => "value"
));
March 18, 2012

Retrieving Image from MySQL with PHP

Question by Dev Newb

I understand the debate over whether to store images in the database but I’m stuck with this design for now. I also know that this topic has been covered a thousand times in terms of pulling the MySQL BLOB into a separate php file for display purposes. My question is a little more narrow and I haven’t seen it anywhere.

I am looping image results from my database into an HTML table that shows the file description and upload date. All I want is the file description hyperlinked so when my users click on it the actual image is displayed. I have this working fine in another script where they choose the image from a dropdown and it POSTS the information to another script. For some reason I am wrapped around the axle on how to display the image from a simple hyperlink. I am trying to do this but it displays all the BLOB data on the page. Can someone point me in the right direction on this one?

while ($row = mysql_fetch_array($answer1)) {
    echo '<tr>';
    echo "<td><input name='checkbox[]' type='checkbox' id='checkbox[]' value='$row[imageven_id]'></td>";
    echo "<td><a href='$row[file_data]')'>$row[upload_name]</a></td>";
    echo "<td>$row[image_category]</td>";
    echo "<td>$row[upload_date]</td>";
    echo '</tr>';
}

Answer by Starx

Storing raw blob data is very complicated if you don’t have image type stored somewhere. I hope you have either fixed the type of image the system accepts or have stored the image type somewhere in the table too.

Any ways, when you showing images using blob data in a browser, you need to know the image type. Create a separate page to show images only. For example create showimage.php. On this page write the following code

$id= abs($_GET['id']);
$query = mysql_query("SELECT file_data FROM imagetable WHERE id='$id'");
$data=mysql_fetch_array($query);

header('Content-type: image/jpg'); //This is where we need to know the image type
echo $data['file_data'];

Now, you can link to this page to show the image, in this way

echo "<a href='showimage.php?id=".$row['id']."'>".$row['upload_name']."</a>";
March 5, 2012

Getting the previous page GET parameters in PHP

Question by Alex

I have a range of similar pages that have a URL along the lines of www.mydomain.com/group?id=1.

From each of these pages there is a form that posts it’s values to the server. I need to work out what the id of the group was when the form is posted. I’m aware of being able to use $_SERVER['HTTP_REFERER'] and then maybe I could use a regex to get the id. However, I wondered if there was anything in PHP that would allow you to get the previous $_GET variables?

Alternatively, do people think it is a much better idea to store the current group id as a session variable?

Answer by Starx

Yes, Session is the way to go to . Store them and get the groups on every other page, using session . This is a proper way.


Despite, it is also possible to make $_GET available for every page. Using two ways (AFAIK).

  1. Create the exact same URL String with the parameters and send them along, as you are redirecting from page to page.

    • Or use functions like parse_url() to get only the query string and pass them along
  2. Use Session to back up the $_GET and reassign it to $_GET on every page. Put the below snippet or every page you redirect to.

    if(isset($_SESSION['GET_BACKUP']) { //Check if there was a backup before
         $_GET = $_SESSION['GET_BACKUP'];  //if yes use it
    }
    
    if(isset($_GET) && count($_GET)) { //if not and GET value is sent
         $_SESSION['GET_BACKUP'] = $_GET; //backup it
    }
    // Now use the get as you used to via $_GET
    

    Following this way, you will not get an attached data in the URL, which might be undesirable.


Update:

In case you are going with the second option, you should remember that the solution I provided is an demo and will not fit for more than one $_GET group. For multiple pages and storing their SESSIONS, you have to define separate keys to identify the backup. Kinda like

$_SESSION['mypage.php']['GET_BACKUP'] = $_GET;
March 3, 2012

Folder with Get value

Question by Smile Applications

Could someone with more experience than me explain how it works the link (for example):

http://www.facebook.com/zuck  

I think it’s the same thing of this

http://www.facebook.com/profile.php?id=4

I imagine that “zuck” is a GET type string but I don’t understand how I can do the same thing.

Thank You very much

Answer by ilya iz

.htaccess file:

RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /profile.php?id=$1 [L]

Answer by Starx

Actually, i am not sure about it, but by the way I see it, facebook probably uses both ways to get to a profile

I quick .htaccess to make sure all the request arrive on same page.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /profile.php?input=$1 [L]

Now, in the profile.php, it should do a simple check like

$input = $_GET['input'];

if(is_string($input)) {
 // then retrieve profile id, based on the string
}
//now either way you have an unique identifier at last
//
//
// use your logic further more
December 2, 2011

mysql_connect() using http protocol

Question by Saheelram

I am trying to connect to a MySql server (not localhost) from my computer using the code below. It is giving this error:

Warning: mysql_connect() [function.mysql-connect]: [2002] Connection refused (trying to connect via tcp://10.6.3.6:3306) in on line 7

I wonder if we can use the http protocol to connect instead of tcp that is being used by default? I searched quite a bit on how to change the protocol, but most of the answers were describing how to connect to localhost, and not much about how to connect to another server. Please help.

PS: I am able to connect to the server by going to http://10.6.3.6/phpmyadmin/…). So I am sure the server is up.

My Code

<?php

$db_hostname = '10.6.3.6';
$db_database = 'db_user11';
$db_username = 'db_user11';
$db_password = '########';

$db_server = mysql_connect($db_hostname, $db_username, $db_password);
if (!$db_server) die("Unable to connect to MySQL: " . mysql_error());
mysql_select_db($db_database, $db_server)
or die("Unable to select database: " . mysql_error());

?>

Answer by deceze

First of all, HTTP is layered on top of TCP/IP.
In order to connect to something via HTTP, it needs to run an HTTP server. MySQL does not run an HTTP server and there’s no current/realistic/supported way to tunnel an SQL connection through HTTP. Even if there was, HTTP is not exactly the best protocol for this.

In short: no. You’re trying to solve the wrong problem. You need to configure your MySQL server to allow connections from other machines over the network, give the user you’re trying to connect with appropriate permissions to connect from other machines and make sure the MySQL server is reachable from other machines.

Answer by Starx

Just because the phpmyadmin is hosted on that server, does not neccesarily mean that the database server is in the same IP address. Please ask the domain administrator to give you the details of database server.

...

Please fill the form - I will response as fast as I can!