تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Tracing HTTP Request Flow0:00

Throughout this course, we've spent a lot of time on how to use Valet, but not a ton of time on how Valet itself works. In this episode, that's going to change. So let's take a look at a request to a Valet site and walk through the dependencies it hits one by one. So first you type sitename.test. You hit enter. The browser makes a request. And now what? DNSmasq is one of the key dependencies that Valet installs and relies on.

DNSMasq Handles .test0:25

And now what? DNSmasq is one of the key dependencies that Valet installs and relies on. DNSmasq is a super-light DNS server, sort of how SQLite is a super-light SQL database. It's so small it's actually commonly included in smart-house gadgets and Android phones. Technically, DNSmasq is built to intercept local requests into cache or forward them along. But it also has a configuration system that's far more powerful than /etc/hosts, for example, and it makes it possible to intercept entire IP address ranges or TLDs, which is what we do with Valet. So DNSmasq, at its core, registers and captures all .test requests and sends them through

Nginx Receives Request0:54

what we do with Valet. So DNSmasq, at its core, registers and captures all .test requests and sends them through to our local nginx. And if we take a look at our DNSmasq configuration, we can actually see how it routes all requests for .test domains over to our local loopback, which is 127.0.0.1. So this is DNSmasq saying, capture everything sent to .test and send it over to our loopback address, which is what nginx is listening at. And now a tool called nginx has the request. Nginx is a server, sort of like Apache, but unlike Apache, it's meant to be used as more of a proxy than a traditional server, but we use it as a traditional server anyway.

Nginx is a server, sort of like Apache, but unlike Apache, it's meant to be used as more of a proxy than a traditional server, but we use it as a traditional server anyway. So some of the specifics of how we use it are going to make more sense when you know that it's more meant to be a load balancer and a proxy, even though it's also definitely a web server. So at this point, DNSmasq has captured the request and has said, oh, it's a .test domain, I will send it over to 127.0.1, where we have nginx listening. When we install Valet, we set up an nginx configuration that listens at the loopback IP address and passes all of those requests through to valetserver.php, which we'll take a look at in a second.

IP address and passes all of those requests through to valetserver.php, which we'll take a look at in a second. If we take a look at Valet's nginx configuration, we can see we're listening at the Valet loopback address, which in my case is 127.0.0.1. We're doing a little bit of trickiness I'll talk about later. And then everything else, all other requests are just being sent through to server.php. One more important note, nginx as a proxy uses fastcgi to pass its requests off to php. So if you ever see anything with fastcgi, what fastcgi is doing is proxying requests from nginx to php-fpm, and php-fpm stands for FastCGI Process Manager. So it's a specific implementation of php that is meant to be used with fastcgi and therefore

from nginx to php-fpm, and php-fpm stands for FastCGI Process Manager. So it's a specific implementation of php that is meant to be used with FastCGI and therefore as a proxy for nginx. So as you can see here, the most important thing is fastcgi_pass, which says when we're capturing all these things, where should we send them to? This is where php-fpm is actually listening, which is valet.sock. And if you've been using Valet for a while, you might be familiar with the fact that valet.sock used to cause us a lot of problems because people would have missing valet.sock or they'd have to delete their valet.sock file. What that sock file is, is a pointer on our machine that basically says, hey, nginx, send

have to delete their valet.sock file. What that sock file is, is a pointer on our machine that basically says, hey, nginx, send your requests here, hey php-fpm, listen here. It's not actually a file with contents in it, it is simply an address that you can use for those two systems to talk to each other. Sockets can also be an IP address in a port, but at that point that means you're exposing your traffic up to the network, which we don't actually want to do, so instead we're just using a file. So effectively this nginx config says, listen at 127.0.0.1:80, do a little bit of weird stuff, send everything else over to valet/server.php file, and handle all of our PHP.

PHP-FPM and Sockets3:38

So effectively this nginx config says, listen at 127.0.1 port 80, do a little bit of weird stuff, send everything else over to valet's server.php file, and handle all of our php using fastcgi to proxy the calls over to valet.sock. And then it's passing some information off to that php, saying, this is the actual nginx file we're passing over to. The next thing we should look at is php-fpm. So in this configuration file, it's making it listen at valet82.sock, which you notice may not be the same as valet.sock. So it's setting up a specific pool or a group of processes under my user, listening at this particular socket file.

So it's setting up a specific pool or a group of processes under my User, listening at this particular socket file. Those are really the things that are most important here. So what that means is any requests that are sent over to valet82.soc are going to be handled by this specific version of 8.2. So let's take a really quick look at how those .soc files look. So you can see they're in the config-valet directory. So if we go to cd config-valet, we can see we have several .soc files. What I've done is I've set up a socket for every single version of php that we have running for one of our isolated sites.

What I've done is I've set up a socket for every single version of php that we have running for one of our isolated sites. And then valet.soc, which is the one that normal requests for non-isolated sites point to, is just symlinked to whichever particular version we want to be our primary version at that point. If I were to make a request to a site that's not php-isolated, that means it'll just accept whatever version valet is using as default, it'll just be pointed over to valet.soc. And valet.soc will point you over to whatever particular version we've chosen to be our primary version. But if I make a request to a site that was isolated in valet, it'll point to a specific

valetserver.php Routing Logic5:19

primary version. But if I make a request to a site that was isolated in valet, it'll point to a specific .soc file. In the end, remember, these are just pointers, but they're pointers that are important because Nginx is sending requests here, and different versions of phpFPM are listening at different sockets here. Alright, at this point, we have now routed everything of this request through to valet.server.php, so let's go take a look. Alright, so first thing it does is it loads your specific valet config. It does a quick check to see if this particular server is running as an IP address, because

Alright, so first thing it does is it loads your specific valet config. It does a quick check to see if this particular server is running as an IP address, because you can send requests to your IP address at your IP address slash domain name slash the rest of your normal path. It's not a very common use case, though. It sets up an instance of our Server class. It parses the URI and the site and host for our incoming request so it can match sites based on that information. And it says if we can't find a matching site, and if we don't have a default site path setup, show the 404.

And it says if we can't find a matching site, and if we don't have a default site path setup, show the 404. Then it works through all of our valet drivers and tries to figure out which valet driver should be serving this particular site. If nothing matches, show 404. A little bit of ngrok fanciness. Pulls in any server environment variables that we've defined. It allows this driver to change the URI before it's processed, which some frameworks require us to do. And then it checks, is this particular request for a static file or a PHP file?

us to do. And then it checks, is this particular request for a static file or a PHP file? If it can find that file actually living locally, then it serves the static file instead of running everything through PHP. Finally, if it thinks this is actually a request that's going to be handled by a PHP, it allows the driver to do a quick before loading hook, figures out the path to the front controller, shows a 404 if it can't find the front controller, and finally actually goes into the code. It changes the directory to where the front controller lives, and then requires it. Just directly. There's nothing fancy there.

Just directly. There's nothing fancy there. It's literally just requiring the php of your primary index file for your framework. One quick thing I want to note that's going on here is serveStaticFile. So if we go to the definition of serveStaticFile, what you're going to see is this right here, which is just a little quick thing that we had to do in older versions of PHP. You can basically ignore it. But this, this is what's interesting. We're not actually returning the file. We're not actually returning the file name.

We're not actually returning the file. We're not actually returning the file name. We're just sending a header, and this header is xxlRedirect, and then it basically goes to valetStaticPrefix slash the static file path, which seems kind of interesting, right? Well, let's go look at the definition of valetStaticPrefix. valetStaticPrefix is just this UUID here, and you might have seen that earlier when we were taking a look at the nginx config. You might remember seeing this particular string here. So what happens is basically, originally, in order to serve the static files, it would just put them all at slash static slash whatever.

So what happens is basically, originally, in order to serve the static files, it would just put them all at /static/ whatever. So that was a way to just capture and say any requests made to this particular block should be forwarded through to the static files in our local system. However, what if somebody actually had a folder named static on their site? So instead of that, Adam changed it so that this is now saying if anybody visits the URL underneath this, it should be looking for a static file. So this is saying if somebody makes a request that makes rserver.php decide to serve them a static file, they should get a header named xxlredirect, which we'll talk about in a second, set to that long UUID slash the actual local internal path for the static file.

a static file, they should get a header named xxlredirect, which we'll talk about in a second, set to that long UUID slash the actual local internal path for the static file. What xxlredirect does is it's a nginx feature that allows you to pass the internal file name of a non-public file back to nginx as a header instead of actually serving the whole file. So basically, if you have internal files that you don't want to be accessible to the public, but you do want to serve them through PHP so you can set a permission system to make sure that only certain people can get it, you might have run into the fact that that slows access to those files down, because when you're allowing users to retrieve those files through PHP, access to those files is just slower because it's going through PHP.

slows access to those files down, because when you're allowing users to retrieve those files through php, access to those files is just slower because it's going through php. This is a way to get around that. You can use php to set a header that says, hey nginx, I want them to be served this particular file right here, but your php is not actually doing the work of serving the file. All the php does is send that header, and it allows nginx to take that as an instruction to serve that private file as if it were public. Really cool stuff. All right, and at this point, we've hit your front controller. If it's a Laravel app, it's hitting public/index.php, and at this point, your app

How Valet CLI Works9:49

All right, and at this point, we've hit your front controller. If it's a Laravel app, it's hitting public/index.php, and at this point, your app is handling just like any other php app request, good to go. We just walked the whole way through an HTTP request from your browser, the whole way down to hitting your actual app. Now let's take a look at a valet CLI request. First on your command line, if you just run valet, it just works. How is that? When we install valet, we symlink the valet file, which as you can see here is in the root of the valet project, into the homebrew/bin directory, which we know you'll already

When we install valet, we symlink the valet file, which as you can see here is in the root of the valet project, into the homebrew bin directory, which we know you'll already have in your path. If we were to go to /usr/local/bin, we at some point would see valet, symlinked into that file. That makes sure that we have access to valet anywhere because you should already have this in your path. So when you're running valet, you're running that particular file, which is a bash script. So let's take a look at it. First, the script does a little bit of directory hopping to make sure it's running in the right

So let's take a look at it. First, the script does a little bit of directory hopping to make sure it's running in the right place. Next, it makes sure we have a PHP 8 plus version of php to work with. This allows you to run an older version of php as your daily driver, as long as you have PHP 8 plus installed. It does this by actually running find usable php.php, which either gives you a good response of the executable path, or it gives you an error if it can't find one. Most valet commands will eventually be proxied through to the PHP part of valet, but there were a few that stopped here.

Most valet commands will eventually be proxied through to the php part of valet, but there were a few that stopped here. Most of anything that had to do with ngrok or expose happened here, but even those rely on a PHP script that reads which share tool you have set. As you can see here, we send a request through to valet to ask which share tool we're using so we can then decide whether we're working with ngrok or whether we're working with expose. And these commands basically pass our parameters through to ngrok and expose appropriately. The other thing we might be proxying here are as if you run valet php, or if you run valet composer, that allows us to proxy calls through to the isolated version of PHP our particular app is working with.

valet composer, that allows us to proxy calls through to the isolated version of PHP our particular app is working with. So again, we're going to pass through the valet and we're going to ask it which version of PHP are we actually working with. And then it passes this PHP requests, or this composer request to the correct version of PHP. And finally, every single other command we hit is just going to proxy into the PHP tool as you can see with these comments here. So it's going to basically pass these commands through to valet.php. So let's take a look at that next.

So it's going to basically pass these commands through to valet.php. So let's take a look at that next. Valet is based on a tool called Silly, which is basically a simple layer on top of Symfony's console commands. It starts with the cli/valet.php. But all this does is load the app, and then run the app. We made the app.php separately because that makes testing easier. So if you go over to cli/app.php, this is the actual definition of valet. Because it's running in different contexts, we have to do our auto loading a little bit more specific.

Because it's running in different contexts, we have to do our auto loading a little bit more specific. Then we set up a container and an application for it, a little bit of event management. We're going to say every single time you run any valet commands in the CLI, you're going to do an upgrader check to see if there's any upgrades that need to be done. And then we start defining what our commands are. You'll see every single command we're exposing here, and these commands will reach into various service classes through nginx as a class, or homebrew as a class, or phpfpm as a class, or dnsmasq as a class. And each of these classes take the responsibility for abstracting away the calls that this particular

or dnsmasq as a class. And each of these classes take the responsibility for abstracting away the calls that this particular file might make to those services. Each of those services eventually generates a CLI command, which then valet just runs to set up its config. So you see we've got the install command here, we've got the status command here, and then if you have an actually functionally installed valet install, you've got other commands, like tld, loopback. As you can see, this will probably be pretty familiar if you've written commands with Laravel. tld, space, optional tld, loopback, space, optional loopback.

As you can see, this will probably be pretty familiar if you've written commands with Laravel. tld, space, optional tld, loopback, space, optional loopback. We've got these input and output interfaces, which are basically what we use in Symfony to read or write additional input, and then whatever parameters we've defined in the command. These commands we're trying to keep as simple as possible, because we want it to be super testable. We pass the majority of the work that's happening in these commands off to the actual classes, but anything that has to do specifically with user input, we need to do in these commands here. So let's take a look for fun at what happens when you install valet.

here. So let's take a look for fun at what happens when you install valet. So it stops nginx, it installs all the configuration directories for valet itself, that's that tld, slash, dot, config, slash, valet directory. It installs nginx, which is basically installing nginx itself via homebrew, and then also installing some general config files. There's one global config file, and there's one server-specific config file that we already looked at together. It installs php fdm, which is just making sure that homebrew has php installed, and then installing that one config file we already took a look at.

It installs phpfdm, which is just making sure that homebrew has php installed, and then installing that one config file we already took a look at. phpfdm's install process also sets up that valet.sock file for you, and does the symlinking. We install and configure dnsmasq, which means we basically install it via homebrew. We put a little forward in that says, point to our local dnsmasq directory to read any config files, and then it creates that config file that I showed at the beginning of the episode, which is how we tell dnsmasq to capture.test and point it to our loopback address. Then it restarts nginx, and makes sure that valet, the file, is symlinked to the /usr/bin file, which is what I showed you earlier, which is why we have universal access to valet. And if you want, you can dig more into how all the other commands that valet exposes.

file, which is what I showed you earlier, which is why we have universal access to valet. And if you want, you can dig more into how all the other commands that valet exposes work by just looking through this file. So that's it for an HTTP request and a CLI request coming through valet. In the next episode, we'll take a look at some more advanced features and how they work behind the scenes as well.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟