php, as we have already established, was created to be a backend language for the web. it shouldn't be a surprise, then, that it has built-in functionality that makes communicating between sites and pages relatively simple. there is a set of special built-in arrays that allow a php program to get information from the user.
before we dive into the specifics, though, we need to talk about how information is communicated on the web.
first, a browser like safari, edge or chrome sends a request to a server. there are several possibilities for these requests but there are only two that should ever be used -- get and post. these differ in what kind of information can be sent to the server and what the address looks like that's used to send it.
the vast majority of requests on the web are get and most of those send only one piece of information -- the name of the page. let's take a look at a simple url...
https://php.org/demo/hello.php
web addresses don't get any simpler than this so let's break it down into its pieces.
https is the protocol. we see it so often, we forget how significant it is or that there are so many other options. http is an acronym, hypertext transfer protocol and the s is for secure. you'll sometimes see http without the s but that has mostly faded into the past as people expect secure communications. for decades, it was expensive to provide the secure version because of subscription costs and computing overhead. it is now available free and computers are fast enough it rarely makes enough difference to matter in the real world unless you have scaled incredibly large. at that point, users are expecting security and companies still provide it.
the protocol tells us how the communication is supposed to happen and provides a default port to communicate with the server on. a server has many ports. you can think of them as doors information can go in and out through. each has a number. if you try to communicate with a server on a port it's not listening on, it won't respond. a server can choose to use any port but there are defaults where it's expected they will be listening for certain types of communications -- like a request for a secure web connection like https. the default port for https is 443. when you request a page, you can specify the port using : but, if you don't, it makes the assumption it's the default and uses 443.
so that address could also look like...
https://php.org:443/demo/hello.php
and it would produce exactly the same result. the 443 is implied. there are other protocols that have defaults, too. http defaults to 80, ssh to 22 and ftp to 21. mail sends to 25 (or 587 if it's secure) on smtpand 143 (993 if secure) on imap. these are just a few examples and port numbers range from 0 to 65535 on standard servers.
the :// has some technical meaning but it really just separates the protocol from the server's web address.
the web address can be either a name or an ip address. if it's a name, your computer sends a request to a dns (dynamic name system) server to translate it into an ip address. that address usually looks like 0.0.0.0 (ipv4) or 0000:0000:0000:0000:0000:0000:0000:0000 (ipv6). in the case of ipv4, it's four decimal numbers separated by . between 0 and 255. for ipv6, it's eight hexadecimal numbers separated by : between 0000 and ffff. what these numbers mean is interesting but unrelated to the result on the server so i encourage you to dive into it if you are curious.
once your computer knows where to send the request, either because you've specified the ip address or it's looked the name up from a dns server, it opens a port of its own to receive any response and tries to send the request to the server on the port you specified (or the one it assumed from the protocol you specified). that request has to include several things. the ones we care about for the moment are the ip address of your computer and the port it's temporarily opened -- because the server has to know where to send the answer to your request -- and the name of the page. that's not all it sends but it's all we need to be concerned with.
the web server (like apache or nginx) remembers the ip address and port for you so you don't have to deal with that in your program. you can include that information but, if you don't interact with it, the web server takes care of that part in the background on its own.
the name or address you used for the server tells it where to find the site. for example, a server might have more than one site -- php.org, javascript.org and html.org might be on different physical machines or all run on the same one. if they ran on the same one, the name would tell the server which one you are looking for.
once it knows which site to run, the rest is like a command. in this case...
tell the site on port 443 of "php.org" to send back "/demo/hello.php".
if a server that identifies itself as php.org is running on port 443 of that machine, it tries to run /demo/hello.php. assuming it has php enabled, it will, by default, take the file stored in your web directory's demo subdirectory called hello.php and run it through the php interpreter. it will then send the output back to the ip address and port the server has remembered from the request.
if hello.php doesn't exist or something goes wrong with the php execution, you will see an error instead. if all goes well, what comes back is whatever hello.php generated. it could be text (like an html document) or a binary file like a graphic or zip.
what we've just described is a get request. it's called that because it is normally used to get information from a server. there are exceptions to this where the name can be misleading but those are rare.
i should probably mention here that the separation of request types has a lot to do with the fact that the web is decades old and these things were built a long time ago. changing them is fraught with controversy and arguments, many of them very passionate and heated. of course, these request types should long ago have been condensed into a single type that does everything but we have to deal with how it works rather than how it should work.
the simplest form of get request is just the name of the page. that request can be as simple as / (get the default page of a site) or have many slashes and long names in it. regardless, it's just a string of text sent to the server and passed along to your program. there are many things you can do with that string by just treating it as a variable but php has a few special ones that are useful.
if the address contains ?, what comes after the question-mark is parsed into an array of variables you can use as if you had manually separated them.
https://php.org:443/demo/hello.php?fruit=apple&vegetable=potato&animal=aardvark
as you might expect, does mean...
tell the site on port 443 of "php.org" to send back "/demo/hello.php?fruit=apple&vegetable=potato&animal=aardvark".
but, under normal circumstances, that means running hello.php and passing the rest as a special array called $_GET that looks like this...
$_GET = ["fruit" => "apple", "vegetable" => "potato", "animal" => "aardvark"]
before we go on, it's important to be aware of one of the big limitations of get requests -- length. while there's technically no maximum for how long a request string can be, every browser and web server does limit it. the biggest issue with that, though, is that, as the standard is non-specific about where that limit should be, they've each chosen one. but they haven't all chosen the same one. some people say 2048 characters is the maximum that's reasonable to expect from the web in general. that includes the whole address, not just the part after the ?. it's also good to know that some characters count as more than one. a chinese character, for example, is available as unicode but not a standard latin letter, number or punctuation. that means it gets translated into a special number, which is more than one character long. the server still understands it as the chinese character but it takes more than one character on the request string to send. why is that important? character length adds up quickly.
there is one other, perhaps more relevant, limitation, however. security.
imagine you are logging into a site. you type your email and password and hit login and the page has to send that information to the program that checks whether it's correct. if get is used to send the information, the request string might look like this...
https://php.org/login.php?email=lavender%40php.org&password=122333444455555
you might be curious about the %40. remember when i mentioned some characters taking up more than one space. @ is a special character so, instead of sending it as it is, it converts it to a number. % means the next thing on the string will be one of those numbers.
but, character conversion aside, you can see the huge issue with sending information this way. the password is sitting right there in the address bar of the browser -- among other places along the way. even if the transmission of information to and from the server is secure, the address is not.
get is extremely useful for requesting a specific page. there are times when passing information after ? can also be functional. for example, a search string...
https://php.org/search.php?s=loops
the search string will be short, plain text and has no need to be secure. it also means it can be bookmarked or referenced in browser history, things that are useful for search requests. this is extremely common -- google uses ?q=... for its searches.
if you request...
hello.php?name=yolanda
and hello.php looks like this...
print_r("hi there, " . $_GET["name") . "!";
it will produce hi there, yolanda!. you can treat $_GET like any other array and even modify its contents. it's special in that it is provided by the web server but it doesn't behave any differently once your program accesses it. that is the case for all the special arrays in php.
if you need to communicate something more than a simple string, however -- or if you don't want that string to appear in the address bar of the user's browser -- you can use the other method we talked about -- post.
there are several options for how to send a post request. the simplest is an html form like this...
<form method="post" action="who.php">
<input type="text" name="name" placeholder="jane doe" />
<input type="text" name="email" placeholder="[email protected]" />
<input type="submit" value="go" />
</form>
while this is not how i would recommend transmitting data back and forth in the real world, it is a great way to learn the basics of post requests. this is also the first time we've given a real html example. if you haven't learned at least enough html to understand this block of code, this might be a good time to take a look at html. while you definitely don't need to know html to do the php side of things, it will make it easier to learn about how php interacts with the browser.
if you take the details from a previous example and put "jasmine park" and "[email protected]" in this form and submit it to who.php looking like this...
print_r("welcome, " . $_POST["name"] . "! can i email you at " . $_POST["email"] . "?");
returns welcome, jasmine park! can i email you at [email protected]?. the browser will still only show who.php as the address.
how you create the get or post request isn't important to the server, only the data that arrives. you can do it using an html form, a javascript program, on the command-line or using any other language.
curl -d "name=jasmine%20park&email=jasmine.park%40php.org" https://php.org/who.php
is the command-line equivalent, for example, assuming the server is php.org. this sends the same post request as the form we just used. (this only works if you have curl installed on your computer just like an html form only works if you have a browser installed.)
if we take that same form and add a file input...
<form method="post" action="who.php" enctype="multipart/form-data">
<input type="text" name="name" placeholder="jane doe" />
<input type="text" name="email" placeholder="[email protected]" />
<input type="file" name="photo" />
<input type="submit" value="go" />
</form>
note that we have to change the encoding type to submit a file.
we can submit it to who.php containing...
isset($_FILES["photo"]) && $_FILES["photo"]["error"] === UPLOAD_ERR_OK && move_uploaded_file($_FILES["photo"]["tmp_name"], __DIR__ . "/" . str_replace(" ", "_", $_POST["name"]) . ".jpg");
we've already seen all these pieces before. $_FILES is a built-in array just like $_POST.
first, we check to make sure the variable $_FILES["photo"] actually has some content. if not, the rest of the command doesn't run.
the next piece is to check what the error state is. UPLOAD_ERR_OK is a special constant meaning the upload was successful. if the error state of the file is identical to this special constant, we can continue to the next piece of the command.
move_uploaded_file is a built-in php function. it takes the temporary name of the uploaded file and the destination name. every uploaded file has a value tmp_name automatically stored in its array. we don't want to have spaces in our filenames so we use the str_replace function we've already talked about several times to change spaces to underscores.
we can use any name we like for our uploaded file but here we just put it in the same directory as the php file (the built-in constant __DIR__) and add .jpg to the end. we'll talk more about how to deal with files on the web server later.
a better way of doing this inside a function looks like this...
function processUploadedFile($id)
{
if (!isset($_FILES[$id]) || !$_FILES[$id]["error"] === UPLOAD_ERR_OK) {
return false;
}
$tempFilename = $_FILES[$id]["tmp_name"];
$name = str_replace(" ", "_", $_POST["name"]);
$extension = pathinfo($tempFilename, PATHINFO_EXTENSION);
$newFilename = __DIR__ . "/" . $name . "." . $extension;
if (!move_uploaded_file($tempFilename, $newFilename)) {
return false;
}
return $newFilename;
}
processUploadedFile("photo") ? print_r("successfully uploaded file as " . $newFilename) : print_r("upload failed");
first, we do the same checks. if either the file "photo" is not uploaded (meaning the value is false) or the error is not UPLOAD_ERR_OK, we return false and the function ends.
if we haven't stopped, that means those two conditions must both be what we are looking for so we can continue on. we get the temporary filename. we replace spaces with underscores. we get the original extension of the temporary file using pathinfo and the built-in constant PATHINFO_EXTENSION.
then, instead of just moving the file, we check whether that move is successful. if it fails, we return false and end the function. otherwise, we return the new filename.
when we call processUploadFile, it either returns the new filename (if it succeeds) or false (if it fails). so we print a success message including the location of the file or an error. there is nothing new in this block of code so it should be easy to follow at this point.