2012-04-09 14:10:25 +00:00
< ? php
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer ;
2012-10-18 14:39:47 +00:00
use Composer\Config\ConfigSourceInterface ;
2016-03-09 23:19:52 +00:00
use Composer\Downloader\TransportException ;
2016-04-19 21:29:04 +00:00
use Composer\IO\IOInterface ;
2016-04-13 00:02:50 +00:00
use Composer\Util\Platform ;
2019-04-09 05:44:08 +00:00
use Composer\Util\ProcessExecutor ;
2012-10-18 14:39:47 +00:00
2012-04-09 14:10:25 +00:00
/**
* @ author Jordi Boggiano < j . boggiano @ seld . be >
*/
class Config
{
2014-12-16 14:28:51 +00:00
const RELATIVE_PATHS = 1 ;
2012-06-23 10:55:05 +00:00
public static $defaultConfig = array (
'process-timeout' => 300 ,
2013-02-12 10:16:52 +00:00
'use-include-path' => false ,
2013-03-05 11:56:09 +00:00
'preferred-install' => 'auto' ,
2012-06-23 10:55:05 +00:00
'notify-on-install' => true ,
2016-03-01 13:19:44 +00:00
'github-protocols' => array ( 'https' , 'ssh' , 'git' ),
2013-02-12 10:16:52 +00:00
'vendor-dir' => 'vendor' ,
'bin-dir' => '{$vendor-dir}/bin' ,
2012-11-14 16:46:09 +00:00
'cache-dir' => '{$home}/cache' ,
2014-10-16 12:39:48 +00:00
'data-dir' => '{$home}' ,
2012-11-14 16:46:09 +00:00
'cache-files-dir' => '{$cache-dir}/files' ,
'cache-repo-dir' => '{$cache-dir}/repo' ,
'cache-vcs-dir' => '{$cache-dir}/vcs' ,
2013-02-12 10:16:52 +00:00
'cache-ttl' => 15552000 , // 6 months
'cache-files-ttl' => null , // fallback to cache-ttl
'cache-files-maxsize' => '300MiB' ,
2015-02-04 18:40:50 +00:00
'bin-compat' => 'auto' ,
2013-03-01 22:47:24 +00:00
'discard-changes' => false ,
2013-12-26 16:40:52 +00:00
'autoloader-suffix' => null ,
2015-12-18 20:13:36 +00:00
'sort-packages' => false ,
2014-01-17 13:43:54 +00:00
'optimize-autoloader' => false ,
2015-01-04 00:35:25 +00:00
'classmap-authoritative' => false ,
2016-07-28 08:23:39 +00:00
'apcu-autoloader' => false ,
2013-10-14 16:38:30 +00:00
'prepend-autoloader' => true ,
2012-09-07 23:51:33 +00:00
'github-domains' => array ( 'github.com' ),
2016-03-07 03:05:00 +00:00
'bitbucket-expose-hostname' => true ,
2014-02-28 20:40:57 +00:00
'disable-tls' => false ,
2016-02-11 13:15:03 +00:00
'secure-http' => true ,
2014-02-28 20:40:57 +00:00
'cafile' => null ,
2016-01-20 20:20:18 +00:00
'capath' => null ,
2014-07-25 10:37:11 +00:00
'github-expose-hostname' => true ,
2015-02-17 17:25:44 +00:00
'gitlab-domains' => array ( 'gitlab.com' ),
2014-05-27 11:50:47 +00:00
'store-auths' => 'prompt' ,
2014-05-14 18:31:42 +00:00
'platform' => array (),
2015-05-27 07:19:19 +00:00
'archive-format' => 'tar' ,
'archive-dir' => '.' ,
2017-06-15 15:06:13 +00:00
'htaccess-protect' => true ,
2019-01-28 20:53:24 +00:00
'use-github-api' => true ,
2019-10-19 19:46:29 +00:00
'lock' => true ,
2020-04-21 13:25:35 +00:00
'platform-check' => true ,
2014-05-27 11:50:47 +00:00
// valid keys without defaults (auth config stuff):
2016-04-06 09:46:29 +00:00
// bitbucket-oauth
2014-05-27 11:50:47 +00:00
// github-oauth
2015-12-03 13:30:07 +00:00
// gitlab-oauth
2016-07-05 10:02:39 +00:00
// gitlab-token
2014-05-27 11:50:47 +00:00
// http-basic
2020-03-10 12:39:22 +00:00
// bearer
2012-06-23 10:55:05 +00:00
);
public static $defaultRepositories = array (
2016-11-03 09:59:59 +00:00
'packagist.org' => array (
2012-06-24 11:03:55 +00:00
'type' => 'composer' ,
2018-07-24 07:30:06 +00:00
'url' => 'https?://repo.packagist.org' ,
2013-02-21 16:37:18 +00:00
'allow_ssl_downgrade' => true ,
2015-09-28 09:51:14 +00:00
),
2012-06-23 10:55:05 +00:00
);
2012-04-09 14:10:25 +00:00
private $config ;
2014-12-16 11:12:13 +00:00
private $baseDir ;
2012-06-23 10:55:05 +00:00
private $repositories ;
2016-12-26 23:39:02 +00:00
/** @var ConfigSourceInterface */
2012-10-18 14:39:47 +00:00
private $configSource ;
2016-12-26 23:39:02 +00:00
/** @var ConfigSourceInterface */
2014-05-27 11:50:47 +00:00
private $authConfigSource ;
2014-11-21 10:14:40 +00:00
private $useEnvironment ;
2016-04-19 21:29:04 +00:00
private $warnedHosts = array ();
2012-04-09 14:10:25 +00:00
2014-11-21 10:14:40 +00:00
/**
2016-04-11 14:06:57 +00:00
* @ param bool $useEnvironment Use COMPOSER_ environment variables to replace config settings
* @ param string $baseDir Optional base directory of the config
2014-11-21 10:14:40 +00:00
*/
2014-12-16 11:12:13 +00:00
public function __construct ( $useEnvironment = true , $baseDir = null )
2012-04-09 14:10:25 +00:00
{
// load defaults
2012-06-23 10:55:05 +00:00
$this -> config = static :: $defaultConfig ;
$this -> repositories = static :: $defaultRepositories ;
2014-11-21 10:14:40 +00:00
$this -> useEnvironment = ( bool ) $useEnvironment ;
2014-12-16 11:12:13 +00:00
$this -> baseDir = $baseDir ;
2012-04-09 14:10:25 +00:00
}
2012-10-18 14:39:47 +00:00
public function setConfigSource ( ConfigSourceInterface $source )
{
$this -> configSource = $source ;
}
public function getConfigSource ()
{
return $this -> configSource ;
}
2014-05-27 11:50:47 +00:00
public function setAuthConfigSource ( ConfigSourceInterface $source )
{
$this -> authConfigSource = $source ;
}
public function getAuthConfigSource ()
{
return $this -> authConfigSource ;
}
2012-04-09 14:13:46 +00:00
/**
* Merges new config values with the existing ones ( overriding )
*
* @ param array $config
*/
2014-06-29 11:11:27 +00:00
public function merge ( $config )
2012-04-09 14:10:25 +00:00
{
// override defaults with given config
if ( ! empty ( $config [ 'config' ]) && is_array ( $config [ 'config' ])) {
2012-12-08 20:45:21 +00:00
foreach ( $config [ 'config' ] as $key => $val ) {
2020-03-10 12:39:22 +00:00
if ( in_array ( $key , array ( 'bitbucket-oauth' , 'github-oauth' , 'gitlab-oauth' , 'gitlab-token' , 'http-basic' , 'bearer' )) && isset ( $this -> config [ $key ])) {
2012-12-08 20:45:21 +00:00
$this -> config [ $key ] = array_merge ( $this -> config [ $key ], $val );
2015-02-26 16:20:59 +00:00
} elseif ( 'preferred-install' === $key && isset ( $this -> config [ $key ])) {
2015-04-18 22:31:16 +00:00
if ( is_array ( $val ) || is_array ( $this -> config [ $key ])) {
if ( is_string ( $val )) {
$val = array ( '*' => $val );
}
if ( is_string ( $this -> config [ $key ])) {
$this -> config [ $key ] = array ( '*' => $this -> config [ $key ]);
}
$this -> config [ $key ] = array_merge ( $this -> config [ $key ], $val );
// the full match pattern needs to be last
if ( isset ( $this -> config [ $key ][ '*' ])) {
$wildcard = $this -> config [ $key ][ '*' ];
unset ( $this -> config [ $key ][ '*' ]);
$this -> config [ $key ][ '*' ] = $wildcard ;
}
} else {
$this -> config [ $key ] = $val ;
2015-02-26 16:20:59 +00:00
}
2012-12-08 20:45:21 +00:00
} else {
$this -> config [ $key ] = $val ;
}
}
2012-04-09 14:10:25 +00:00
}
2012-06-23 10:55:05 +00:00
if ( ! empty ( $config [ 'repositories' ]) && is_array ( $config [ 'repositories' ])) {
2012-06-23 11:04:23 +00:00
$this -> repositories = array_reverse ( $this -> repositories , true );
2012-06-24 11:03:55 +00:00
$newRepos = array_reverse ( $config [ 'repositories' ], true );
foreach ( $newRepos as $name => $repository ) {
// disable a repository by name
if ( false === $repository ) {
2016-11-03 09:59:59 +00:00
$this -> disableRepoByName ( $name );
2012-06-24 11:03:55 +00:00
continue ;
}
// disable a repository with an anonymous {"name": false} repo
2015-01-20 10:03:55 +00:00
if ( is_array ( $repository ) && 1 === count ( $repository ) && false === current ( $repository )) {
2016-11-03 09:59:59 +00:00
$this -> disableRepoByName ( key ( $repository ));
2012-06-29 09:45:06 +00:00
continue ;
2012-06-24 11:03:55 +00:00
}
// store repo
if ( is_int ( $name )) {
$this -> repositories [] = $repository ;
} else {
2016-11-03 09:59:59 +00:00
if ( $name === 'packagist' ) { // BC support for default "packagist" named repo
$this -> repositories [ $name . '.org' ] = $repository ;
} else {
$this -> repositories [ $name ] = $repository ;
}
2012-06-23 11:04:23 +00:00
}
}
2012-06-24 11:03:55 +00:00
$this -> repositories = array_reverse ( $this -> repositories , true );
2012-06-23 10:55:05 +00:00
}
}
/**
* @ return array
*/
public function getRepositories ()
{
return $this -> repositories ;
2012-04-09 14:10:25 +00:00
}
2012-04-09 14:13:46 +00:00
/**
* Returns a setting
*
2013-06-13 11:28:24 +00:00
* @ param string $key
2014-12-17 21:57:27 +00:00
* @ param int $flags Options ( see class constants )
2013-06-13 00:05:44 +00:00
* @ throws \RuntimeException
2012-04-09 14:13:46 +00:00
* @ return mixed
*/
2014-12-16 14:28:51 +00:00
public function get ( $key , $flags = 0 )
2012-04-09 14:10:25 +00:00
{
switch ( $key ) {
2020-08-25 11:54:29 +00:00
// strings/paths with env var and {$refs} support
2012-04-09 14:10:25 +00:00
case 'vendor-dir' :
case 'bin-dir' :
case 'process-timeout' :
2014-10-16 12:39:48 +00:00
case 'data-dir' :
2012-11-14 16:46:09 +00:00
case 'cache-dir' :
case 'cache-files-dir' :
case 'cache-repo-dir' :
case 'cache-vcs-dir' :
2014-03-01 14:32:07 +00:00
case 'cafile' :
2016-01-20 20:20:18 +00:00
case 'capath' :
2012-04-09 14:10:25 +00:00
// convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config
$env = 'COMPOSER_' . strtoupper ( strtr ( $key , '-' , '_' ));
2012-05-22 10:07:08 +00:00
2016-09-21 01:13:22 +00:00
$val = $this -> getComposerEnv ( $env );
2016-12-19 09:31:48 +00:00
$val = rtrim (( string ) $this -> process ( false !== $val ? $val : $this -> config [ $key ], $flags ), '/\\' );
2016-04-13 00:02:50 +00:00
$val = Platform :: expandPath ( $val );
2014-06-29 12:47:43 +00:00
2014-12-17 21:57:27 +00:00
if ( substr ( $key , - 4 ) !== '-dir' ) {
return $val ;
}
2016-01-26 15:19:58 +00:00
return (( $flags & self :: RELATIVE_PATHS ) == self :: RELATIVE_PATHS ) ? $val : $this -> realpath ( $val );
2012-04-09 14:10:25 +00:00
2020-08-25 11:54:29 +00:00
// booleans with env var support
2018-12-13 18:22:31 +00:00
case 'htaccess-protect' :
2020-08-25 11:54:29 +00:00
// convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config
$env = 'COMPOSER_' . strtoupper ( strtr ( $key , '-' , '_' ));
$val = $this -> getComposerEnv ( $env );
if ( false === $val ) {
$val = $this -> config [ $key ];
2018-12-13 18:22:31 +00:00
}
2020-08-25 11:54:29 +00:00
return $val !== 'false' && ( bool ) $val ;
// booleans without env var support
case 'disable-tls' :
case 'secure-http' :
case 'use-github-api' :
case 'lock' :
return $this -> config [ $key ] !== 'false' && ( bool ) $this -> config [ $key ];
2018-12-13 18:22:31 +00:00
2020-08-25 11:54:29 +00:00
// ints without env var support
2012-11-11 14:31:50 +00:00
case 'cache-ttl' :
return ( int ) $this -> config [ $key ];
2020-08-25 11:54:29 +00:00
// numbers with kb/mb/gb support, without env var support
2012-12-16 19:19:16 +00:00
case 'cache-files-maxsize' :
2013-01-05 19:02:51 +00:00
if ( ! preg_match ( '/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i' , $this -> config [ $key ], $matches )) {
2012-12-16 19:19:16 +00:00
throw new \RuntimeException (
2020-08-25 11:54:29 +00:00
" Could not parse the value of ' $key ': { $this -> config [ $key ] } "
2012-12-16 19:19:16 +00:00
);
}
$size = $matches [ 1 ];
if ( isset ( $matches [ 2 ])) {
switch ( strtolower ( $matches [ 2 ])) {
2013-01-05 19:02:51 +00:00
case 'g' :
2012-12-16 19:19:16 +00:00
$size *= 1024 ;
2013-01-05 19:02:51 +00:00
// intentional fallthrough
2018-07-24 12:32:52 +00:00
// no break
2013-01-05 19:02:51 +00:00
case 'm' :
2012-12-16 19:19:16 +00:00
$size *= 1024 ;
2013-01-05 19:02:51 +00:00
// intentional fallthrough
2018-07-24 12:32:52 +00:00
// no break
2013-01-05 19:02:51 +00:00
case 'k' :
2012-12-16 19:19:16 +00:00
$size *= 1024 ;
2013-01-05 19:02:51 +00:00
break ;
2012-12-16 19:19:16 +00:00
}
}
2013-01-05 19:01:58 +00:00
2012-12-16 19:19:16 +00:00
return $size ;
2020-08-25 11:54:29 +00:00
// special cases below
2012-11-11 14:31:50 +00:00
case 'cache-files-ttl' :
if ( isset ( $this -> config [ $key ])) {
return ( int ) $this -> config [ $key ];
}
return ( int ) $this -> config [ 'cache-ttl' ];
2012-04-09 14:36:06 +00:00
case 'home' :
2016-01-20 11:17:40 +00:00
$val = preg_replace ( '#^(\$HOME|~)(/|$)#' , rtrim ( getenv ( 'HOME' ) ? : getenv ( 'USERPROFILE' ), '/\\' ) . '/' , $this -> config [ $key ]);
return rtrim ( $this -> process ( $val , $flags ), '/\\' );
2012-04-09 14:36:06 +00:00
2015-02-03 18:27:29 +00:00
case 'bin-compat' :
2015-02-18 19:23:13 +00:00
$value = $this -> getComposerEnv ( 'COMPOSER_BIN_COMPAT' ) ? : $this -> config [ $key ];
2015-02-03 18:27:29 +00:00
2015-10-27 15:36:12 +00:00
if ( ! in_array ( $value , array ( 'auto' , 'full' ))) {
2015-02-03 18:27:29 +00:00
throw new \RuntimeException (
2015-10-27 15:36:12 +00:00
" Invalid value for 'bin-compat': { $value } . Expected auto, full "
2015-02-03 18:27:29 +00:00
);
}
return $value ;
2013-02-28 16:10:04 +00:00
case 'discard-changes' :
2014-11-21 10:14:40 +00:00
if ( $env = $this -> getComposerEnv ( 'COMPOSER_DISCARD_CHANGES' )) {
2013-04-15 17:19:27 +00:00
if ( ! in_array ( $env , array ( 'stash' , 'true' , 'false' , '1' , '0' ), true )) {
throw new \RuntimeException (
2013-04-15 19:55:09 +00:00
" Invalid value for COMPOSER_DISCARD_CHANGES: { $env } . Expected 1, 0, true, false or stash "
2013-04-15 17:19:27 +00:00
);
}
if ( 'stash' === $env ) {
return 'stash' ;
}
// convert string value to bool
return $env !== 'false' && ( bool ) $env ;
}
if ( ! in_array ( $this -> config [ $key ], array ( true , false , 'stash' ), true )) {
2013-02-28 16:10:04 +00:00
throw new \RuntimeException (
2013-04-15 19:55:09 +00:00
" Invalid value for 'discard-changes': { $this -> config [ $key ] } . Expected true, false or stash "
2013-02-28 16:10:04 +00:00
);
}
return $this -> config [ $key ];
2013-06-28 17:16:12 +00:00
case 'github-protocols' :
2016-03-01 13:19:44 +00:00
$protos = $this -> config [ 'github-protocols' ];
if ( $this -> config [ 'secure-http' ] && false !== ( $index = array_search ( 'git' , $protos ))) {
unset ( $protos [ $index ]);
}
if ( reset ( $protos ) === 'http' ) {
2014-02-13 15:23:53 +00:00
throw new \RuntimeException ( 'The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"' );
2013-06-28 17:16:12 +00:00
}
2016-03-01 13:19:44 +00:00
return $protos ;
2013-06-28 17:16:12 +00:00
2012-04-09 14:10:25 +00:00
default :
2012-10-18 14:39:47 +00:00
if ( ! isset ( $this -> config [ $key ])) {
return null ;
}
2014-12-17 21:57:27 +00:00
return $this -> process ( $this -> config [ $key ], $flags );
2012-04-09 14:10:25 +00:00
}
}
2014-12-17 21:57:27 +00:00
public function all ( $flags = 0 )
2012-11-30 15:21:08 +00:00
{
$all = array (
'repositories' => $this -> getRepositories (),
);
foreach ( array_keys ( $this -> config ) as $key ) {
2014-12-17 21:57:27 +00:00
$all [ 'config' ][ $key ] = $this -> get ( $key , $flags );
2012-11-30 15:21:08 +00:00
}
return $all ;
}
2013-02-12 10:16:52 +00:00
public function raw ()
{
return array (
'repositories' => $this -> getRepositories (),
'config' => $this -> config ,
);
}
2012-04-09 14:13:46 +00:00
/**
* Checks whether a setting exists
*
2012-06-23 09:58:18 +00:00
* @ param string $key
* @ return bool
2012-04-09 14:13:46 +00:00
*/
2012-04-09 14:10:25 +00:00
public function has ( $key )
{
return array_key_exists ( $key , $this -> config );
}
/**
* Replaces { $refs } inside a config string
*
2016-12-19 09:31:48 +00:00
* @ param string | int | null $value a config string that can contain { $refs - to - other - config }
* @ param int $flags Options ( see class constants )
* @ return string | int | null
2012-04-09 14:10:25 +00:00
*/
2014-12-17 21:57:27 +00:00
private function process ( $value , $flags )
2012-04-09 14:10:25 +00:00
{
$config = $this ;
2012-05-22 10:07:08 +00:00
2012-10-18 14:39:47 +00:00
if ( ! is_string ( $value )) {
return $value ;
}
2014-12-17 21:57:27 +00:00
return preg_replace_callback ( '#\{\$(.+)\}#' , function ( $match ) use ( $config , $flags ) {
return $config -> get ( $match [ 1 ], $flags );
2012-04-09 14:10:25 +00:00
}, $value );
}
2014-11-21 10:14:40 +00:00
2014-12-16 11:12:13 +00:00
/**
* Turns relative paths in absolute paths without realpath ()
*
* Since the dirs might not exist yet we can not call realpath or it will fail .
*
* @ param string $path
* @ return string
*/
private function realpath ( $path )
{
2016-01-25 23:40:16 +00:00
if ( preg_match ( '{^(?:/|[a-z]:|[a-z0-9.]+://)}i' , $path )) {
2014-12-16 11:12:13 +00:00
return $path ;
}
return $this -> baseDir . '/' . $path ;
}
2014-11-21 10:14:40 +00:00
/**
* Reads the value of a Composer environment variable
*
* This should be used to read COMPOSER_ environment variables
* that overload config values .
*
2015-09-28 09:51:14 +00:00
* @ param string $var
* @ return string | bool
2014-11-21 10:14:40 +00:00
*/
private function getComposerEnv ( $var )
{
if ( $this -> useEnvironment ) {
return getenv ( $var );
}
return false ;
}
2016-03-09 23:19:52 +00:00
2016-11-03 09:59:59 +00:00
private function disableRepoByName ( $name )
{
if ( isset ( $this -> repositories [ $name ])) {
unset ( $this -> repositories [ $name ]);
2017-03-08 14:07:29 +00:00
} elseif ( $name === 'packagist' ) { // BC support for default "packagist" named repo
2016-11-03 09:59:59 +00:00
unset ( $this -> repositories [ 'packagist.org' ]);
}
}
2016-03-09 23:19:52 +00:00
/**
* Validates that the passed URL is allowed to be used by current config , or throws an exception .
*
2016-04-19 21:29:04 +00:00
* @ param string $url
* @ param IOInterface $io
2016-03-09 23:19:52 +00:00
*/
2016-04-19 21:29:04 +00:00
public function prohibitUrlByConfig ( $url , IOInterface $io = null )
2016-03-09 23:19:52 +00:00
{
2016-04-19 21:29:04 +00:00
// Return right away if the URL is malformed or custom (see issue #5173)
if ( false === filter_var ( $url , FILTER_VALIDATE_URL )) {
2016-03-09 23:19:52 +00:00
return ;
}
2016-04-15 22:13:07 +00:00
// Extract scheme and throw exception on known insecure protocols
$scheme = parse_url ( $url , PHP_URL_SCHEME );
if ( in_array ( $scheme , array ( 'http' , 'git' , 'ftp' , 'svn' ))) {
2016-04-19 21:29:04 +00:00
if ( $this -> get ( 'secure-http' )) {
throw new TransportException ( " Your configuration does not allow connections to $url . See https://getcomposer.org/doc/06-config.md#secure-http for details. " );
} elseif ( $io ) {
$host = parse_url ( $url , PHP_URL_HOST );
if ( ! isset ( $this -> warnedHosts [ $host ])) {
$io -> writeError ( " <warning>Warning: Accessing $host over $scheme which is an insecure protocol.</warning> " );
}
$this -> warnedHosts [ $host ] = true ;
}
2016-03-09 23:19:52 +00:00
}
}
2019-04-09 05:44:08 +00:00
/**
* Used by long - running custom scripts in composer . json
*
* " scripts " : {
* " watch " : [
* " Composer \\ Config::disableProcessTimeout " ,
* " vendor/bin/long-running-script --watch "
* ]
* }
*/
public static function disableProcessTimeout ()
{
// Override global timeout set earlier by environment or config
ProcessExecutor :: setTimeout ( 0 );
}
2012-04-09 14:10:25 +00:00
}