1
0
mirror of https://github.com/laravel/valet.git synced 2026-02-05 00:20:08 +01:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Florian Schwaiger
2016-12-24 17:07:17 -05:00
46 changed files with 960 additions and 1731 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.DS_Store
vendor/
composer.lock
error.log

View File

@@ -1,9 +1,9 @@
language: php
php:
- 5.5
- 5.6
- 7.0
- 7.1
env:
global:
@@ -15,6 +15,10 @@ sudo: false
before_install:
- travis_retry composer self-update
cache:
directories:
- $HOME/.composer/cache
install:
- if [[ $setup = 'basic' ]]; then travis_retry composer install --no-interaction --prefer-dist; fi
- if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable; fi

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

BIN
bin/caddy

Binary file not shown.

BIN
bin/ngrok

Binary file not shown.

View File

@@ -30,7 +30,7 @@ function __construct(CommandLine $cli, Filesystem $files)
*/
function installed($formula)
{
return in_array($formula, explode(PHP_EOL, $this->cli->run('brew list | grep '.$formula)));
return in_array($formula, explode(PHP_EOL, $this->cli->runAsUser('brew list | grep '.$formula)));
}
/**
@@ -40,7 +40,8 @@ function installed($formula)
*/
function hasInstalledPhp()
{
return $this->installed('php70')
return $this->installed('php71')
|| $this->installed('php70')
|| $this->installed('php56')
|| $this->installed('php55');
}
@@ -49,13 +50,14 @@ function hasInstalledPhp()
* Ensure that the given formula is installed.
*
* @param string $formula
* @param array $options
* @param array $taps
* @return void
*/
function ensureInstalled($formula, array $taps = [])
function ensureInstalled($formula, $options = [], $taps = [])
{
if (! $this->installed($formula)) {
$this->installOrFail($formula, $taps);
$this->installOrFail($formula, $options, $taps);
}
}
@@ -63,10 +65,11 @@ function ensureInstalled($formula, array $taps = [])
* Install the given formula and throw an exception on failure.
*
* @param string $formula
* @param array $options
* @param array $taps
* @return void
*/
function installOrFail($formula, array $taps = [])
function installOrFail($formula, $options = [], $taps = [])
{
if (count($taps) > 0) {
$this->tap($taps);
@@ -74,7 +77,7 @@ function installOrFail($formula, array $taps = [])
output('<info>['.$formula.'] is not installed, installing it now via Brew...</info> 🍻');
$this->cli->runAsUser('brew install '.$formula, function ($exitCode, $errorOutput) use ($formula) {
$this->cli->runAsUser(trim('brew install '.$formula.' '.implode(' ', $options)), function ($exitCode, $errorOutput) use ($formula) {
output($errorOutput);
throw new DomainException('Brew was unable to install ['.$formula.'].');
@@ -82,7 +85,7 @@ function installOrFail($formula, array $taps = [])
}
/**
* Tag the given formulas.
* Tap the given formulas.
*
* @param dynamic[string] $formula
* @return void
@@ -137,7 +140,9 @@ function linkedPhp()
$resolvedPath = $this->files->readLink('/usr/local/bin/php');
if (strpos($resolvedPath, 'php70') !== false) {
if (strpos($resolvedPath, 'php71') !== false) {
return 'php71';
} elseif (strpos($resolvedPath, 'php70') !== false) {
return 'php70';
} elseif (strpos($resolvedPath, 'php56') !== false) {
return 'php56';

View File

@@ -1,116 +0,0 @@
<?php
namespace Valet;
class Caddy
{
var $cli;
var $files;
var $daemonPath = '/Library/LaunchDaemons/com.laravel.valetServer.plist';
/**
* Create a new Brew instance.
*
* @param CommandLine $cli
* @param Filesystem $files
*/
function __construct(CommandLine $cli, Filesystem $files)
{
$this->cli = $cli;
$this->files = $files;
}
/**
* Install the system launch daemon for the Caddy server.
*
* @return void
*/
function install()
{
$this->installCaddyFile();
$this->installCaddyDirectory();
$this->installCaddyDaemon();
}
/**
* Install the Caddyfile to the ~/.valet directory.
*
* This file serves as the main server configuration for Valet.
*
* @return void
*/
function installCaddyFile()
{
$this->files->putAsUser(
VALET_HOME_PATH.'/Caddyfile',
str_replace('VALET_HOME_PATH', VALET_HOME_PATH, $this->files->get(__DIR__.'/../stubs/Caddyfile'))
);
}
/**
* Install the Caddy configuration directory to the ~/.valet directory.
*
* This directory contains all site-specific Caddy definitions.
*
* @return void
*/
function installCaddyDirectory()
{
if (! $this->files->isDir($caddyDirectory = VALET_HOME_PATH.'/Caddy')) {
$this->files->mkdirAsUser($caddyDirectory);
}
$this->files->touchAsUser($caddyDirectory.'/.keep');
}
/**
* Install the Caddy daemon on a system level daemon.
*
* @return void
*/
function installCaddyDaemon()
{
$contents = str_replace(
'VALET_PATH', $this->files->realpath(__DIR__.'/../../'),
$this->files->get(__DIR__.'/../stubs/daemon.plist')
);
$this->files->put(
$this->daemonPath, str_replace('VALET_HOME_PATH', VALET_HOME_PATH, $contents)
);
}
/**
* Restart the launch daemon.
*
* @return void
*/
function restart()
{
$this->cli->quietly('sudo launchctl unload '.$this->daemonPath);
$this->cli->quietly('sudo launchctl load '.$this->daemonPath);
}
/**
* Stop the launch daemon.
*
* @return void
*/
function stop()
{
$this->cli->quietly('sudo launchctl unload '.$this->daemonPath);
}
/**
* Remove the launch daemon.
*
* @return void
*/
function uninstall()
{
$this->stop();
$this->files->unlink($this->daemonPath);
}
}

View File

@@ -12,7 +12,7 @@ class CommandLine
* @param string $command
* @return void
*/
public function quietly($command)
function quietly($command)
{
$this->runCommand($command.' > /dev/null 2>&1');
}
@@ -23,7 +23,7 @@ public function quietly($command)
* @param string $command
* @return void
*/
public function quietlyAsUser($command)
function quietlyAsUser($command)
{
$this->quietly('sudo -u '.user().' '.$command.' > /dev/null 2>&1');
}
@@ -34,7 +34,7 @@ public function quietlyAsUser($command)
* @param string $command
* @return void
*/
public function passthru($command)
function passthru($command)
{
passthru($command);
}
@@ -46,7 +46,7 @@ public function passthru($command)
* @param callable $onError
* @return string
*/
public function run($command, callable $onError = null)
function run($command, callable $onError = null)
{
return $this->runCommand($command, $onError);
}
@@ -58,7 +58,7 @@ public function run($command, callable $onError = null)
* @param callable $onError
* @return string
*/
public function runAsUser($command, callable $onError = null)
function runAsUser($command, callable $onError = null)
{
return $this->runCommand('sudo -u '.user().' '.$command, $onError);
}
@@ -70,7 +70,7 @@ public function runAsUser($command, callable $onError = null)
* @param callable $onError
* @return string
*/
protected function runCommand($command, callable $onError = null)
function runCommand($command, callable $onError = null)
{
$onError = $onError ?: function () {};

View File

@@ -27,6 +27,7 @@ function install()
$this->createDriversDirectory();
$this->createSitesDirectory();
$this->createExtensionsDirectory();
$this->createLogDirectory();
$this->writeBaseConfiguration();
$this->files->chown($this->path(), user());
@@ -81,6 +82,18 @@ function createExtensionsDirectory()
$this->files->ensureDirExists(VALET_HOME_PATH.'/Extensions', user());
}
/**
* Create the directory for Nginx logs.
*
* @return void
*/
function createLogDirectory()
{
$this->files->ensureDirExists(VALET_HOME_PATH.'/Log', user());
$this->files->touch(VALET_HOME_PATH.'/Log/nginx-error.log');
}
/**
* Write the base, initial configuration for Valet.
*/
@@ -119,7 +132,7 @@ function prependPath($path)
}
/**
* Add the given path to the configuration.
* Remove the given path from the configuration.
*
* @param string $path
* @return void
@@ -183,7 +196,7 @@ function updateKey($key, $value)
* @param array $config
* @return void
*/
function write(array $config)
function write($config)
{
$this->files->putAsUser($this->path(), json_encode(
$config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES

145
cli/Valet/Nginx.php Normal file
View File

@@ -0,0 +1,145 @@
<?php
namespace Valet;
class Nginx
{
var $brew;
var $cli;
var $files;
var $configuration;
var $site;
/**
* Create a new Nginx instance.
*
* @param Brew $brew
* @param CommandLine $cli
* @param Filesystem $files
* @param Configuration $configuration
* @param Site $site
* @return void
*/
function __construct(Brew $brew, CommandLine $cli, Filesystem $files,
Configuration $configuration, Site $site)
{
$this->cli = $cli;
$this->brew = $brew;
$this->site = $site;
$this->files = $files;
$this->configuration = $configuration;
}
/**
* Install the configuration files for Nginx.
*
* @return void
*/
function install()
{
$this->brew->ensureInstalled('nginx', ['--with-http2']);
$this->installConfiguration();
$this->installServer();
$this->installNginxDirectory();
}
/**
* Install the Nginx configuration file.
*
* @return void
*/
function installConfiguration()
{
$contents = $this->files->get(__DIR__.'/../stubs/nginx.conf');
$this->files->putAsUser(
'/usr/local/etc/nginx/nginx.conf',
str_replace(['VALET_USER', 'VALET_HOME_PATH'], [user(), VALET_HOME_PATH], $contents)
);
}
/**
* Install the Valet Nginx server configuration file.
*
* @return void
*/
function installServer()
{
$this->files->ensureDirExists('/usr/local/etc/nginx/valet');
$this->files->putAsUser(
'/usr/local/etc/nginx/valet/valet.conf',
str_replace(
['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX'],
[VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX],
$this->files->get(__DIR__.'/../stubs/valet.conf')
)
);
$this->files->putAsUser(
'/usr/local/etc/nginx/fastcgi_params',
$this->files->get(__DIR__.'/../stubs/fastcgi_params')
);
}
/**
* Install the Nginx configuration directory to the ~/.valet directory.
*
* This directory contains all site-specific Nginx servers.
*
* @return void
*/
function installNginxDirectory()
{
if (! $this->files->isDir($nginxDirectory = VALET_HOME_PATH.'/Nginx')) {
$this->files->mkdirAsUser($nginxDirectory);
}
$this->files->putAsUser($nginxDirectory.'/.keep', "\n");
$this->rewriteSecureNginxFiles();
}
/**
* Generate fresh Nginx servers for existing secure sites.
*
* @return void
*/
function rewriteSecureNginxFiles()
{
$domain = $this->configuration->read()['domain'];
$this->site->resecureForNewDomain($domain, $domain);
}
/**
* Restart the Nginx service.
*
* @return void
*/
function restart()
{
$this->cli->quietly('sudo brew services restart nginx');
}
/**
* Stop the Nginx service.
*
* @return void
*/
function stop()
{
$this->cli->quietly('sudo brew services stop nginx');
}
/**
* Prepare Nginx for uninstallation.
*
* @return void
*/
function uninstall()
{
$this->stop();
}
}

View File

@@ -7,14 +7,14 @@
class Ngrok
{
public $tunnelsEndpoint = 'http://127.0.0.1:4040/api/tunnels';
var $tunnelsEndpoint = 'http://127.0.0.1:4040/api/tunnels';
/**
* Get the current tunnel URL from the Ngrok API.
*
* @return string
*/
public function currentTunnelUrl()
function currentTunnelUrl()
{
return retry(20, function () {
$body = Request::get($this->tunnelsEndpoint)->send()->body;
@@ -36,7 +36,7 @@ public function currentTunnelUrl()
* @param array $tunnels
* @return string|null
*/
public function findHttpTunnelUrl(array $tunnels)
function findHttpTunnelUrl($tunnels)
{
foreach ($tunnels as $tunnel) {
if ($tunnel->proto === 'http') {

View File

@@ -8,9 +8,9 @@
class PhpFpm
{
public $brew, $cli, $files;
var $brew, $cli, $files;
public $taps = [
var $taps = [
'homebrew/dupes', 'homebrew/versions', 'homebrew/homebrew-php'
];
@@ -22,7 +22,7 @@ class PhpFpm
* @param Filesystem $files
* @return void
*/
public function __construct(Brew $brew, CommandLine $cli, Filesystem $files)
function __construct(Brew $brew, CommandLine $cli, Filesystem $files)
{
$this->cli = $cli;
$this->brew = $brew;
@@ -34,12 +34,13 @@ public function __construct(Brew $brew, CommandLine $cli, Filesystem $files)
*
* @return void
*/
public function install()
function install()
{
if (! $this->brew->installed('php70') &&
if (! $this->brew->installed('php71') &&
! $this->brew->installed('php70') &&
! $this->brew->installed('php56') &&
! $this->brew->installed('php55')) {
$this->brew->ensureInstalled('php70', $this->taps);
$this->brew->ensureInstalled('php71', [], $this->taps);
}
$this->files->ensureDirExists('/usr/local/var/log', user());
@@ -50,16 +51,20 @@ public function install()
}
/**
* Update the PHP FPM configuration to use the current user.
* Update the PHP FPM configuration.
*
* @return void
*/
public function updateConfiguration()
function updateConfiguration()
{
$contents = $this->files->get($this->fpmConfigPath());
$contents = preg_replace('/^user = .+$/m', 'user = '.user(), $contents);
$contents = preg_replace('/^group = .+$/m', 'group = staff', $contents);
$contents = preg_replace('/^listen = .+$/m', 'listen = '.VALET_HOME_PATH.'/valet.sock', $contents);
$contents = preg_replace('/^;?listen\.owner = .+$/m', 'listen.owner = '.user(), $contents);
$contents = preg_replace('/^;?listen\.group = .+$/m', 'listen.group = staff', $contents);
$contents = preg_replace('/^;?listen\.mode = .+$/m', 'listen.mode = 0777', $contents);
$this->files->put($this->fpmConfigPath(), $contents);
}
@@ -69,7 +74,7 @@ public function updateConfiguration()
*
* @return void
*/
public function restart()
function restart()
{
$this->stop();
@@ -81,9 +86,9 @@ public function restart()
*
* @return void
*/
public function stop()
function stop()
{
$this->brew->stopService('php55', 'php56', 'php70');
$this->brew->stopService('php55', 'php56', 'php70', 'php71');
}
/**
@@ -91,16 +96,15 @@ public function stop()
*
* @return string
*/
public function fpmConfigPath()
function fpmConfigPath()
{
if ($this->brew->linkedPhp() === 'php70') {
return '/usr/local/etc/php/7.0/php-fpm.d/www.conf';
} elseif ($this->brew->linkedPhp() === 'php56') {
return '/usr/local/etc/php/5.6/php-fpm.conf';
} elseif ($this->brew->linkedPhp() === 'php55') {
return '/usr/local/etc/php/5.5/php-fpm.conf';
} else {
throw new DomainException('Unable to find php-fpm config.');
}
$confLookup = [
'php71' => '/usr/local/etc/php/7.1/php-fpm.d/www.conf',
'php70' => '/usr/local/etc/php/7.0/php-fpm.d/www.conf',
'php56' => '/usr/local/etc/php/5.6/php-fpm.conf',
'php55' => '/usr/local/etc/php/5.5/php-fpm.conf',
];
return $confLookup[$this->brew->linkedPhp()];
}
}

View File

@@ -93,7 +93,7 @@ function pruneLinks()
*/
function resecureForNewDomain($oldDomain, $domain)
{
if (!$this->files->exists($this->certificatesPath())) {
if (! $this->files->exists($this->certificatesPath())) {
return;
}
@@ -136,7 +136,7 @@ function secure($url)
$this->createCertificate($url);
$this->files->putAsUser(
VALET_HOME_PATH.'/Caddy/'.$url, $this->buildSecureCaddyfile($url)
VALET_HOME_PATH.'/Nginx/'.$url, $this->buildSecureNginxServer($url)
);
}
@@ -201,18 +201,19 @@ function trustCertificate($crtPath)
}
/**
* Build the TLS secured Caddyfile for the given URL.
* Build the TLS secured Nginx server for the given URL.
*
* @param string $url
* @return string
*/
function buildSecureCaddyfile($url)
function buildSecureNginxServer($url)
{
$path = $this->certificatesPath();
return str_replace(
['VALET_SITE', 'VALET_CERT', 'VALET_KEY'], [$url, $path.'/'.$url.'.crt', $path.'/'.$url.'.key'],
$this->files->get(__DIR__.'/../stubs/SecureCaddyfile')
['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_CERT', 'VALET_KEY'],
[VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $url, $path.'/'.$url.'.crt', $path.'/'.$url.'.key'],
$this->files->get(__DIR__.'/../stubs/secure.valet.conf')
);
}
@@ -225,7 +226,7 @@ function buildSecureCaddyfile($url)
function unsecure($url)
{
if ($this->files->exists($this->certificatesPath().'/'.$url.'.crt')) {
$this->files->unlink(VALET_HOME_PATH.'/Caddy/'.$url);
$this->files->unlink(VALET_HOME_PATH.'/Nginx/'.$url);
$this->files->unlink($this->certificatesPath().'/'.$url.'.key');
$this->files->unlink($this->certificatesPath().'/'.$url.'.csr');
@@ -235,29 +236,6 @@ function unsecure($url)
}
}
/**
* Get all of the log files for all sites.
*
* @param array $paths
* @return array
*/
function logs($paths)
{
$files = collect();
foreach ($paths as $path) {
$files = $files->merge(collect($this->files->scandir($path))->map(function ($directory) use ($path) {
$logPath = $path.'/'.$directory.'/storage/logs/laravel.log';
if ($this->files->isDir(dirname($logPath))) {
return $this->files->touchAsUser($logPath);
}
})->filter());
}
return $files->values()->all();
}
/**
* Get the path to the linked Valet sites.
*

View File

@@ -54,20 +54,22 @@ public function frontControllerPath($sitePath, $siteName, $uri)
if ($this->isActualFile($candidate)) {
$_SERVER['SCRIPT_FILENAME'] = $candidate;
$_SERVER['SCRIPT_NAME'] = str_replace($sitePath, '', $candidate);
$_SERVER['DOCUMENT_ROOT'] = $sitePath;
return $candidate;
}
}
$fixedCandidates = [
$this->asRootPhpIndexFile($sitePath),
$this->asPublicPhpIndexFile($sitePath),
$this->asPublicHtmlIndexFile($sitePath),
$fixedCandidatesAndDocroots = [
$this->asRootPhpIndexFile($sitePath) => $sitePath,
$this->asPublicPhpIndexFile($sitePath) => $sitePath . '/public',
$this->asPublicHtmlIndexFile($sitePath) => $sitePath . '/public',
];
foreach ($fixedCandidates as $candidate) {
foreach ($fixedCandidatesAndDocroots as $candidate => $docroot) {
if ($this->isActualFile($candidate)) {
$_SERVER['SCRIPT_FILENAME'] = $candidate;
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['DOCUMENT_ROOT'] = $docroot;
return $candidate;
}
}

View File

@@ -51,10 +51,25 @@ public function frontControllerPath($sitePath, $siteName, $uri)
if (strpos($uri, '/wp/') === 0) {
return is_dir($sitePath.'/web'.$uri)
? $sitePath.'/web'.$uri.'/index.php'
? $sitePath.'/web'.$this->forceTrailingSlash($uri).'/index.php'
: $sitePath.'/web'.$uri;
}
return $sitePath.'/web/index.php';
}
/**
* Redirect to uri with trailing slash.
*
* @param string $uri
* @return string
*/
private function forceTrailingSlash($uri)
{
if (substr($uri, -1 * strlen('/wp/wp-admin')) == '/wp/wp-admin') {
header('Location: '.$uri.'/'); die;
}
return $uri;
}
}

View File

@@ -0,0 +1,48 @@
<?php
class Concrete5ValetDriver extends BasicValetDriver
{
/**
* If a concrete directory exists, it's probably c5
* @param string $sitePath
* @param string $siteName
* @param string $uri
* @return bool
*/
public function serves($sitePath, $siteName, $uri)
{
return file_exists($sitePath . "/concrete/config/install/base");
}
/**
* @param string $sitePath
* @param string $siteName
* @param string $uri
* @return string
*/
public function frontControllerPath($sitePath, $siteName, $uri)
{
if (!getenv('CONCRETE5_ENV')) {
putenv('CONCRETE5_ENV=valet');
}
$matches = [];
if (preg_match('/^\/(.*?)\.php/', $uri, $matches)) {
$filename = $matches[0];
if (file_exists($sitePath.$filename) && ! is_dir($sitePath.$filename)) {
$_SERVER['SCRIPT_FILENAME'] = $sitePath.$filename;
$_SERVER['SCRIPT_NAME'] = $filename;
return $sitePath . $filename;
}
}
$_SERVER['SCRIPT_FILENAME'] = $sitePath . '/index.php';
$_SERVER['SCRIPT_NAME'] = '/index.php';
return $sitePath . '/index.php';
}
}

View File

@@ -42,10 +42,141 @@ public function isStaticFile($sitePath, $siteName, $uri)
*/
public function frontControllerPath($sitePath, $siteName, $uri)
{
$_SERVER['SCRIPT_FILENAME'] = $sitePath.'/public/index.php';
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
$_SERVER['SCRIPT_NAME'] = '/index.php';
// Default index path
$indexPath = $sitePath.'/public/index.php';
$scriptName = '/index.php';
return $sitePath.'/public/index.php';
// Check if the first URL segment matches any of the defined locales
$locales = [
'ar',
'ar_sa',
'bg',
'bg_bg',
'ca_es',
'cs',
'cy_gb',
'da',
'da_dk',
'de',
'de_at',
'de_ch',
'de_de',
'el',
'el_gr',
'en',
'en_as',
'en_au',
'en_bb',
'en_be',
'en_bm',
'en_bw',
'en_bz',
'en_ca',
'en_dsrt',
'en_dsrt_us',
'en_gb',
'en_gu',
'en_gy',
'en_hk',
'en_ie',
'en_in',
'en_jm',
'en_mh',
'en_mp',
'en_mt',
'en_mu',
'en_na',
'en_nz',
'en_ph',
'en_pk',
'en_sg',
'en_shaw',
'en_tt',
'en_um',
'en_us',
'en_us_posix',
'en_vi',
'en_za',
'en_zw',
'en_zz',
'es',
'es_cl',
'es_es',
'es_mx',
'es_us',
'es_ve',
'et',
'fi',
'fi_fi',
'fil',
'fr',
'fr_be',
'fr_ca',
'fr_ch',
'fr_fr',
'fr_ma',
'he',
'hr',
'hr_hr',
'hu',
'hu_hu',
'id',
'id_id',
'it',
'it_ch',
'it_it',
'ja',
'ja_jp',
'ko',
'ko_kr',
'lt',
'lv',
'ms',
'ms_my',
'nb',
'nb_no',
'nl',
'nl_be',
'nl_nl',
'nn',
'nn_no',
'no',
'pl',
'pl_pl',
'pt',
'pt_br',
'pt_pt',
'ro',
'ro_ro',
'ru',
'ru_ru',
'sk',
'sl',
'sr',
'sv',
'sv_se',
'th',
'th_th',
'tr',
'tr_tr',
'uk',
'vi',
'zh',
'zh_cn',
'zh_tw',
];
$parts = explode('/', $uri);
if (count($parts) > 1 && in_array($parts[1], $locales)) {
$indexPath = $sitePath.'/public/'. $parts[1] .'/index.php';
$scriptName = '/' . $parts[1] . '/index.php';
}
$_SERVER['SCRIPT_FILENAME'] = $indexPath;
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
$_SERVER['SCRIPT_NAME'] = $scriptName;
$_SERVER['PHP_SELF'] = $scriptName;
return $indexPath;
}
}

View File

@@ -0,0 +1,73 @@
<?php
class DrupalValetDriver extends ValetDriver
{
/**
* Determine if the driver serves the request.
*
* @param string $sitePath
* @param string $siteName
* @param string $uri
* @return void
*/
public function serves($sitePath, $siteName, $uri)
{
/**
* /misc/drupal.js = Drupal 7
* /core/lib/Drupal.php = Drupal 8
*/
if (file_exists($sitePath.'/misc/drupal.js') ||
file_exists($sitePath.'/core/lib/Drupal.php')) {
return true;
}
}
/**
* Determine if the incoming request is for a static file.
*
* @param string $sitePath
* @param string $siteName
* @param string $uri
* @return string|false
*/
public function isStaticFile($sitePath, $siteName, $uri)
{
if (file_exists($sitePath.$uri) &&
! is_dir($sitePath.$uri) &&
pathinfo($sitePath.$uri)['extension'] != 'php') {
return $sitePath.$uri;
}
return false;
}
/**
* Get the fully resolved path to the application's front controller.
*
* @param string $sitePath
* @param string $siteName
* @param string $uri
* @return string
*/
public function frontControllerPath($sitePath, $siteName, $uri)
{
if (!empty($uri) && $uri !== '/') {
$_GET['q'] = $uri;
}
$matches = [];
if (preg_match('/^\/(.*?)\.php/', $uri, $matches)) {
$filename = $matches[0];
if (file_exists($sitePath.$filename) && ! is_dir($sitePath.$filename)) {
$_SERVER['SCRIPT_FILENAME'] = $sitePath.$filename;
$_SERVER['SCRIPT_NAME'] = $filename;
return $sitePath.$filename;
}
}
// Fallback
$_SERVER['SCRIPT_FILENAME'] = $sitePath.'/index.php';
$_SERVER['SCRIPT_NAME'] = '/index.php';
return $sitePath.'/index.php';
}
}

View File

@@ -42,7 +42,13 @@ abstract public function frontControllerPath($sitePath, $siteName, $uri);
*/
public static function assign($sitePath, $siteName, $uri)
{
$drivers = static::driversIn(VALET_HOME_PATH.'/Drivers');
$drivers = [];
if ($customSiteDriver = static::customSiteDriver($sitePath)) {
$drivers[] = $customSiteDriver;
}
$drivers = array_merge($drivers, static::driversIn(VALET_HOME_PATH.'/Drivers'));
$drivers[] = 'LaravelValetDriver';
@@ -59,6 +65,8 @@ public static function assign($sitePath, $siteName, $uri)
$drivers[] = 'ContaoValetDriver';
$drivers[] = 'KatanaValetDriver';
$drivers[] = 'JoomlaValetDriver';
$drivers[] = 'DrupalValetDriver';
$drivers[] = 'Concrete5ValetDriver';
$drivers[] = 'Typo3ValetDriver';
$drivers[] = 'BasicValetDriver';
@@ -72,6 +80,23 @@ public static function assign($sitePath, $siteName, $uri)
}
}
/**
* Get the custom driver class from the site path, if one exists.
*
* @param string $sitePath
* @return string
*/
public static function customSiteDriver($sitePath)
{
if (! file_exists($sitePath.'/LocalValetDriver.php')) {
return;
}
require_once $sitePath.'/LocalValetDriver.php';
return 'LocalValetDriver';
}
/**
* Get all of the driver classes in a given path.
*
@@ -119,15 +144,25 @@ public function mutateUri($uri)
*/
public function serveStaticFile($staticFilePath, $sitePath, $siteName, $uri)
{
$extension = strtolower(pathinfo($staticFilePath)['extension']);
/**
* Back story...
*
* PHP docs *claim* you can set default_mimetype = "" to disable the default
* Content-Type header. This works in PHP 7+, but in PHP 5.* it sends an
* *empty* Content-Type header, which is significantly different than
* sending *no* Content-Type header.
*
* However, if you explicitly set a Content-Type header, then explicitly
* remove that Content-Type header, PHP seems to not re-add the default.
*
* I have a hard time believing this is by design and not coincidence.
*
* Burn. it. all.
*/
header('Content-Type: text/html');
header_remove('Content-Type');
$mimes = require(__DIR__.'/../mimes.php');
$mime = isset($mimes[$extension]) ? $mimes[$extension] : 'application/octet-stream';
header('Content-Type: '. $mime);
readfile($staticFilePath);
header('X-Accel-Redirect: /' . VALET_STATIC_PREFIX . $staticFilePath);
}
/**

View File

@@ -12,7 +12,7 @@ class WordPressValetDriver extends BasicValetDriver
*/
public function serves($sitePath, $siteName, $uri)
{
return file_exists($sitePath.'/wp-config.php');
return file_exists($sitePath.'/wp-config.php') || file_exists($sitePath.'/wp-config-sample.php');
}
/**
@@ -27,7 +27,25 @@ public function frontControllerPath($sitePath, $siteName, $uri)
{
$_SERVER['PHP_SELF'] = $uri;
$_SERVER['SERVER_ADDR'] = '127.0.0.1';
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
return parent::frontControllerPath($sitePath, $siteName, $uri);
return parent::frontControllerPath(
$sitePath, $siteName, $this->forceTrailingSlash($uri)
);
}
/**
* Redirect to uri with trailing slash.
*
* @param string $uri
* @return string
*/
private function forceTrailingSlash($uri)
{
if (substr($uri, -1 * strlen('/wp-admin')) == '/wp-admin') {
header('Location: '.$uri.'/'); die;
}
return $uri;
}
}

View File

@@ -23,4 +23,6 @@
require_once __DIR__.'/KatanaValetDriver.php';
require_once __DIR__.'/CakeValetDriver.php';
require_once __DIR__.'/JoomlaValetDriver.php';
require_once __DIR__.'/DrupalValetDriver.php';
require_once __DIR__.'/Concrete5ValetDriver.php';
require_once __DIR__.'/Typo3ValetDriver.php';

View File

@@ -17,8 +17,8 @@
exit(1);
}
if (exec('which brew') !== '/usr/local/bin/brew' && ! $inTestingEnvironment) {
echo 'Valet requires Brew to be installed on your Mac.';
if (exec('which brew') == '' && ! $inTestingEnvironment) {
echo 'Valet requires Homebrew to be installed on your Mac.';
exit(1);
}

View File

@@ -1,5 +1,7 @@
<?php
use Illuminate\Container\Container;
class Facade
{
/**
@@ -21,12 +23,14 @@ public static function containerKey()
*/
public static function __callStatic($method, $parameters)
{
return call_user_func_array([resolve(static::containerKey()), $method], $parameters);
$resolvedInstance = Container::getInstance()->make(static::containerKey());
return call_user_func_array([$resolvedInstance, $method], $parameters);
}
}
class Brew extends Facade {}
class Caddy extends Facade {}
class Nginx extends Facade {}
class CommandLine extends Facade {}
class Configuration extends Facade {}
class DnsMasq extends Facade {}

View File

@@ -7,6 +7,8 @@
* Define the ~/.valet path as a constant.
*/
define('VALET_HOME_PATH', $_SERVER['HOME'].'/.valet');
define('VALET_SERVER_PATH', realpath(__DIR__ . '/../../server.php'));
define('VALET_STATIC_PREFIX', '41c270e4-5535-4daa-b23e-c269744c2f45');
/**
* Output the given text to the console.
@@ -45,15 +47,17 @@ function output($output)
(new Symfony\Component\Console\Output\ConsoleOutput)->writeln($output);
}
/**
* Resolve the given class from the container.
*
* @param string $class
* @return mixed
*/
function resolve($class)
{
return Container::getInstance()->make($class);
if (! function_exists('resolve')) {
/**
* Resolve the given class from the container.
*
* @param string $class
* @return mixed
*/
function resolve($class)
{
return Container::getInstance()->make($class);
}
}
/**
@@ -68,31 +72,33 @@ function swap($class, $instance)
Container::getInstance()->instance($class, $instance);
}
/**
* Retry the given function N times.
*
* @param int $retries
* @param callable $retries
* @param int $sleep
* @return mixed
*/
function retry($retries, $fn, $sleep = 0)
{
beginning:
try {
return $fn();
} catch (Exception $e) {
if (! $retries) {
throw $e;
if (! function_exists('retry')) {
/**
* Retry the given function N times.
*
* @param int $retries
* @param callable $retries
* @param int $sleep
* @return mixed
*/
function retry($retries, $fn, $sleep = 0)
{
beginning:
try {
return $fn();
} catch (Exception $e) {
if (! $retries) {
throw $e;
}
$retries--;
if ($sleep > 0) {
usleep($sleep * 1000);
}
goto beginning;
}
$retries--;
if ($sleep > 0) {
usleep($sleep * 1000);
}
goto beginning;
}
}

View File

@@ -1,989 +0,0 @@
<?php
return [
"ez" => "application/andrew-inset",
"aw" => "application/applixware",
"atom" => "application/atom+xml",
"atomcat" => "application/atomcat+xml",
"atomsvc" => "application/atomsvc+xml",
"ccxml" => "application/ccxml+xml",
"cdmia" => "application/cdmi-capability",
"cdmic" => "application/cdmi-container",
"cdmid" => "application/cdmi-domain",
"cdmio" => "application/cdmi-object",
"cdmiq" => "application/cdmi-queue",
"cu" => "application/cu-seeme",
"davmount" => "application/davmount+xml",
"dbk" => "application/docbook+xml",
"dssc" => "application/dssc+der",
"xdssc" => "application/dssc+xml",
"ecma" => "application/ecmascript",
"emma" => "application/emma+xml",
"epub" => "application/epub+zip",
"exi" => "application/exi",
"pfr" => "application/font-tdpfr",
"gml" => "application/gml+xml",
"gpx" => "application/gpx+xml",
"gxf" => "application/gxf",
"stk" => "application/hyperstudio",
"ink" => "application/inkml+xml",
"inkml" => "application/inkml+xml",
"ipfix" => "application/ipfix",
"jar" => "application/java-archive",
"ser" => "application/java-serialized-object",
"class" => "application/java-vm",
"js" => "application/javascript",
"json" => "application/json",
"jsonml" => "application/jsonml+json",
"lostxml" => "application/lost+xml",
"hqx" => "application/mac-binhex40",
"cpt" => "application/mac-compactpro",
"mads" => "application/mads+xml",
"mrc" => "application/marc",
"mrcx" => "application/marcxml+xml",
"ma" => "application/mathematica",
"nb" => "application/mathematica",
"mb" => "application/mathematica",
"mathml" => "application/mathml+xml",
"mbox" => "application/mbox",
"mscml" => "application/mediaservercontrol+xml",
"metalink" => "application/metalink+xml",
"meta4" => "application/metalink4+xml",
"mets" => "application/mets+xml",
"mods" => "application/mods+xml",
"m21" => "application/mp21",
"mp21" => "application/mp21",
"mp4s" => "application/mp4",
"doc" => "application/msword",
"dot" => "application/msword",
"mxf" => "application/mxf",
"bin" => "application/octet-stream",
"dms" => "application/octet-stream",
"lrf" => "application/octet-stream",
"mar" => "application/octet-stream",
"so" => "application/octet-stream",
"dist" => "application/octet-stream",
"distz" => "application/octet-stream",
"pkg" => "application/octet-stream",
"bpk" => "application/octet-stream",
"dump" => "application/octet-stream",
"elc" => "application/octet-stream",
"deploy" => "application/octet-stream",
"oda" => "application/oda",
"opf" => "application/oebps-package+xml",
"ogx" => "application/ogg",
"omdoc" => "application/omdoc+xml",
"onetoc" => "application/onenote",
"onetoc2" => "application/onenote",
"onetmp" => "application/onenote",
"onepkg" => "application/onenote",
"oxps" => "application/oxps",
"xer" => "application/patch-ops-error+xml",
"pdf" => "application/pdf",
"pgp" => "application/pgp-encrypted",
"asc" => "application/pgp-signature",
"sig" => "application/pgp-signature",
"prf" => "application/pics-rules",
"p10" => "application/pkcs10",
"p7m" => "application/pkcs7-mime",
"p7c" => "application/pkcs7-mime",
"p7s" => "application/pkcs7-signature",
"p8" => "application/pkcs8",
"ac" => "application/pkix-attr-cert",
"cer" => "application/pkix-cert",
"crl" => "application/pkix-crl",
"pkipath" => "application/pkix-pkipath",
"pki" => "application/pkixcmp",
"pls" => "application/pls+xml",
"ai" => "application/postscript",
"eps" => "application/postscript",
"ps" => "application/postscript",
"cww" => "application/prs.cww",
"pskcxml" => "application/pskc+xml",
"rdf" => "application/rdf+xml",
"rif" => "application/reginfo+xml",
"rnc" => "application/relax-ng-compact-syntax",
"rl" => "application/resource-lists+xml",
"rld" => "application/resource-lists-diff+xml",
"rs" => "application/rls-services+xml",
"gbr" => "application/rpki-ghostbusters",
"mft" => "application/rpki-manifest",
"roa" => "application/rpki-roa",
"rsd" => "application/rsd+xml",
"rss" => "application/rss+xml",
"rtf" => "application/rtf",
"sbml" => "application/sbml+xml",
"scq" => "application/scvp-cv-request",
"scs" => "application/scvp-cv-response",
"spq" => "application/scvp-vp-request",
"spp" => "application/scvp-vp-response",
"sdp" => "application/sdp",
"setpay" => "application/set-payment-initiation",
"setreg" => "application/set-registration-initiation",
"shf" => "application/shf+xml",
"smi" => "application/smil+xml",
"smil" => "application/smil+xml",
"rq" => "application/sparql-query",
"srx" => "application/sparql-results+xml",
"gram" => "application/srgs",
"grxml" => "application/srgs+xml",
"sru" => "application/sru+xml",
"ssdl" => "application/ssdl+xml",
"ssml" => "application/ssml+xml",
"tei" => "application/tei+xml",
"teicorpus" => "application/tei+xml",
"tfi" => "application/thraud+xml",
"tsd" => "application/timestamped-data",
"plb" => "application/vnd.3gpp.pic-bw-large",
"psb" => "application/vnd.3gpp.pic-bw-small",
"pvb" => "application/vnd.3gpp.pic-bw-var",
"tcap" => "application/vnd.3gpp2.tcap",
"pwn" => "application/vnd.3m.post-it-notes",
"aso" => "application/vnd.accpac.simply.aso",
"imp" => "application/vnd.accpac.simply.imp",
"acu" => "application/vnd.acucobol",
"atc" => "application/vnd.acucorp",
"acutc" => "application/vnd.acucorp",
"air" => "application/vnd.adobe.air-application-installer-package+zip",
"fcdt" => "application/vnd.adobe.formscentral.fcdt",
"fxp" => "application/vnd.adobe.fxp",
"fxpl" => "application/vnd.adobe.fxp",
"xdp" => "application/vnd.adobe.xdp+xml",
"xfdf" => "application/vnd.adobe.xfdf",
"ahead" => "application/vnd.ahead.space",
"azf" => "application/vnd.airzip.filesecure.azf",
"azs" => "application/vnd.airzip.filesecure.azs",
"azw" => "application/vnd.amazon.ebook",
"acc" => "application/vnd.americandynamics.acc",
"ami" => "application/vnd.amiga.ami",
"apk" => "application/vnd.android.package-archive",
"cii" => "application/vnd.anser-web-certificate-issue-initiation",
"fti" => "application/vnd.anser-web-funds-transfer-initiation",
"atx" => "application/vnd.antix.game-component",
"mpkg" => "application/vnd.apple.installer+xml",
"m3u8" => "application/vnd.apple.mpegurl",
"swi" => "application/vnd.aristanetworks.swi",
"iota" => "application/vnd.astraea-software.iota",
"aep" => "application/vnd.audiograph",
"mpm" => "application/vnd.blueice.multipass",
"bmi" => "application/vnd.bmi",
"rep" => "application/vnd.businessobjects",
"cdxml" => "application/vnd.chemdraw+xml",
"mmd" => "application/vnd.chipnuts.karaoke-mmd",
"cdy" => "application/vnd.cinderella",
"cla" => "application/vnd.claymore",
"rp9" => "application/vnd.cloanto.rp9",
"c4g" => "application/vnd.clonk.c4group",
"c4d" => "application/vnd.clonk.c4group",
"c4f" => "application/vnd.clonk.c4group",
"c4p" => "application/vnd.clonk.c4group",
"c4u" => "application/vnd.clonk.c4group",
"c11amc" => "application/vnd.cluetrust.cartomobile-config",
"c11amz" => "application/vnd.cluetrust.cartomobile-config-pkg",
"csp" => "application/vnd.commonspace",
"cdbcmsg" => "application/vnd.contact.cmsg",
"cmc" => "application/vnd.cosmocaller",
"clkx" => "application/vnd.crick.clicker",
"clkk" => "application/vnd.crick.clicker.keyboard",
"clkp" => "application/vnd.crick.clicker.palette",
"clkt" => "application/vnd.crick.clicker.template",
"clkw" => "application/vnd.crick.clicker.wordbank",
"wbs" => "application/vnd.criticaltools.wbs+xml",
"pml" => "application/vnd.ctc-posml",
"ppd" => "application/vnd.cups-ppd",
"car" => "application/vnd.curl.car",
"pcurl" => "application/vnd.curl.pcurl",
"dart" => "application/vnd.dart",
"rdz" => "application/vnd.data-vision.rdz",
"uvf" => "application/vnd.dece.data",
"uvvf" => "application/vnd.dece.data",
"uvd" => "application/vnd.dece.data",
"uvvd" => "application/vnd.dece.data",
"uvt" => "application/vnd.dece.ttml+xml",
"uvvt" => "application/vnd.dece.ttml+xml",
"uvx" => "application/vnd.dece.unspecified",
"uvvx" => "application/vnd.dece.unspecified",
"uvz" => "application/vnd.dece.zip",
"uvvz" => "application/vnd.dece.zip",
"fe_launch" => "application/vnd.denovo.fcselayout-link",
"dna" => "application/vnd.dna",
"mlp" => "application/vnd.dolby.mlp",
"dpg" => "application/vnd.dpgraph",
"dfac" => "application/vnd.dreamfactory",
"kpxx" => "application/vnd.ds-keypoint",
"ait" => "application/vnd.dvb.ait",
"svc" => "application/vnd.dvb.service",
"geo" => "application/vnd.dynageo",
"mag" => "application/vnd.ecowin.chart",
"nml" => "application/vnd.enliven",
"esf" => "application/vnd.epson.esf",
"msf" => "application/vnd.epson.msf",
"qam" => "application/vnd.epson.quickanime",
"slt" => "application/vnd.epson.salt",
"ssf" => "application/vnd.epson.ssf",
"es3" => "application/vnd.eszigno3+xml",
"et3" => "application/vnd.eszigno3+xml",
"ez2" => "application/vnd.ezpix-album",
"ez3" => "application/vnd.ezpix-package",
"fdf" => "application/vnd.fdf",
"mseed" => "application/vnd.fdsn.mseed",
"seed" => "application/vnd.fdsn.seed",
"dataless" => "application/vnd.fdsn.seed",
"gph" => "application/vnd.flographit",
"ftc" => "application/vnd.fluxtime.clip",
"fm" => "application/vnd.framemaker",
"frame" => "application/vnd.framemaker",
"maker" => "application/vnd.framemaker",
"book" => "application/vnd.framemaker",
"fnc" => "application/vnd.frogans.fnc",
"ltf" => "application/vnd.frogans.ltf",
"fsc" => "application/vnd.fsc.weblaunch",
"oas" => "application/vnd.fujitsu.oasys",
"oa2" => "application/vnd.fujitsu.oasys2",
"oa3" => "application/vnd.fujitsu.oasys3",
"fg5" => "application/vnd.fujitsu.oasysgp",
"bh2" => "application/vnd.fujitsu.oasysprs",
"ddd" => "application/vnd.fujixerox.ddd",
"xdw" => "application/vnd.fujixerox.docuworks",
"xbd" => "application/vnd.fujixerox.docuworks.binder",
"fzs" => "application/vnd.fuzzysheet",
"txd" => "application/vnd.genomatix.tuxedo",
"ggb" => "application/vnd.geogebra.file",
"ggt" => "application/vnd.geogebra.tool",
"gex" => "application/vnd.geometry-explorer",
"gre" => "application/vnd.geometry-explorer",
"gxt" => "application/vnd.geonext",
"g2w" => "application/vnd.geoplan",
"g3w" => "application/vnd.geospace",
"gmx" => "application/vnd.gmx",
"kml" => "application/vnd.google-earth.kml+xml",
"kmz" => "application/vnd.google-earth.kmz",
"gqf" => "application/vnd.grafeq",
"gqs" => "application/vnd.grafeq",
"gac" => "application/vnd.groove-account",
"ghf" => "application/vnd.groove-help",
"gim" => "application/vnd.groove-identity-message",
"grv" => "application/vnd.groove-injector",
"gtm" => "application/vnd.groove-tool-message",
"tpl" => "application/vnd.groove-tool-template",
"vcg" => "application/vnd.groove-vcard",
"hal" => "application/vnd.hal+xml",
"zmm" => "application/vnd.handheld-entertainment+xml",
"hbci" => "application/vnd.hbci",
"les" => "application/vnd.hhe.lesson-player",
"hpgl" => "application/vnd.hp-hpgl",
"hpid" => "application/vnd.hp-hpid",
"hps" => "application/vnd.hp-hps",
"jlt" => "application/vnd.hp-jlyt",
"pcl" => "application/vnd.hp-pcl",
"pclxl" => "application/vnd.hp-pclxl",
"sfd- =>dstx", "application/vnd.hydrostatix.sof-data",
"mpy" => "application/vnd.ibm.minipay",
"afp" => "application/vnd.ibm.modcap",
"listafp" => "application/vnd.ibm.modcap",
"list3820" => "application/vnd.ibm.modcap",
"irm" => "application/vnd.ibm.rights-management",
"sc" => "application/vnd.ibm.secure-container",
"icc" => "application/vnd.iccprofile",
"icm" => "application/vnd.iccprofile",
"igl" => "application/vnd.igloader",
"ivp" => "application/vnd.immervision-ivp",
"ivu" => "application/vnd.immervision-ivu",
"igm" => "application/vnd.insors.igm",
"xpw" => "application/vnd.intercon.formnet",
"xpx" => "application/vnd.intercon.formnet",
"i2g" => "application/vnd.intergeo",
"qbo" => "application/vnd.intu.qbo",
"qfx" => "application/vnd.intu.qfx",
"rcprofile" => "application/vnd.ipunplugged.rcprofile",
"irp" => "application/vnd.irepository.package+xml",
"xpr" => "application/vnd.is-xpr",
"fcs" => "application/vnd.isac.fcs",
"jam" => "application/vnd.jam",
"rms" => "application/vnd.jcp.javame.midlet-rms",
"jisp" => "application/vnd.jisp",
"joda" => "application/vnd.joost.joda-archive",
"ktz" => "application/vnd.kahootz",
"ktr" => "application/vnd.kahootz",
"karbon" => "application/vnd.kde.karbon",
"chrt" => "application/vnd.kde.kchart",
"kfo" => "application/vnd.kde.kformula",
"flw" => "application/vnd.kde.kivio",
"kon" => "application/vnd.kde.kontour",
"kpr" => "application/vnd.kde.kpresenter",
"kpt" => "application/vnd.kde.kpresenter",
"ksp" => "application/vnd.kde.kspread",
"kwd" => "application/vnd.kde.kword",
"kwt" => "application/vnd.kde.kword",
"htke" => "application/vnd.kenameaapp",
"kia" => "application/vnd.kidspiration",
"kne" => "application/vnd.kinar",
"knp" => "application/vnd.kinar",
"skp" => "application/vnd.koan",
"skd" => "application/vnd.koan",
"skt" => "application/vnd.koan",
"skm" => "application/vnd.koan",
"sse" => "application/vnd.kodak-descriptor",
"lasxml" => "application/vnd.las.las+xml",
"lbd" => "application/vnd.llamagraphics.life-balance.desktop",
"lbe" => "application/vnd.llamagraphics.life-balance.exchange+xml",
"123" => "application/vnd.lotus-1-2-3",
"apr" => "application/vnd.lotus-approach",
"pre" => "application/vnd.lotus-freelance",
"nsf" => "application/vnd.lotus-notes",
"org" => "application/vnd.lotus-organizer",
"scm" => "application/vnd.lotus-screencam",
"lwp" => "application/vnd.lotus-wordpro",
"portpkg" => "application/vnd.macports.portpkg",
"mcd" => "application/vnd.mcd",
"mc1" => "application/vnd.medcalcdata",
"cdkey" => "application/vnd.mediastation.cdkey",
"mwf" => "application/vnd.mfer",
"mfm" => "application/vnd.mfmp",
"flo" => "application/vnd.micrografx.flo",
"igx" => "application/vnd.micrografx.igx",
"mif" => "application/vnd.mif",
"daf" => "application/vnd.mobius.daf",
"dis" => "application/vnd.mobius.dis",
"mbk" => "application/vnd.mobius.mbk",
"mqy" => "application/vnd.mobius.mqy",
"msl" => "application/vnd.mobius.msl",
"plc" => "application/vnd.mobius.plc",
"txf" => "application/vnd.mobius.txf",
"mpn" => "application/vnd.mophun.application",
"mpc" => "application/vnd.mophun.certificate",
"xul" => "application/vnd.mozilla.xul+xml",
"cil" => "application/vnd.ms-artgalry",
"cab" => "application/vnd.ms-cab-compressed",
"xls" => "application/vnd.ms-excel",
"xlm" => "application/vnd.ms-excel",
"xla" => "application/vnd.ms-excel",
"xlc" => "application/vnd.ms-excel",
"xlt" => "application/vnd.ms-excel",
"xlw" => "application/vnd.ms-excel",
"xlam" => "application/vnd.ms-excel.addin.macroenabled.12",
"xlsb" => "application/vnd.ms-excel.sheet.binary.macroenabled.12",
"xlsm" => "application/vnd.ms-excel.sheet.macroenabled.12",
"xltm" => "application/vnd.ms-excel.template.macroenabled.12",
"eot" => "application/vnd.ms-fontobject",
"chm" => "application/vnd.ms-htmlhelp",
"ims" => "application/vnd.ms-ims",
"lrm" => "application/vnd.ms-lrm",
"thmx" => "application/vnd.ms-officetheme",
"cat" => "application/vnd.ms-pki.seccat",
"stl" => "application/vnd.ms-pki.stl",
"ppt" => "application/vnd.ms-powerpoint",
"pps" => "application/vnd.ms-powerpoint",
"pot" => "application/vnd.ms-powerpoint",
"ppam" => "application/vnd.ms-powerpoint.addin.macroenabled.12",
"pptm" => "application/vnd.ms-powerpoint.presentation.macroenabled.12",
"sldm" => "application/vnd.ms-powerpoint.slide.macroenabled.12",
"ppsm" => "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
"potm" => "application/vnd.ms-powerpoint.template.macroenabled.12",
"mpp" => "application/vnd.ms-project",
"mpt" => "application/vnd.ms-project",
"docm" => "application/vnd.ms-word.document.macroenabled.12",
"dotm" => "application/vnd.ms-word.template.macroenabled.12",
"wps" => "application/vnd.ms-works",
"wks" => "application/vnd.ms-works",
"wcm" => "application/vnd.ms-works",
"wdb" => "application/vnd.ms-works",
"wpl" => "application/vnd.ms-wpl",
"xps" => "application/vnd.ms-xpsdocument",
"mseq" => "application/vnd.mseq",
"mus" => "application/vnd.musician",
"msty" => "application/vnd.muvee.style",
"taglet" => "application/vnd.mynfc",
"nlu" => "application/vnd.neurolanguage.nlu",
"ntf" => "application/vnd.nitf",
"nitf" => "application/vnd.nitf",
"nnd" => "application/vnd.noblenet-directory",
"nns" => "application/vnd.noblenet-sealer",
"nnw" => "application/vnd.noblenet-web",
"ngdat" => "application/vnd.nokia.n-gage.data",
"n- =>age", "application/vnd.nokia.n-gage.symbian.install",
"rpst" => "application/vnd.nokia.radio-preset",
"rpss" => "application/vnd.nokia.radio-presets",
"edm" => "application/vnd.novadigm.edm",
"edx" => "application/vnd.novadigm.edx",
"ext" => "application/vnd.novadigm.ext",
"odc" => "application/vnd.oasis.opendocument.chart",
"otc" => "application/vnd.oasis.opendocument.chart-template",
"odb" => "application/vnd.oasis.opendocument.database",
"odf" => "application/vnd.oasis.opendocument.formula",
"odft" => "application/vnd.oasis.opendocument.formula-template",
"odg" => "application/vnd.oasis.opendocument.graphics",
"otg" => "application/vnd.oasis.opendocument.graphics-template",
"odi" => "application/vnd.oasis.opendocument.image",
"oti" => "application/vnd.oasis.opendocument.image-template",
"odp" => "application/vnd.oasis.opendocument.presentation",
"otp" => "application/vnd.oasis.opendocument.presentation-template",
"ods" => "application/vnd.oasis.opendocument.spreadsheet",
"ots" => "application/vnd.oasis.opendocument.spreadsheet-template",
"odt" => "application/vnd.oasis.opendocument.text",
"odm" => "application/vnd.oasis.opendocument.text-master",
"ott" => "application/vnd.oasis.opendocument.text-template",
"oth" => "application/vnd.oasis.opendocument.text-web",
"xo" => "application/vnd.olpc-sugar",
"dd2" => "application/vnd.oma.dd2+xml",
"oxt" => "application/vnd.openofficeorg.extension",
"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"sldx" => "application/vnd.openxmlformats-officedocument.presentationml.slide",
"ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
"potx" => "application/vnd.openxmlformats-officedocument.presentationml.template",
"xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
"mgp" => "application/vnd.osgeo.mapguide.package",
"dp" => "application/vnd.osgi.dp",
"esa" => "application/vnd.osgi.subsystem",
"pdb" => "application/vnd.palm",
"pqa" => "application/vnd.palm",
"oprc" => "application/vnd.palm",
"paw" => "application/vnd.pawaafile",
"str" => "application/vnd.pg.format",
"ei6" => "application/vnd.pg.osasli",
"efif" => "application/vnd.picsel",
"wg" => "application/vnd.pmi.widget",
"plf" => "application/vnd.pocketlearn",
"pbd" => "application/vnd.powerbuilder6",
"box" => "application/vnd.previewsystems.box",
"mgz" => "application/vnd.proteus.magazine",
"qps" => "application/vnd.publishare-delta-tree",
"ptid" => "application/vnd.pvi.ptid1",
"qxd" => "application/vnd.quark.quarkxpress",
"qxt" => "application/vnd.quark.quarkxpress",
"qwd" => "application/vnd.quark.quarkxpress",
"qwt" => "application/vnd.quark.quarkxpress",
"qxl" => "application/vnd.quark.quarkxpress",
"qxb" => "application/vnd.quark.quarkxpress",
"bed" => "application/vnd.realvnc.bed",
"mxl" => "application/vnd.recordare.musicxml",
"musicxml" => "application/vnd.recordare.musicxml+xml",
"cryptonote" => "application/vnd.rig.cryptonote",
"cod" => "application/vnd.rim.cod",
"rm" => "application/vnd.rn-realmedia",
"rmvb" => "application/vnd.rn-realmedia-vbr",
"link66" => "application/vnd.route66.link66+xml",
"st" => "application/vnd.sailingtracker.track",
"see" => "application/vnd.seemail",
"sema" => "application/vnd.sema",
"semd" => "application/vnd.semd",
"semf" => "application/vnd.semf",
"ifm" => "application/vnd.shana.informed.formdata",
"itp" => "application/vnd.shana.informed.formtemplate",
"iif" => "application/vnd.shana.informed.interchange",
"ipk" => "application/vnd.shana.informed.package",
"twd" => "application/vnd.simtech-mindmapper",
"twds" => "application/vnd.simtech-mindmapper",
"mmf" => "application/vnd.smaf",
"teacher" => "application/vnd.smart.teacher",
"sdkm" => "application/vnd.solent.sdkm+xml",
"sdkd" => "application/vnd.solent.sdkm+xml",
"dxp" => "application/vnd.spotfire.dxp",
"sfs" => "application/vnd.spotfire.sfs",
"sdc" => "application/vnd.stardivision.calc",
"sda" => "application/vnd.stardivision.draw",
"sdd" => "application/vnd.stardivision.impress",
"smf" => "application/vnd.stardivision.math",
"sdw" => "application/vnd.stardivision.writer",
"vor" => "application/vnd.stardivision.writer",
"sgl" => "application/vnd.stardivision.writer-global",
"smzip" => "application/vnd.stepmania.package",
"sm" => "application/vnd.stepmania.stepchart",
"sxc" => "application/vnd.sun.xml.calc",
"stc" => "application/vnd.sun.xml.calc.template",
"sxd" => "application/vnd.sun.xml.draw",
"std" => "application/vnd.sun.xml.draw.template",
"sxi" => "application/vnd.sun.xml.impress",
"sti" => "application/vnd.sun.xml.impress.template",
"sxm" => "application/vnd.sun.xml.math",
"sxw" => "application/vnd.sun.xml.writer",
"sxg" => "application/vnd.sun.xml.writer.global",
"stw" => "application/vnd.sun.xml.writer.template",
"sus" => "application/vnd.sus-calendar",
"susp" => "application/vnd.sus-calendar",
"svd" => "application/vnd.svd",
"sis" => "application/vnd.symbian.install",
"sisx" => "application/vnd.symbian.install",
"xsm" => "application/vnd.syncml+xml",
"bdm" => "application/vnd.syncml.dm+wbxml",
"xdm" => "application/vnd.syncml.dm+xml",
"tao" => "application/vnd.tao.intent-module-archive",
"pcap" => "application/vnd.tcpdump.pcap",
"cap" => "application/vnd.tcpdump.pcap",
"dmp" => "application/vnd.tcpdump.pcap",
"tmo" => "application/vnd.tmobile-livetv",
"tpt" => "application/vnd.trid.tpt",
"mxs" => "application/vnd.triscape.mxs",
"tra" => "application/vnd.trueapp",
"ufd" => "application/vnd.ufdl",
"ufdl" => "application/vnd.ufdl",
"utz" => "application/vnd.uiq.theme",
"umj" => "application/vnd.umajin",
"unityweb" => "application/vnd.unity",
"uoml" => "application/vnd.uoml+xml",
"vcx" => "application/vnd.vcx",
"vsd" => "application/vnd.visio",
"vst" => "application/vnd.visio",
"vss" => "application/vnd.visio",
"vsw" => "application/vnd.visio",
"vis" => "application/vnd.visionary",
"vsf" => "application/vnd.vsf",
"wbxml" => "application/vnd.wap.wbxml",
"wmlc" => "application/vnd.wap.wmlc",
"wmlsc" => "application/vnd.wap.wmlscriptc",
"wtb" => "application/vnd.webturbo",
"nbp" => "application/vnd.wolfram.player",
"wpd" => "application/vnd.wordperfect",
"wqd" => "application/vnd.wqd",
"stf" => "application/vnd.wt.stf",
"xar" => "application/vnd.xara",
"xfdl" => "application/vnd.xfdl",
"hvd" => "application/vnd.yamaha.hv-dic",
"hvs" => "application/vnd.yamaha.hv-script",
"hvp" => "application/vnd.yamaha.hv-voice",
"osf" => "application/vnd.yamaha.openscoreformat",
"osfpvg" => "application/vnd.yamaha.openscoreformat.osfpvg+xml",
"saf" => "application/vnd.yamaha.smaf-audio",
"spf" => "application/vnd.yamaha.smaf-phrase",
"cmp" => "application/vnd.yellowriver-custom-menu",
"zir" => "application/vnd.zul",
"zirz" => "application/vnd.zul",
"zaz" => "application/vnd.zzazz.deck+xml",
"vxml" => "application/voicexml+xml",
"wgt" => "application/widget",
"hlp" => "application/winhlp",
"wsdl" => "application/wsdl+xml",
"wspolicy" => "application/wspolicy+xml",
"7z" => "application/x-7z-compressed",
"abw" => "application/x-abiword",
"ace" => "application/x-ace-compressed",
"dmg" => "application/x-apple-diskimage",
"aab" => "application/x-authorware-bin",
"x32" => "application/x-authorware-bin",
"u32" => "application/x-authorware-bin",
"vox" => "application/x-authorware-bin",
"aam" => "application/x-authorware-map",
"aas" => "application/x-authorware-seg",
"bcpio" => "application/x-bcpio",
"torrent" => "application/x-bittorrent",
"blb" => "application/x-blorb",
"blorb" => "application/x-blorb",
"bz" => "application/x-bzip",
"bz2" => "application/x-bzip2",
"boz" => "application/x-bzip2",
"cbr" => "application/x-cbr",
"cba" => "application/x-cbr",
"cbt" => "application/x-cbr",
"cbz" => "application/x-cbr",
"cb7" => "application/x-cbr",
"vcd" => "application/x-cdlink",
"cfs" => "application/x-cfs-compressed",
"chat" => "application/x-chat",
"pgn" => "application/x-chess-pgn",
"nsc" => "application/x-conference",
"cpio" => "application/x-cpio",
"csh" => "application/x-csh",
"deb" => "application/x-debian-package",
"udeb" => "application/x-debian-package",
"dgc" => "application/x-dgc-compressed",
"dir" => "application/x-director",
"dcr" => "application/x-director",
"dxr" => "application/x-director",
"cst" => "application/x-director",
"cct" => "application/x-director",
"cxt" => "application/x-director",
"w3d" => "application/x-director",
"fgd" => "application/x-director",
"swa" => "application/x-director",
"wad" => "application/x-doom",
"ncx" => "application/x-dtbncx+xml",
"dtb" => "application/x-dtbook+xml",
"res" => "application/x-dtbresource+xml",
"dvi" => "application/x-dvi",
"evy" => "application/x-envoy",
"eva" => "application/x-eva",
"bdf" => "application/x-font-bdf",
"gsf" => "application/x-font-ghostscript",
"psf" => "application/x-font-linux-psf",
"otf" => "application/x-font-otf",
"pcf" => "application/x-font-pcf",
"snf" => "application/x-font-snf",
"ttf" => "application/x-font-ttf",
"ttc" => "application/x-font-ttf",
"pfa" => "application/x-font-type1",
"pfb" => "application/x-font-type1",
"pfm" => "application/x-font-type1",
"afm" => "application/x-font-type1",
"woff" => "application/font-woff",
"woff2" => "application/font-woff2",
"arc" => "application/x-freearc",
"spl" => "application/x-futuresplash",
"gca" => "application/x-gca-compressed",
"ulx" => "application/x-glulx",
"gnumeric" => "application/x-gnumeric",
"gramps" => "application/x-gramps-xml",
"gtar" => "application/x-gtar",
"hdf" => "application/x-hdf",
"install" => "application/x-install-instructions",
"iso" => "application/x-iso9660-image",
"jnlp" => "application/x-java-jnlp-file",
"latex" => "application/x-latex",
"lzh" => "application/x-lzh-compressed",
"lha" => "application/x-lzh-compressed",
"mie" => "application/x-mie",
"prc" => "application/x-mobipocket-ebook",
"mobi" => "application/x-mobipocket-ebook",
"application" => "application/x-ms-application",
"lnk" => "application/x-ms-shortcut",
"wmd" => "application/x-ms-wmd",
"wmz" => "application/x-msmetafile",
"xbap" => "application/x-ms-xbap",
"mdb" => "application/x-msaccess",
"obd" => "application/x-msbinder",
"crd" => "application/x-mscardfile",
"clp" => "application/x-msclip",
"exe" => "application/x-msdownload",
"dll" => "application/x-msdownload",
"com" => "application/x-msdownload",
"bat" => "application/x-msdownload",
"msi" => "application/x-msdownload",
"mvb" => "application/x-msmediaview",
"m13" => "application/x-msmediaview",
"m14" => "application/x-msmediaview",
"wmf" => "application/x-msmetafile",
"emf" => "application/x-msmetafile",
"emz" => "application/x-msmetafile",
"mny" => "application/x-msmoney",
"pub" => "application/x-mspublisher",
"scd" => "application/x-msschedule",
"trm" => "application/x-msterminal",
"wri" => "application/x-mswrite",
"nc" => "application/x-netcdf",
"cdf" => "application/x-netcdf",
"nzb" => "application/x-nzb",
"p12" => "application/x-pkcs12",
"pfx" => "application/x-pkcs12",
"p7b" => "application/x-pkcs7-certificates",
"spc" => "application/x-pkcs7-certificates",
"p7r" => "application/x-pkcs7-certreqresp",
"rar" => "application/x-rar-compressed",
"ris" => "application/x-research-info-systems",
"sh" => "application/x-sh",
"shar" => "application/x-shar",
"swf" => "application/x-shockwave-flash",
"xap" => "application/x-silverlight-app",
"sql" => "application/x-sql",
"sit" => "application/x-stuffit",
"sitx" => "application/x-stuffitx",
"srt" => "application/x-subrip",
"sv4cpio" => "application/x-sv4cpio",
"sv4crc" => "application/x-sv4crc",
"t3" => "application/x-t3vm-image",
"gam" => "application/x-tads",
"tar" => "application/x-tar",
"tcl" => "application/x-tcl",
"tex" => "application/x-tex",
"tfm" => "application/x-tex-tfm",
"texinfo" => "application/x-texinfo",
"texi" => "application/x-texinfo",
"obj" => "application/x-tgif",
"ustar" => "application/x-ustar",
"src" => "application/x-wais-source",
"der" => "application/x-x509-ca-cert",
"crt" => "application/x-x509-ca-cert",
"fig" => "application/x-xfig",
"xlf" => "application/x-xliff+xml",
"xpi" => "application/x-xpinstall",
"xz" => "application/x-xz",
"z1" => "application/x-zmachine",
"z2" => "application/x-zmachine",
"z3" => "application/x-zmachine",
"z4" => "application/x-zmachine",
"z5" => "application/x-zmachine",
"z6" => "application/x-zmachine",
"z7" => "application/x-zmachine",
"z8" => "application/x-zmachine",
"xaml" => "application/xaml+xml",
"xdf" => "application/xcap-diff+xml",
"xenc" => "application/xenc+xml",
"xhtml" => "application/xhtml+xml",
"xht" => "application/xhtml+xml",
"xml" => "application/xml",
"xsl" => "application/xml",
"dtd" => "application/xml-dtd",
"xop" => "application/xop+xml",
"xpl" => "application/xproc+xml",
"xslt" => "application/xslt+xml",
"xspf" => "application/xspf+xml",
"mxml" => "application/xv+xml",
"xhvml" => "application/xv+xml",
"xvml" => "application/xv+xml",
"xvm" => "application/xv+xml",
"yang" => "application/yang",
"yin" => "application/yin+xml",
"zip" => "application/zip",
"adp" => "audio/adpcm",
"au" => "audio/basic",
"snd" => "audio/basic",
"mid" => "audio/midi",
"midi" => "audio/midi",
"kar" => "audio/midi",
"rmi" => "audio/midi",
"mp4a" => "audio/mp4",
"mpga" => "audio/mpeg",
"mp2" => "audio/mpeg",
"mp2a" => "audio/mpeg",
"mp3" => "audio/mpeg",
"m2a" => "audio/mpeg",
"m3a" => "audio/mpeg",
"oga" => "audio/ogg",
"ogg" => "audio/ogg",
"spx" => "audio/ogg",
"s3m" => "audio/s3m",
"sil" => "audio/silk",
"uva" => "audio/vnd.dece.audio",
"uvva" => "audio/vnd.dece.audio",
"eol" => "audio/vnd.digital-winds",
"dra" => "audio/vnd.dra",
"dts" => "audio/vnd.dts",
"dtshd" => "audio/vnd.dts.hd",
"lvp" => "audio/vnd.lucent.voice",
"pya" => "audio/vnd.ms-playready.media.pya",
"ecelp4800" => "audio/vnd.nuera.ecelp4800",
"ecelp7470" => "audio/vnd.nuera.ecelp7470",
"ecelp9600" => "audio/vnd.nuera.ecelp9600",
"rip" => "audio/vnd.rip",
"weba" => "audio/webm",
"aac" => "audio/x-aac",
"aif" => "audio/x-aiff",
"aiff" => "audio/x-aiff",
"aifc" => "audio/x-aiff",
"caf" => "audio/x-caf",
"flac" => "audio/x-flac",
"mka" => "audio/x-matroska",
"m3u" => "audio/x-mpegurl",
"wax" => "audio/x-ms-wax",
"wma" => "audio/x-ms-wma",
"ram" => "audio/x-pn-realaudio",
"ra" => "audio/x-pn-realaudio",
"rmp" => "audio/x-pn-realaudio-plugin",
"wav" => "audio/x-wav",
"xm" => "audio/xm",
"cdx" => "chemical/x-cdx",
"cif" => "chemical/x-cif",
"cmdf" => "chemical/x-cmdf",
"cml" => "chemical/x-cml",
"csml" => "chemical/x-csml",
"xyz" => "chemical/x-xyz",
"bmp" => "image/bmp",
"cgm" => "image/cgm",
"g3" => "image/g3fax",
"gif" => "image/gif",
"ief" => "image/ief",
"jpeg" => "image/jpeg",
"jpg" => "image/jpeg",
"jpe" => "image/jpeg",
"ktx" => "image/ktx",
"png" => "image/png",
"btif" => "image/prs.btif",
"sgi" => "image/sgi",
"svg" => "image/svg+xml",
"svgz" => "image/svg+xml",
"tiff" => "image/tiff",
"tif" => "image/tiff",
"psd" => "image/vnd.adobe.photoshop",
"uvi" => "image/vnd.dece.graphic",
"uvvi" => "image/vnd.dece.graphic",
"uvg" => "image/vnd.dece.graphic",
"uvvg" => "image/vnd.dece.graphic",
"sub" => "text/vnd.dvb.subtitle",
"djvu" => "image/vnd.djvu",
"djv" => "image/vnd.djvu",
"dwg" => "image/vnd.dwg",
"dxf" => "image/vnd.dxf",
"fbs" => "image/vnd.fastbidsheet",
"fpx" => "image/vnd.fpx",
"fst" => "image/vnd.fst",
"mmr" => "image/vnd.fujixerox.edmics-mmr",
"rlc" => "image/vnd.fujixerox.edmics-rlc",
"mdi" => "image/vnd.ms-modi",
"wdp" => "image/vnd.ms-photo",
"npx" => "image/vnd.net-fpx",
"wbmp" => "image/vnd.wap.wbmp",
"xif" => "image/vnd.xiff",
"webp" => "image/webp",
"3ds" => "image/x-3ds",
"ras" => "image/x-cmu-raster",
"cmx" => "image/x-cmx",
"fh" => "image/x-freehand",
"fhc" => "image/x-freehand",
"fh4" => "image/x-freehand",
"fh5" => "image/x-freehand",
"fh7" => "image/x-freehand",
"ico" => "image/x-icon",
"sid" => "image/x-mrsid-image",
"pcx" => "image/x-pcx",
"pic" => "image/x-pict",
"pct" => "image/x-pict",
"pnm" => "image/x-portable-anymap",
"pbm" => "image/x-portable-bitmap",
"pgm" => "image/x-portable-graymap",
"ppm" => "image/x-portable-pixmap",
"rgb" => "image/x-rgb",
"tga" => "image/x-tga",
"xbm" => "image/x-xbitmap",
"xpm" => "image/x-xpixmap",
"xwd" => "image/x-xwindowdump",
"eml" => "message/rfc822",
"mime" => "message/rfc822",
"igs" => "model/iges",
"iges" => "model/iges",
"msh" => "model/mesh",
"mesh" => "model/mesh",
"silo" => "model/mesh",
"dae" => "model/vnd.collada+xml",
"dwf" => "model/vnd.dwf",
"gdl" => "model/vnd.gdl",
"gtw" => "model/vnd.gtw",
"mts" => "model/vnd.mts",
"vtu" => "model/vnd.vtu",
"wrl" => "model/vrml",
"vrml" => "model/vrml",
"x3db" => "model/x3d+binary",
"x3dbz" => "model/x3d+binary",
"x3dv" => "model/x3d+vrml",
"x3dvz" => "model/x3d+vrml",
"x3d" => "model/x3d+xml",
"x3dz" => "model/x3d+xml",
"appcache" => "text/cache-manifest",
"ics" => "text/calendar",
"ifb" => "text/calendar",
"css" => "text/css",
"csv" => "text/csv",
"html" => "text/html",
"htm" => "text/html",
"n3" => "text/n3",
"txt" => "text/plain",
"text" => "text/plain",
"conf" => "text/plain",
"def" => "text/plain",
"list" => "text/plain",
"log" => "text/plain",
"in" => "text/plain",
"dsc" => "text/prs.lines.tag",
"rtx" => "text/richtext",
"sgml" => "text/sgml",
"sgm" => "text/sgml",
"tsv" => "text/tab-separated-values",
"t" => "text/troff",
"tr" => "text/troff",
"roff" => "text/troff",
"man" => "text/troff",
"me" => "text/troff",
"ms" => "text/troff",
"ttl" => "text/turtle",
"uri" => "text/uri-list",
"uris" => "text/uri-list",
"urls" => "text/uri-list",
"vcard" => "text/vcard",
"curl" => "text/vnd.curl",
"dcurl" => "text/vnd.curl.dcurl",
"scurl" => "text/vnd.curl.scurl",
"mcurl" => "text/vnd.curl.mcurl",
"fly" => "text/vnd.fly",
"flx" => "text/vnd.fmi.flexstor",
"gv" => "text/vnd.graphviz",
"3dml" => "text/vnd.in3d.3dml",
"spot" => "text/vnd.in3d.spot",
"jad" => "text/vnd.sun.j2me.app-descriptor",
"wml" => "text/vnd.wap.wml",
"wmls" => "text/vnd.wap.wmlscript",
"s" => "text/x-asm",
"asm" => "text/x-asm",
"c" => "text/x-c",
"cc" => "text/x-c",
"cxx" => "text/x-c",
"cpp" => "text/x-c",
"h" => "text/x-c",
"hh" => "text/x-c",
"dic" => "text/x-c",
"f" => "text/x-fortran",
"for" => "text/x-fortran",
"f77" => "text/x-fortran",
"f90" => "text/x-fortran",
"java" => "text/x-java-source",
"opml" => "text/x-opml",
"p" => "text/x-pascal",
"pas" => "text/x-pascal",
"nfo" => "text/x-nfo",
"etx" => "text/x-setext",
"sfv" => "text/x-sfv",
"uu" => "text/x-uuencode",
"vcs" => "text/x-vcalendar",
"vcf" => "text/x-vcard",
"3gp" => "video/3gpp",
"3g2" => "video/3gpp2",
"h261" => "video/h261",
"h263" => "video/h263",
"h264" => "video/h264",
"jpgv" => "video/jpeg",
"jpm" => "video/jpm",
"jpgm" => "video/jpm",
"mj2" => "video/mj2",
"mjp2" => "video/mj2",
"mp4" => "video/mp4",
"mp4v" => "video/mp4",
"mpg4" => "video/mp4",
"mpeg" => "video/mpeg",
"mpg" => "video/mpeg",
"mpe" => "video/mpeg",
"m1v" => "video/mpeg",
"m2v" => "video/mpeg",
"ogv" => "video/ogg",
"qt" => "video/quicktime",
"mov" => "video/quicktime",
"uvh" => "video/vnd.dece.hd",
"uvvh" => "video/vnd.dece.hd",
"uvm" => "video/vnd.dece.mobile",
"uvvm" => "video/vnd.dece.mobile",
"uvp" => "video/vnd.dece.pd",
"uvvp" => "video/vnd.dece.pd",
"uvs" => "video/vnd.dece.sd",
"uvvs" => "video/vnd.dece.sd",
"uvv" => "video/vnd.dece.video",
"uvvv" => "video/vnd.dece.video",
"dvb" => "video/vnd.dvb.file",
"fvt" => "video/vnd.fvt",
"mxu" => "video/vnd.mpegurl",
"m4u" => "video/vnd.mpegurl",
"pyv" => "video/vnd.ms-playready.media.pyv",
"uvu" => "video/vnd.uvvu.mp4",
"uvvu" => "video/vnd.uvvu.mp4",
"viv" => "video/vnd.vivo",
"webm" => "video/webm",
"f4v" => "video/x-f4v",
"fli" => "video/x-fli",
"flv" => "video/x-flv",
"m4v" => "video/x-m4v",
"mkv" => "video/x-matroska",
"mk3d" => "video/x-matroska",
"mks" => "video/x-matroska",
"mng" => "video/x-mng",
"asf" => "video/x-ms-asf",
"asx" => "video/x-ms-asf",
"vob" => "video/x-ms-vob",
"wm" => "video/x-ms-wm",
"wmv" => "video/x-ms-wmv",
"wmx" => "video/x-ms-wmx",
"wvx" => "video/x-ms-wvx",
"avi" => "video/x-msvideo",
"movie" => "video/x-sgi-movie",
"smv" => "video/x-smv",
"ice" => "x-conference/x-cooltalk",
"map" => "application/json",
"hbs" => "text/html",
"mustache" => "text/html",
];

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env bash
# Install Homebrew for dependency management
if [[ ! $(which brew -A) ]]
then
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi
brew install wget > /dev/null 2>&1
brew install jq > /dev/null 2>&1
# Install PHP 7.0
brew tap homebrew/dupes
brew tap homebrew/versions
brew tap homebrew/homebrew-php
brew unlink php56 > /dev/null 2>&1
brew install php70
# Install Composer to /usr/local/bin
if [[ ! $(which composer -A) ]]
then
echo "Installing Composer..."
/usr/local/bin/php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
/usr/local/bin/php -r "if (hash_file('SHA384', 'composer-setup.php') === '92102166af5abdb03f49ce52a40591073a7b859a86e8ff13338cf7db58a19f7844fbc0bb79b2773bf30791e935dbd938') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" > /dev/null 2>&1
/usr/local/bin/php composer-setup.php > /dev/null 2>&1
/usr/local/bin/php -r "unlink('composer-setup.php');"
mv composer.phar /usr/local/bin/composer
chmod +x /usr/local/bin/composer
fi
COMPOSER_PATH=$(which composer)
# Download and unpack the latest Valet release
rm -rf $HOME/.valet-cli
mkdir $HOME/.valet-cli
echo "Downloading Valet..."
TARBALL=$(curl -s https://api.github.com/repos/laravel/valet/releases/latest | jq ".tarball_url")
TARBALL=$(echo $TARBALL | sed -e 's/^"//' -e 's/"$//')
wget --max-redirect=10 $TARBALL -O $HOME/.valet-cli/valet.tar.gz > /dev/null 2>&1
tar xvzf $HOME/.valet-cli/valet.tar.gz -C $HOME/.valet-cli --strip 1 > /dev/null 2>&1
# Install Valet to /usr/local/bin
rm /usr/local/bin/valet
ln -s $HOME/.valet-cli/valet /usr/local/bin/valet
chmod +x /usr/local/bin/valet
# Install Valet's Composer dependencies
echo "Installing Valet's Composer dependencies..."
/usr/local/bin/php $COMPOSER_PATH install -d $HOME/.valet-cli > /dev/null 2>&1
# Run the Valet server installation process
/usr/local/bin/valet install

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env bash
# Determine if this is the latest Valet release
LATEST=$($HOME/.valet-cli/valet on-latest-version)
if [[ "$LATEST" = "YES" ]]
then
echo "You are already using the latest version of Valet."
exit
fi
# Remove existing Valet directory
rm -rf $HOME/.valet-cli
# Download and unpack the latest Valet release
mkdir $HOME/.valet-cli
echo "Downloading latest release of Valet..."
TARBALL=$(curl -s https://api.github.com/repos/laravel/valet/releases/latest | jq ".tarball_url")
TARBALL=$(echo $TARBALL | sed -e 's/^"//' -e 's/"$//')
wget --max-redirect=10 $TARBALL -O $HOME/.valet-cli/valet.tar.gz > /dev/null 2>&1
tar xvzf $HOME/.valet-cli/valet.tar.gz -C $HOME/.valet-cli --strip 1 > /dev/null 2>&1
# Install Valet's Composer dependencies
echo "Installing Valet's Composer dependencies..."
/usr/local/bin/php /usr/local/bin/composer install -d $HOME/.valet-cli > /dev/null 2>&1
# Run the Valet installation process
/usr/local/bin/valet install
# Display the new Valet version
$HOME/.valet-cli/valet --version

View File

@@ -1,11 +0,0 @@
import VALET_HOME_PATH/Caddy/*
:80 {
fastcgi / 127.0.0.1:9000 php {
index server.php
}
rewrite {
to /server.php?{query}
}
}

View File

@@ -1,15 +0,0 @@
http://VALET_SITE:80 {
redir https://{host}{uri}
}
https://VALET_SITE:443 {
tls VALET_CERT VALET_KEY
fastcgi / 127.0.0.1:9000 php {
index server.php
}
rewrite {
to /server.php?{query}
}
}

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.laravel.valetServer</string>
<key>WorkingDirectory</key>
<string>VALET_PATH</string>
<key>ProgramArguments</key>
<array>
<string>./bin/caddy</string>
<string>--conf=VALET_HOME_PATH/Caddyfile</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/com.laravel.valetServer.err</string>
</dict>
</plist>

20
cli/stubs/fastcgi_params Normal file
View File

@@ -0,0 +1,20 @@
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_param HTTP_PROXY "";

41
cli/stubs/nginx.conf Normal file
View File

@@ -0,0 +1,41 @@
user VALET_USER staff;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
include VALET_HOME_PATH/Nginx/*;
include servers/*;
include valet/valet.conf;
}

View File

@@ -0,0 +1,45 @@
server {
listen 80;
server_name VALET_SITE;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name VALET_SITE;
root /;
charset utf-8;
location /VALET_STATIC_PREFIX/ {
internal;
alias /;
try_files $uri $uri/;
}
ssl_certificate VALET_CERT;
ssl_certificate_key VALET_KEY;
location / {
rewrite ^ VALET_SERVER_PATH?$query_string last;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log VALET_HOME_PATH/Log/nginx-error.log;
error_page 404 VALET_SERVER_PATH;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:VALET_HOME_PATH/valet.sock;
fastcgi_index VALET_SERVER_PATH;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME VALET_SERVER_PATH;
}
location ~ /\.ht {
deny all;
}
}

36
cli/stubs/valet.conf Normal file
View File

@@ -0,0 +1,36 @@
server {
listen 80 default_server;
root /;
charset utf-8;
client_max_body_size 128M;
location /VALET_STATIC_PREFIX/ {
internal;
alias /;
try_files $uri $uri/;
}
location / {
rewrite ^ VALET_SERVER_PATH last;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log VALET_HOME_PATH/Log/nginx-error.log;
error_page 404 VALET_SERVER_PATH;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:VALET_HOME_PATH/valet.sock;
fastcgi_index VALET_SERVER_PATH;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME VALET_SERVER_PATH;
}
location ~ /\.ht {
deny all;
}
}

View File

@@ -18,7 +18,7 @@
*/
Container::setInstance(new Container);
$version = '1.1.13';
$version = '2.0.3';
$app = new Application('Laravel Valet', $version);
@@ -35,13 +35,13 @@
* Allow Valet to be run more conveniently by allowing the Node proxy to run password-less sudo.
*/
$app->command('install', function () {
Caddy::stop();
Nginx::stop();
Configuration::install();
Caddy::install();
Nginx::install();
PhpFpm::install();
DnsMasq::install();
Caddy::restart();
Nginx::restart();
Valet::symlinkToUsersBin();
Brew::createSudoersEntry();
Valet::createSudoersEntry();
@@ -65,7 +65,7 @@
Site::resecureForNewDomain($oldDomain, $domain);
PhpFpm::restart();
Caddy::restart();
Nginx::restart();
info('Your Valet domain has been updated to ['.$domain.'].');
})->descriptions('Get or set the domain used for Valet sites');
@@ -73,20 +73,20 @@
/**
* Add the current working directory to the paths configuration.
*/
$app->command('park', function () {
Configuration::addPath(getcwd());
$app->command('park [path]', function ($path = null) {
Configuration::addPath($path ?: getcwd());
info("This directory has been added to Valet's paths.");
})->descriptions('Register the current working directory with Valet');
info(($path === null ? "This" : "The [{$path}]") . " directory has been added to Valet's paths.");
})->descriptions('Register the current working (or specified) directory with Valet');
/**
* Remove the current working directory to the paths configuration.
* Remove the current working directory from the paths configuration.
*/
$app->command('forget', function () {
Configuration::removePath(getcwd());
$app->command('forget [path]', function ($path = null) {
Configuration::removePath($path ?: getcwd());
info("This directory has been removed from Valet's paths.");
})->descriptions('Remove the current working directory from Valet\'s list of paths');
info(($path === null ? "This" : "The [{$path}]") . " directory has been removed from Valet's paths.");
})->descriptions('Remove the current working (or specified) directory from Valet\'s list of paths');
/**
* Register a symbolic link with Valet.
@@ -123,11 +123,14 @@
PhpFpm::restart();
Caddy::restart();
Nginx::restart();
info('The ['.$url.'] site has been secured with a fresh TLS certificate.');
});
})->descriptions('Secure the given domain with a trusted TLS certificate');
/**
* Stop serving the given domain over HTTPS and remove the trusted TLS certificate.
*/
$app->command('unsecure [domain]', function ($domain = null) {
$url = ($domain ?: Site::host(getcwd())).'.'.Configuration::read()['domain'];
@@ -135,10 +138,10 @@
PhpFpm::restart();
Caddy::restart();
Nginx::restart();
info('The ['.$url.'] site will now serve traffic over HTTP.');
});
})->descriptions('Stop serving the given domain over HTTPS and remove the trusted TLS certificate');
/**
* Determine which Valet driver the current directory is using.
@@ -155,23 +158,6 @@
}
})->descriptions('Determine which Valet driver serves the current working directory');
/**
* Stream all of the logs for all sites.
*/
$app->command('logs', function () {
$files = Site::logs(Configuration::read()['paths']);
$files = collect($files)->transform(function ($file) {
return escapeshellarg($file);
})->all();
if (count($files) > 0) {
passthru('tail -f '.implode(' ', $files));
} else {
warning('No log files were found.');
}
})->descriptions('Stream all of the logs for all Laravel sites registered with Valet');
/**
* Display all of the registered paths.
*/
@@ -194,6 +180,13 @@
passthru("open ".escapeshellarg($url));
})->descriptions('Open the site for the current directory in your browser');
/**
* Generate a publicly accessible URL for your project.
*/
$app->command('share', function () {
warning("It looks like you are running `cli/valet.php` directly, please use the `valet` script in the project root instead.");
})->descriptions('Generate a publicly accessible URL for your project');
/**
* Echo the currently tunneled URL.
*/
@@ -207,7 +200,7 @@
$app->command('start', function () {
PhpFpm::restart();
Caddy::restart();
Nginx::restart();
info('Valet services have been started.');
})->descriptions('Start the Valet services');
@@ -218,7 +211,7 @@
$app->command('restart', function () {
PhpFpm::restart();
Caddy::restart();
Nginx::restart();
info('Valet services have been restarted.');
})->descriptions('Restart the Valet services');
@@ -229,7 +222,7 @@
$app->command('stop', function () {
PhpFpm::stop();
Caddy::stop();
Nginx::stop();
info('Valet services have been stopped.');
})->descriptions('Stop the Valet services');
@@ -238,7 +231,7 @@
* Uninstall Valet entirely.
*/
$app->command('uninstall', function () {
Caddy::uninstall();
Nginx::uninstall();
info('Valet has been uninstalled.');
})->descriptions('Uninstall the Valet services');

View File

@@ -6,7 +6,7 @@
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
"email": "taylor@laravel.com"
},
{
"name": "Adam Wathan",

View File

@@ -1,6 +1,6 @@
# Laravel Valet
[![Build Status](https://travis-ci.org/laravel/valet.svg)](https://travis-ci.org/laravel/valet)
[![Build Status](https://travis-ci.org/laravel/valet.svg?branch=master)](https://travis-ci.org/laravel/valet)
[![Total Downloads](https://poser.pugx.org/laravel/valet/d/total.svg)](https://packagist.org/packages/laravel/valet)
[![Latest Stable Version](https://poser.pugx.org/laravel/valet/v/stable.svg)](https://packagist.org/packages/laravel/valet)
[![Latest Unstable Version](https://poser.pugx.org/laravel/valet/v/unstable.svg)](https://packagist.org/packages/laravel/valet)
@@ -8,15 +8,33 @@ # Laravel Valet
## Introduction
Valet is a Laravel development environment for Mac minimalists. No Vagrant, No Apache, No Nginx, No `/etc/hosts` file. You can even share your sites publicly using local tunnels. _Yeah, we like it too._
Valet is a Laravel development environment for Mac minimalists. No Vagrant, no `/etc/hosts` file. You can even share your sites publicly using local tunnels. _Yeah, we like it too._
Laravel Valet configures your Mac to always run [Caddy](https://caddyserver.com/) in the background when your machine starts. Then, using [DnsMasq](https://en.wikipedia.org/wiki/Dnsmasq), Valet proxies all requests on the `*.dev` domain to point to sites installed on your local machine.
Laravel Valet configures your Mac to always run Nginx in the background when your machine starts. Then, using [DnsMasq](https://en.wikipedia.org/wiki/Dnsmasq), Valet proxies all requests on the `*.dev` domain to point to sites installed on your local machine.
In other words, a blazing fast Laravel development environment that uses roughly 7mb of RAM. Valet isn't a complete replacement for Vagrant or Homestead, but provides a great alternative if you want flexible basics, prefer extreme speed, or are working on a machine with a limited amount of RAM.
## Official Documentation
Documentation for Valet can be found on the [Laravel website](http://laravel.com/docs/5.2/valet).
Documentation for Valet can be found on the [Laravel website](https://laravel.com/docs/valet).
## Upgrading To Valet 2.0
Valet 2.0 transitions Valet's underlying web server from Caddy to Nginx. Before upgrading to this version you should run the following commands to stop and uninstall the existing Caddy daemon:
```
valet stop
valet uninstall
```
Next, you should upgrade to the latest version of Valet. Depending on how you installed Valet, this is typically done through Git or Composer. Once the fresh Valet source code has been downloaded, you should run the `install` command:
```
valet install
valet restart
```
After upgrading, it may be necessary to re-park or re-link your sites.
## License

View File

@@ -5,6 +5,7 @@
*/
define('VALET_HOME_PATH', posix_getpwuid(fileowner(__FILE__))['dir'].'/.valet');
define('VALET_STATIC_PREFIX', '41c270e4-5535-4daa-b23e-c269744c2f45');
/**
* Show the Valet 404 "Not Found" page.
@@ -16,6 +17,24 @@ function show_valet_404()
exit;
}
/**
* @param $domain string Domain to filter
*
* @return string Filtered domain (without xip.io feature)
*/
function valet_support_xip_io($domain)
{
if (substr($domain, -7) === '.xip.io') {
// support only ip v4 for now
$domainPart = explode('.', $domain);
if (count($domainPart) > 6) {
$domain = implode('.', array_reverse(array_slice(array_reverse($domainPart), 6)));
}
}
return $domain;
}
/**
* Load the Valet configuration.
*/
@@ -27,11 +46,12 @@ function show_valet_404()
* Parse the URI and site / host for the incoming request.
*/
$uri = urldecode(
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
explode("?", $_SERVER['REQUEST_URI'])[0]
);
$siteName = basename(
$_SERVER['HTTP_HOST'],
// Filter host to support xip.io feature
valet_support_xip_io($_SERVER['HTTP_HOST']),
'.'.$valetConfig['domain']
);
@@ -56,6 +76,8 @@ function show_valet_404()
show_valet_404();
}
$valetSitePath = realpath($valetSitePath);
/**
* Find the appropriate Valet driver for the request.
*/

View File

@@ -30,54 +30,57 @@ public function test_brew_can_be_resolved_from_container()
public function test_installed_returns_true_when_given_formula_is_installed()
{
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('run')->once()->with('brew list | grep php70')->andReturn('php70');
$cli->shouldReceive('runAsUser')->once()->with('brew list | grep php71')->andReturn('php71');
swap(CommandLine::class, $cli);
$this->assertTrue(resolve(Brew::class)->installed('php70'));
$this->assertTrue(resolve(Brew::class)->installed('php71'));
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('run')->once()->with('brew list | grep php70')->andReturn('php70-mcrypt
php70');
$cli->shouldReceive('runAsUser')->once()->with('brew list | grep php71')->andReturn('php71-mcrypt
php71');
swap(CommandLine::class, $cli);
$this->assertTrue(resolve(Brew::class)->installed('php70'));
$this->assertTrue(resolve(Brew::class)->installed('php71'));
}
public function test_installed_returns_false_when_given_formula_is_not_installed()
{
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('run')->once()->with('brew list | grep php70')->andReturn('');
$cli->shouldReceive('runAsUser')->once()->with('brew list | grep php71')->andReturn('');
swap(CommandLine::class, $cli);
$this->assertFalse(resolve(Brew::class)->installed('php70'));
$this->assertFalse(resolve(Brew::class)->installed('php71'));
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('run')->once()->with('brew list | grep php70')->andReturn('php70-mcrypt');
$cli->shouldReceive('runAsUser')->once()->with('brew list | grep php71')->andReturn('php71-mcrypt');
swap(CommandLine::class, $cli);
$this->assertFalse(resolve(Brew::class)->installed('php70'));
$this->assertFalse(resolve(Brew::class)->installed('php71'));
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('run')->once()->with('brew list | grep php70')->andReturn('php70-mcrypt
php70-something-else
$cli->shouldReceive('runAsUser')->once()->with('brew list | grep php71')->andReturn('php71-mcrypt
php71-something-else
php7');
swap(CommandLine::class, $cli);
$this->assertFalse(resolve(Brew::class)->installed('php70'));
$this->assertFalse(resolve(Brew::class)->installed('php71'));
}
public function test_has_installed_php_indicates_if_php_is_installed_via_brew()
{
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
$brew->shouldReceive('installed')->once()->with('php70')->andReturn(true);
$brew->shouldReceive('installed')->once()->with('php71')->andReturn(true);
$brew->shouldReceive('installed')->with('php70')->andReturn(true);
$brew->shouldReceive('installed')->with('php56')->andReturn(true);
$brew->shouldReceive('installed')->with('php55')->andReturn(true);
$this->assertTrue($brew->hasInstalledPhp());
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
$brew->shouldReceive('installed')->once()->with('php70')->andReturn(true);
$brew->shouldReceive('installed')->with('php71')->andReturn(false);
$brew->shouldReceive('installed')->with('php56')->andReturn(false);
$brew->shouldReceive('installed')->with('php55')->andReturn(false);
$this->assertTrue($brew->hasInstalledPhp());
$brew = Mockery::mock(Brew::class.'[installed]', [new CommandLine, new Filesystem]);
$brew->shouldReceive('installed')->once()->with('php71')->andReturn(false);
$brew->shouldReceive('installed')->once()->with('php70')->andReturn(false);
$brew->shouldReceive('installed')->once()->with('php56')->andReturn(false);
$brew->shouldReceive('installed')->once()->with('php55')->andReturn(false);
@@ -88,10 +91,11 @@ public function test_has_installed_php_indicates_if_php_is_installed_via_brew()
public function test_tap_taps_the_given_homebrew_repository()
{
$cli = Mockery::mock(CommandLine::class);
$cli->shouldReceive('passthru')->once()->with('sudo -u '.user().' brew tap php71');
$cli->shouldReceive('passthru')->once()->with('sudo -u '.user().' brew tap php70');
$cli->shouldReceive('passthru')->once()->with('sudo -u '.user().' brew tap php56');
swap(CommandLine::class, $cli);
resolve(Brew::class)->tap('php70', 'php56');
resolve(Brew::class)->tap('php71', 'php70', 'php56');
}
@@ -117,9 +121,9 @@ public function test_linked_php_returns_linked_php_formula_name()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isLink')->once()->with('/usr/local/bin/php')->andReturn(true);
$files->shouldReceive('readLink')->once()->with('/usr/local/bin/php')->andReturn('/test/path/php70/test');
$files->shouldReceive('readLink')->once()->with('/usr/local/bin/php')->andReturn('/test/path/php71/test');
swap(Filesystem::class, $files);
$this->assertSame('php70', resolve(Brew::class)->linkedPhp());
$this->assertSame('php71', resolve(Brew::class)->linkedPhp());
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isLink')->once()->with('/usr/local/bin/php')->andReturn(true);
@@ -170,7 +174,7 @@ public function test_install_or_fail_can_install_taps()
swap(CommandLine::class, $cli);
$brew = Mockery::mock(Brew::class.'[tap]', [$cli, new Filesystem]);
$brew->shouldReceive('tap')->once()->with(['test/tap']);
$brew->installOrFail('dnsmasq', ['test/tap']);
$brew->installOrFail('dnsmasq', [], ['test/tap']);
}

View File

@@ -1,80 +0,0 @@
<?php
use Valet\Caddy;
use Valet\Filesystem;
use Illuminate\Container\Container;
class CaddyTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$_SERVER['SUDO_USER'] = user();
Container::setInstance(new Container);
}
public function tearDown()
{
Mockery::close();
}
public function test_install_caddy_file_places_stub_in_valet_home_directory()
{
$files = Mockery::mock(Filesystem::class.'[putAsUser]');
$files->shouldReceive('putAsUser')->andReturnUsing(function ($path, $contents) {
$this->assertSame(VALET_HOME_PATH.'/Caddyfile', $path);
$this->assertTrue(strpos($contents, 'import '.VALET_HOME_PATH.'/Caddy/*') !== false);
});
swap(Filesystem::class, $files);
$caddy = resolve(Caddy::class);
$caddy->installCaddyFile();
}
public function test_install_caddy_directories_creates_location_for_site_specific_configuration()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Caddy')->andReturn(false);
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH.'/Caddy');
$files->shouldReceive('touchAsUser')->with(VALET_HOME_PATH.'/Caddy/.keep');
swap(Filesystem::class, $files);
$caddy = resolve(Caddy::class);
$caddy->installCaddyDirectory();
}
public function test_caddy_directory_is_never_created_if_it_already_exists()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Caddy')->andReturn(true);
$files->shouldReceive('mkdirAsUser')->never();
$files->shouldReceive('touchAsUser')->with(VALET_HOME_PATH.'/Caddy/.keep');
swap(Filesystem::class, $files);
$caddy = resolve(Caddy::class);
$caddy->installCaddyDirectory();
}
public function test_caddy_daemon_is_placed_in_correct_location()
{
$files = Mockery::mock(Filesystem::class.'[put]');
swap(Filesystem::class, $files);
$caddy = resolve(Caddy::class);
$files->shouldReceive('put')->andReturnUsing(function ($path, $contents) use ($caddy) {
$this->assertSame($caddy->daemonPath, $path);
$this->assertTrue(strpos($contents, VALET_HOME_PATH) !== false);
});
$caddy->installCaddyDaemon();
}
}

View File

@@ -39,6 +39,14 @@ public function test_drivers_directory_is_created_with_sample_driver_if_it_doesn
resolve(Configuration::class)->createDriversDirectory();
}
public function test_log_directory_is_created_with_log_files_if_it_doesnt_exist()
{
$files = Mockery::mock(Filesystem::class.'[ensureDirExists,touch]');
$files->shouldReceive('ensureDirExists')->with(VALET_HOME_PATH.'/Log', user());
$files->shouldReceive('touch')->once();
swap(Filesystem::class, $files);
resolve(Configuration::class)->createLogDirectory();
}
public function test_add_path_adds_a_path_to_the_paths_array_and_removes_duplicates()
{

90
tests/NginxTest.php Normal file
View File

@@ -0,0 +1,90 @@
<?php
use Valet\Site;
use Valet\Nginx;
use Valet\Filesystem;
use Valet\Configuration;
use Illuminate\Container\Container;
class NginxTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$_SERVER['SUDO_USER'] = user();
Container::setInstance(new Container);
}
public function tearDown()
{
Mockery::close();
}
public function test_install_nginx_configuration_places_nginx_base_configuration_in_proper_location()
{
$files = Mockery::mock(Filesystem::class.'[putAsUser]');
$files->shouldReceive('putAsUser')->andReturnUsing(function ($path, $contents) {
$this->assertSame('/usr/local/etc/nginx/nginx.conf', $path);
$this->assertTrue(strpos($contents, 'include '.VALET_HOME_PATH.'/Nginx/*') !== false);
})->once();
swap(Filesystem::class, $files);
$nginx = resolve(Nginx::class);
$nginx->installConfiguration();
}
public function test_install_caddy_directories_creates_location_for_site_specific_configuration()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Nginx')->andReturn(false);
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH.'/Nginx')->once();
$files->shouldReceive('putAsUser')->with(VALET_HOME_PATH.'/Nginx/.keep', "\n")->once();
swap(Filesystem::class, $files);
swap(Configuration::class, Mockery::spy(Configuration::class));
swap(Site::class, Mockery::spy(Site::class));
$nginx = resolve(Nginx::class);
$nginx->installNginxDirectory();
}
public function test_nginx_directory_is_never_created_if_it_already_exists()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Nginx')->andReturn(true);
$files->shouldReceive('mkdirAsUser')->never();
$files->shouldReceive('putAsUser')->with(VALET_HOME_PATH.'/Nginx/.keep', "\n")->once();
swap(Filesystem::class, $files);
swap(Configuration::class, Mockery::spy(Configuration::class));
swap(Site::class, Mockery::spy(Site::class));
$nginx = resolve(Nginx::class);
$nginx->installNginxDirectory();
}
public function test_install_nginx_directories_rewrites_secure_nginx_files()
{
$files = Mockery::mock(Filesystem::class);
$files->shouldReceive('isDir')->with(VALET_HOME_PATH.'/Nginx')->andReturn(false);
$files->shouldReceive('mkdirAsUser')->with(VALET_HOME_PATH.'/Nginx')->once();
$files->shouldReceive('putAsUser')->with(VALET_HOME_PATH.'/Nginx/.keep', "\n")->once();
swap(Filesystem::class, $files);
swap(Configuration::class, $config = Mockery::spy(Configuration::class, ['read' => ['domain' => 'dev']]));
swap(Site::class, $site = Mockery::spy(Site::class));
$nginx = resolve(Nginx::class);
$nginx->installNginxDirectory();
$site->shouldHaveReceived('resecureForNewDomain', ['dev', 'dev']);
}
}

View File

@@ -22,14 +22,14 @@ public function tearDown()
Mockery::close();
}
public function test_update_configuration_replaces_user_and_group_in_config_file()
public function test_fpm_is_configured_with_the_correct_user_group_and_port()
{
copy(__DIR__.'/files/fpm.conf', __DIR__.'/output/fpm.conf');
resolve(StubForUpdatingFpmConfigFiles::class)->updateConfiguration();
$contents = file_get_contents(__DIR__.'/output/fpm.conf');
$this->assertTrue(strpos($contents, 'user = '.user()) !== false);
$this->assertTrue(strpos($contents, 'group = staff') !== false);
$this->assertContains(sprintf("\nuser = %s", user()), $contents);
$this->assertContains("\ngroup = staff", $contents);
$this->assertContains("\nlisten = ".VALET_HOME_PATH."/valet.sock", $contents);
}
}

View File

@@ -64,14 +64,6 @@ public function test_prune_links_removes_broken_symlinks_in_sites_path()
$site->pruneLinks();
$this->assertFileNotExists(__DIR__.'/output/link');
}
public function test_logs_method_returns_array_of_log_files()
{
$logs = resolve(Site::class)->logs([__DIR__.'/test-directory-for-logs']);
$this->assertSame(__DIR__.'/test-directory-for-logs/project/storage/logs/laravel.log', $logs[0]);
unlink(__DIR__.'/test-directory-for-logs/project/storage/logs/laravel.log');
}
}

View File

@@ -2,5 +2,6 @@ Test contents
user = something
group = something-else
listen = /potentially/some.socket
more contents

12
valet
View File

@@ -29,18 +29,10 @@ then
exit
fi
# If the command is to run the updater we'll run the updater script and
# let it handle this entire update. It will download a fresh copy of
# Valet and replace the current install with the "fresh" download.
if [[ "$1" = "update" ]]
then
bash $DIR/cli/scripts/update.sh
exit
# If the command is the "share" command we will need to resolve out any
# symbolic links for the site. Before starting Ngrok, we will fire a
# process to retrieve the live Ngrok tunnel URL in the background.
elif [[ "$1" = "share" ]]
if [[ "$1" = "share" ]]
then
HOST="${PWD##*/}"
DOMAIN=$(php "$DIR/cli/valet.php" domain)
@@ -54,7 +46,7 @@ then
# Fetch Ngrok URL In Background...
bash "$DIR/cli/scripts/fetch-share-url.sh" &
sudo -u $(logname) "$DIR/bin/ngrok" http -host-header=rewrite "$HOST.$DOMAIN:80"
sudo -u $(logname) "$DIR/bin/ngrok" http "$HOST.$DOMAIN:80" -host-header=rewrite ${*:2}
exit
# Finally, for every other command we will just proxy into the PHP tool