├── .gitignore ├── LICENSE ├── README.md ├── app.php ├── cache └── .gitkeep ├── composer.json ├── composer.lock ├── config.ini.dist ├── console.php ├── logs └── .gitkeep ├── views └── index.html.twig └── web ├── .htaccess ├── index.php ├── proxy └── .gitkeep └── top.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | config.ini 2 | vendor 3 | web/proxy 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 Shogo Kawahara 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Composer Proxy 2 | ============== 3 | 4 | composer-proxy can cache package information for composer repository. 5 | It's an effective way to use composer when central repository 6 | (packagist.org) server is too far. 7 | 8 | There is an available server in Japan. 9 | (http://composer-proxy.jp/) 10 | 11 | System Requirement 12 | ------------------ 13 | 14 | - PHP5.3+ 15 | 16 | How to install 17 | -------------- 18 | 19 | Clone it. 20 | 21 | $ git clone https://github.com/kawahara/composer-proxy 22 | 23 | Resolve dependencies with composer (See https://getcomposer.org/) 24 | 25 | $ cd /path/to/app 26 | $ composer install 27 | 28 | Change permission for cache directories 29 | 30 | $ cd /path/to/app 31 | $ chmod 777 cache 32 | $ chmod 777 web/proxy 33 | 34 | Copy configuration file and modify for your needs 35 | 36 | cp config.ini.dist config.ini 37 | 38 | Example: Configure web server (Apache) 39 | 40 | 41 | Options -MultiViews 42 | 43 | RewriteEngine On 44 | RewriteBase /path/to/app/web 45 | RewriteCond %{REQUEST_FILENAME} !-f 46 | RewriteRule ^ index.php [QSA,L] 47 | 48 | 49 | Example: Configure web server (Nginx) 50 | 51 | server { 52 | listen 80; 53 | listen [::]:80 default_server ipv6only=on; 54 | 55 | root /path/to/app/web; 56 | server_name localhost; 57 | 58 | location / { 59 | index index.php index.html index.htm; 60 | try_files $uri @rewriteapp; 61 | } 62 | 63 | location @rewriteapp { 64 | rewrite ^(.*)$ /index.php/$1 last; 65 | } 66 | 67 | location ~ \.php(/|$) { 68 | fastcgi_pass unix:/var/run/php5-fpm.sock; 69 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 70 | include fastcgi_params; 71 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 72 | fastcgi_param HTTPS off; 73 | } 74 | } 75 | 76 | Register the script to crontab 77 | 78 | php /path/to/app/console.php cache:clear-old-file 79 | 80 | `cache:clear-old-file` command can delete old cache file. `packages.json` (the root file to define packages) is deleted every 5 minutes (default) by this command. Other file TTL is 6 months. 81 | 82 | - --ttl (-t) : TTL of `packages.json`. default is 300 seconds. 83 | - --dry-run : Show the action without real remove operations. 84 | - --without-hashed-file : You can ignore to delete package definition file. 85 | - --hashed-file-ttl : TTL of package definition file. default is 15,552,000 seconds. (6 months) 86 | 87 | 88 | You can change TTL by options of this command. 89 | 90 | If you need to delete all of the cache information, you can delete by following command. 91 | 92 | php /path/to/app/console.php cache:clear-all 93 | 94 | -------------------------------------------------------------------------------- /app.php: -------------------------------------------------------------------------------- 1 | 'https://packagist.org' 14 | ); 15 | 16 | $app['cache_dir'] = __DIR__.'/web/proxy'; 17 | 18 | # Read additional configs from a "config.ini" file. 19 | # See config.ini.dist for an example. 20 | $config_file = __DIR__ . '/config.ini'; 21 | if (is_file($config_file)) { 22 | $config = parse_ini_file($config_file); 23 | foreach ($config as $key => $value) { 24 | if (is_array($value)) { 25 | foreach ($value as $arr_key => $arr_value) { 26 | $app[$key][$arr_key] = $arr_value; 27 | } 28 | } else { 29 | $app[$key] = $value; 30 | } 31 | } 32 | } 33 | 34 | $app['browser'] = $app->share(function() { 35 | $client = new Buzz\Client\Curl(); 36 | $client->setTimeout(20); 37 | 38 | return new Buzz\Browser($client); 39 | }); 40 | 41 | $app->register(new Silex\Provider\HttpCacheServiceProvider(), array( 42 | 'http_cache.cache_dir' => __DIR__.'/cache/' 43 | )); 44 | 45 | 46 | $app->register(new Silex\Provider\TwigServiceProvider(), array( 47 | 'twig.path' => __DIR__.'/views' 48 | )); 49 | 50 | $app->get('/', function() use ($app) { 51 | $body = $app['twig']->render('index.html.twig', array( 52 | 'app' => $app 53 | )); 54 | 55 | return new Response($body, 200, array('Cache-Control' => 's-maxage=3600,public')); 56 | }); 57 | 58 | $app->get('/proxy/{rep}/', function($rep) use ($app) { 59 | return $app->redirect("/proxy/${rep}/packages.json"); 60 | }); 61 | 62 | $app->get('/proxy/{rep}/packages.json', function($rep) use ($app) { 63 | if (!isset($app['repositories'][$rep])) { 64 | $app->abort(404, "Not Found"); 65 | } 66 | 67 | $url = $app['repositories'][$rep]."/packages.json"; 68 | $response = $app['browser']->get($url); 69 | if (!$response->isOk()) { 70 | $app->abort($response->getStatusCode(), ""); 71 | } 72 | 73 | $responseJson = json_decode($response->getContent(), true); 74 | 75 | // convert 76 | if (isset($responseJson['notify']) && $responseJson['notify'][0] === '/') { 77 | $responseJson['notify'] = $app['repositories'][$rep] . $responseJson['notify']; 78 | } 79 | if (isset($responseJson['notify-batch']) && $responseJson['notify-batch'][0] === '/') { 80 | $responseJson['notify-batch'] = $app['repositories'][$rep] . $responseJson['notify-batch']; 81 | } 82 | if (isset($responseJson['search']) && $responseJson['search'][0] === '/') { 83 | $responseJson['search'] = $app['repositories'][$rep] . $responseJson['search']; 84 | } 85 | 86 | $responseJson['providers-url'] = "/proxy/".$rep."/p/%package%$%hash%.json"; 87 | 88 | $dir = $app['cache_dir']."/".$rep; 89 | if (!is_dir($dir)) { 90 | @mkdir($dir, 0777, true); 91 | } 92 | 93 | file_put_contents($app['cache_dir']."/".$rep."/packages.json", json_encode($responseJson)); 94 | 95 | return $app->json($responseJson); 96 | }); 97 | 98 | $app->get('/proxy/{rep}/p/{p}${hash}.json', function($rep, $p, $hash) use ($app) { 99 | if (!isset($app['repositories'][$rep])) { 100 | $app->abort(404, "Not Found"); 101 | } 102 | 103 | $path = "/p/"; 104 | $file = $p."$".$hash.".json"; 105 | 106 | $url = $app['repositories'][$rep].$path.$file; 107 | $response = $app['browser']->get($url); 108 | if (!$response->isOk()) { 109 | $app->abort($response->getStatusCode(), ""); 110 | } 111 | 112 | $contents = $response->getContent(); 113 | $gethash = hash('sha256', $contents, false); 114 | 115 | if ($gethash != $hash) { 116 | $app->abort(500, "Cannot fetch file correctly."); 117 | } 118 | 119 | $responseJson = json_decode($contents, true); 120 | 121 | $dir = $app['cache_dir']."/".$rep.$path; 122 | if (!is_dir($dir)) { 123 | @mkdir($dir, 0777, true); 124 | } 125 | 126 | file_put_contents($dir.$file, json_encode($responseJson)); 127 | 128 | return $app->json($responseJson); 129 | }); 130 | 131 | $app->get('/proxy/{rep}/p/{namespace}/{package}${hash}.json', function($rep, $namespace, $package, $hash) use ($app) { 132 | if (!isset($app['repositories'][$rep])) { 133 | $app->abort(404, "Not Found"); 134 | } 135 | 136 | $path = "/p/".$namespace."/"; 137 | $file = $package."$".$hash.".json"; 138 | 139 | $url = $app['repositories'][$rep].$path.$file; 140 | $response = $app['browser']->get($url); 141 | if (!$response->isOk()) { 142 | $app->abort($response->getStatusCode(), ""); 143 | } 144 | 145 | $contents = $response->getContent(); 146 | $gethash = hash('sha256', $contents, false); 147 | 148 | // Check hash 149 | if ($gethash != $hash) { 150 | $app->abort(500, "Cannot fetch file correctly."); 151 | } 152 | 153 | $responseJson = json_decode($contents, true); 154 | 155 | $dir = $app['cache_dir']."/".$rep.$path; 156 | if (!is_dir($dir)) { 157 | @mkdir($dir, 0777, true); 158 | } 159 | 160 | // Save cache 161 | file_put_contents($dir.$file, json_encode($responseJson)); 162 | 163 | return $app->json($responseJson); 164 | }); 165 | 166 | $app->get('/proxy/{rep}/p/{namespace}/{package}.json', function($rep, $namespace, $package) use ($app) { 167 | if (!isset($app['repositories'][$rep])) { 168 | $app->abort(404, "Not Found"); 169 | } 170 | 171 | $path = "/p/".$namespace."/"; 172 | $file = $package.".json"; 173 | 174 | $url = $app['repositories'][$rep].$path.$file; 175 | $response = $app['browser']->get($url); 176 | if (!$response->isOk()) { 177 | $app->abort($response->getStatusCode(), ""); 178 | } 179 | 180 | $responseJson = json_decode($response->getContent(), true); 181 | 182 | $dir = $app['cache_dir']."/".$rep.$path; 183 | if (!is_dir($dir)) { 184 | @mkdir($dir, 0777, true); 185 | } 186 | 187 | file_put_contents($dir.$file, json_encode($responseJson)); 188 | 189 | return $app->json($responseJson); 190 | }); 191 | 192 | return $app; 193 | -------------------------------------------------------------------------------- /cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kawahara/composer-proxy/6a5f6831d2e995c56f8139b51d9afbc9f9efb5b3/cache/.gitkeep -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kawahara/composer-proxy", 3 | "description": "The composer proxy", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Shogo Kawahara", 8 | "email": "kawahara@bucyou.net" 9 | } 10 | ], 11 | "require": { 12 | "ext-curl": "*", 13 | "silex/silex": "1.*", 14 | "symfony/console": "2.3.*", 15 | "symfony/finder": "2.3.*", 16 | "symfony/filesystem": "2.3.*", 17 | "react/react": "0.3.*", 18 | "kriswallsmith/buzz": "0.*", 19 | "twig/twig": ">=1.8,<2.0-dev" 20 | }, 21 | "autoload": { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" 5 | ], 6 | "hash": "610674e92f1015f725c66a9be8137d32", 7 | "packages": [ 8 | { 9 | "name": "evenement/evenement", 10 | "version": "v1.0.0", 11 | "source": { 12 | "type": "git", 13 | "url": "https://github.com/igorw/evenement", 14 | "reference": "v1.0.0" 15 | }, 16 | "dist": { 17 | "type": "zip", 18 | "url": "https://github.com/igorw/evenement/zipball/v1.0.0", 19 | "reference": "v1.0.0", 20 | "shasum": "" 21 | }, 22 | "require": { 23 | "php": ">=5.3.0" 24 | }, 25 | "type": "library", 26 | "autoload": { 27 | "psr-0": { 28 | "Evenement": "src" 29 | } 30 | }, 31 | "notification-url": "https://packagist.org/downloads/", 32 | "license": [ 33 | "MIT" 34 | ], 35 | "authors": [ 36 | { 37 | "name": "Igor Wiedler", 38 | "email": "igor@wiedler.ch", 39 | "homepage": "http://wiedler.ch/igor/" 40 | } 41 | ], 42 | "description": "Événement is a very simple event dispatching library for PHP 5.3", 43 | "keywords": [ 44 | "event-dispatcher" 45 | ], 46 | "time": "2012-05-30 08:01:08" 47 | }, 48 | { 49 | "name": "guzzle/parser", 50 | "version": "v3.7.1", 51 | "target-dir": "Guzzle/Parser", 52 | "source": { 53 | "type": "git", 54 | "url": "https://github.com/guzzle/parser.git", 55 | "reference": "v3.7.1" 56 | }, 57 | "dist": { 58 | "type": "zip", 59 | "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.7.1", 60 | "reference": "v3.7.1", 61 | "shasum": "" 62 | }, 63 | "require": { 64 | "php": ">=5.3.2" 65 | }, 66 | "type": "library", 67 | "extra": { 68 | "branch-alias": { 69 | "dev-master": "3.7-dev" 70 | } 71 | }, 72 | "autoload": { 73 | "psr-0": { 74 | "Guzzle\\Parser": "" 75 | } 76 | }, 77 | "notification-url": "https://packagist.org/downloads/", 78 | "license": [ 79 | "MIT" 80 | ], 81 | "description": "Interchangeable parsers used by Guzzle", 82 | "homepage": "http://guzzlephp.org/", 83 | "keywords": [ 84 | "URI Template", 85 | "cookie", 86 | "http", 87 | "message", 88 | "url" 89 | ], 90 | "time": "2013-06-11 00:24:07" 91 | }, 92 | { 93 | "name": "kriswallsmith/buzz", 94 | "version": "v0.10", 95 | "source": { 96 | "type": "git", 97 | "url": "https://github.com/kriswallsmith/Buzz.git", 98 | "reference": "v0.10" 99 | }, 100 | "dist": { 101 | "type": "zip", 102 | "url": "https://api.github.com/repos/kriswallsmith/Buzz/zipball/v0.10", 103 | "reference": "v0.10", 104 | "shasum": "" 105 | }, 106 | "require": { 107 | "php": ">=5.3.0" 108 | }, 109 | "require-dev": { 110 | "phpunit/phpunit": "3.7.*" 111 | }, 112 | "suggest": { 113 | "ext-curl": "*" 114 | }, 115 | "type": "library", 116 | "autoload": { 117 | "psr-0": { 118 | "Buzz": "lib/" 119 | } 120 | }, 121 | "notification-url": "https://packagist.org/downloads/", 122 | "license": [ 123 | "MIT" 124 | ], 125 | "authors": [ 126 | { 127 | "name": "Kris Wallsmith", 128 | "email": "kris.wallsmith@gmail.com", 129 | "homepage": "http://kriswallsmith.net/" 130 | } 131 | ], 132 | "description": "Lightweight HTTP client", 133 | "homepage": "https://github.com/kriswallsmith/Buzz", 134 | "keywords": [ 135 | "curl", 136 | "http client" 137 | ], 138 | "time": "2013-05-19 03:41:15" 139 | }, 140 | { 141 | "name": "pimple/pimple", 142 | "version": "v1.0.2", 143 | "source": { 144 | "type": "git", 145 | "url": "https://github.com/fabpot/Pimple.git", 146 | "reference": "v1.0.2" 147 | }, 148 | "dist": { 149 | "type": "zip", 150 | "url": "https://api.github.com/repos/fabpot/Pimple/zipball/v1.0.2", 151 | "reference": "v1.0.2", 152 | "shasum": "" 153 | }, 154 | "require": { 155 | "php": ">=5.3.0" 156 | }, 157 | "type": "library", 158 | "extra": { 159 | "branch-alias": { 160 | "dev-master": "1.0.x-dev" 161 | } 162 | }, 163 | "autoload": { 164 | "psr-0": { 165 | "Pimple": "lib/" 166 | } 167 | }, 168 | "notification-url": "https://packagist.org/downloads/", 169 | "license": [ 170 | "MIT" 171 | ], 172 | "authors": [ 173 | { 174 | "name": "Fabien Potencier", 175 | "email": "fabien@symfony.com" 176 | } 177 | ], 178 | "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", 179 | "homepage": "http://pimple.sensiolabs.org", 180 | "keywords": [ 181 | "container", 182 | "dependency injection" 183 | ], 184 | "time": "2013-03-08 08:21:40" 185 | }, 186 | { 187 | "name": "psr/log", 188 | "version": "1.0.0", 189 | "source": { 190 | "type": "git", 191 | "url": "https://github.com/php-fig/log", 192 | "reference": "1.0.0" 193 | }, 194 | "dist": { 195 | "type": "zip", 196 | "url": "https://github.com/php-fig/log/archive/1.0.0.zip", 197 | "reference": "1.0.0", 198 | "shasum": "" 199 | }, 200 | "type": "library", 201 | "autoload": { 202 | "psr-0": { 203 | "Psr\\Log\\": "" 204 | } 205 | }, 206 | "notification-url": "https://packagist.org/downloads/", 207 | "license": [ 208 | "MIT" 209 | ], 210 | "authors": [ 211 | { 212 | "name": "PHP-FIG", 213 | "homepage": "http://www.php-fig.org/" 214 | } 215 | ], 216 | "description": "Common interface for logging libraries", 217 | "keywords": [ 218 | "log", 219 | "psr", 220 | "psr-3" 221 | ], 222 | "time": "2012-12-21 11:40:51" 223 | }, 224 | { 225 | "name": "react/promise", 226 | "version": "v1.0.4", 227 | "source": { 228 | "type": "git", 229 | "url": "https://github.com/reactphp/promise.git", 230 | "reference": "v1.0.4" 231 | }, 232 | "dist": { 233 | "type": "zip", 234 | "url": "https://api.github.com/repos/reactphp/promise/zipball/v1.0.4", 235 | "reference": "v1.0.4", 236 | "shasum": "" 237 | }, 238 | "require": { 239 | "php": ">=5.3.3" 240 | }, 241 | "type": "library", 242 | "extra": { 243 | "branch-alias": { 244 | "dev-master": "1.0-dev" 245 | } 246 | }, 247 | "autoload": { 248 | "psr-0": { 249 | "React\\Promise": "src/" 250 | } 251 | }, 252 | "notification-url": "https://packagist.org/downloads/", 253 | "license": [ 254 | "MIT" 255 | ], 256 | "authors": [ 257 | { 258 | "name": "Jan Sorgalla", 259 | "email": "jsorgalla@googlemail.com", 260 | "homepage": "http://sorgalla.com", 261 | "role": "maintainer" 262 | } 263 | ], 264 | "description": "A lightweight implementation of CommonJS Promises/A for PHP", 265 | "time": "2013-04-03 14:05:55" 266 | }, 267 | { 268 | "name": "react/react", 269 | "version": "v0.3.3", 270 | "source": { 271 | "type": "git", 272 | "url": "https://github.com/reactphp/react.git", 273 | "reference": "v0.3.3" 274 | }, 275 | "dist": { 276 | "type": "zip", 277 | "url": "https://api.github.com/repos/reactphp/react/zipball/v0.3.3", 278 | "reference": "v0.3.3", 279 | "shasum": "" 280 | }, 281 | "require": { 282 | "evenement/evenement": "1.0.*", 283 | "guzzle/parser": "~3.0", 284 | "php": ">=5.3.3", 285 | "react/promise": "~1.0" 286 | }, 287 | "replace": { 288 | "react/cache": "self.version", 289 | "react/dns": "self.version", 290 | "react/event-loop": "self.version", 291 | "react/http": "self.version", 292 | "react/http-client": "self.version", 293 | "react/socket": "self.version", 294 | "react/socket-client": "self.version", 295 | "react/stream": "self.version" 296 | }, 297 | "suggest": { 298 | "ext-libev": "*", 299 | "ext-libevent": "*" 300 | }, 301 | "type": "library", 302 | "extra": { 303 | "branch-alias": { 304 | "dev-master": "0.3-dev" 305 | } 306 | }, 307 | "autoload": { 308 | "psr-0": { 309 | "React": "src" 310 | } 311 | }, 312 | "notification-url": "https://packagist.org/downloads/", 313 | "license": [ 314 | "MIT" 315 | ], 316 | "description": "Nuclear Reactor written in PHP.", 317 | "keywords": [ 318 | "event-loop", 319 | "reactor" 320 | ], 321 | "time": "2013-07-09 01:55:25" 322 | }, 323 | { 324 | "name": "silex/silex", 325 | "version": "v1.1.0", 326 | "source": { 327 | "type": "git", 328 | "url": "https://github.com/fabpot/Silex.git", 329 | "reference": "v1.1.0" 330 | }, 331 | "dist": { 332 | "type": "zip", 333 | "url": "https://api.github.com/repos/fabpot/Silex/zipball/v1.1.0", 334 | "reference": "v1.1.0", 335 | "shasum": "" 336 | }, 337 | "require": { 338 | "php": ">=5.3.3", 339 | "pimple/pimple": "1.*", 340 | "symfony/event-dispatcher": ">=2.3,<2.4-dev", 341 | "symfony/http-foundation": ">=2.3,<2.4-dev", 342 | "symfony/http-kernel": ">=2.3,<2.4-dev", 343 | "symfony/routing": ">=2.3,<2.4-dev" 344 | }, 345 | "require-dev": { 346 | "doctrine/dbal": ">=2.2.0,<2.4.0-dev", 347 | "monolog/monolog": "~1.4,>=1.4.1", 348 | "phpunit/phpunit": "~3.7", 349 | "swiftmailer/swiftmailer": "5.*", 350 | "symfony/browser-kit": ">=2.3,<2.4-dev", 351 | "symfony/config": ">=2.3,<2.4-dev", 352 | "symfony/css-selector": ">=2.3,<2.4-dev", 353 | "symfony/dom-crawler": ">=2.3,<2.4-dev", 354 | "symfony/finder": ">=2.3,<2.4-dev", 355 | "symfony/form": ">=2.3,<2.4-dev", 356 | "symfony/locale": ">=2.3,<2.4-dev", 357 | "symfony/monolog-bridge": ">=2.3,<2.4-dev", 358 | "symfony/options-resolver": ">=2.3,<2.4-dev", 359 | "symfony/process": ">=2.3,<2.4-dev", 360 | "symfony/security": ">=2.3,<2.4-dev", 361 | "symfony/serializer": ">=2.3,<2.4-dev", 362 | "symfony/translation": ">=2.3,<2.4-dev", 363 | "symfony/twig-bridge": ">=2.3,<2.4-dev", 364 | "symfony/validator": ">=2.3,<2.4-dev", 365 | "twig/twig": ">=1.8.0,<2.0-dev" 366 | }, 367 | "suggest": { 368 | "symfony/browser-kit": ">=2.3,<2.4-dev", 369 | "symfony/css-selector": ">=2.3,<2.4-dev", 370 | "symfony/dom-crawler": ">=2.3,<2.4-dev", 371 | "symfony/form": ">=2.3,<2.4-dev" 372 | }, 373 | "type": "library", 374 | "extra": { 375 | "branch-alias": { 376 | "dev-master": "1.1.x-dev" 377 | } 378 | }, 379 | "autoload": { 380 | "psr-0": { 381 | "Silex": "src/" 382 | } 383 | }, 384 | "notification-url": "https://packagist.org/downloads/", 385 | "license": [ 386 | "MIT" 387 | ], 388 | "authors": [ 389 | { 390 | "name": "Fabien Potencier", 391 | "email": "fabien@symfony.com" 392 | }, 393 | { 394 | "name": "Igor Wiedler", 395 | "email": "igor@wiedler.ch", 396 | "homepage": "http://wiedler.ch/igor/" 397 | } 398 | ], 399 | "description": "The PHP micro-framework based on the Symfony2 Components", 400 | "homepage": "http://silex.sensiolabs.org", 401 | "keywords": [ 402 | "microframework" 403 | ], 404 | "time": "2013-07-04 07:15:36" 405 | }, 406 | { 407 | "name": "symfony/console", 408 | "version": "v2.3.1", 409 | "target-dir": "Symfony/Component/Console", 410 | "source": { 411 | "type": "git", 412 | "url": "https://github.com/symfony/Console.git", 413 | "reference": "v2.3.1" 414 | }, 415 | "dist": { 416 | "type": "zip", 417 | "url": "https://api.github.com/repos/symfony/Console/zipball/v2.3.1", 418 | "reference": "v2.3.1", 419 | "shasum": "" 420 | }, 421 | "require": { 422 | "php": ">=5.3.3" 423 | }, 424 | "require-dev": { 425 | "symfony/event-dispatcher": ">=2.1,<3.0" 426 | }, 427 | "suggest": { 428 | "symfony/event-dispatcher": "" 429 | }, 430 | "type": "library", 431 | "extra": { 432 | "branch-alias": { 433 | "dev-master": "2.3-dev" 434 | } 435 | }, 436 | "autoload": { 437 | "psr-0": { 438 | "Symfony\\Component\\Console\\": "" 439 | } 440 | }, 441 | "notification-url": "https://packagist.org/downloads/", 442 | "license": [ 443 | "MIT" 444 | ], 445 | "authors": [ 446 | { 447 | "name": "Fabien Potencier", 448 | "email": "fabien@symfony.com" 449 | }, 450 | { 451 | "name": "Symfony Community", 452 | "homepage": "http://symfony.com/contributors" 453 | } 454 | ], 455 | "description": "Symfony Console Component", 456 | "homepage": "http://symfony.com", 457 | "time": "2013-06-11 07:15:14" 458 | }, 459 | { 460 | "name": "symfony/debug", 461 | "version": "v2.3.1", 462 | "target-dir": "Symfony/Component/Debug", 463 | "source": { 464 | "type": "git", 465 | "url": "https://github.com/symfony/Debug.git", 466 | "reference": "v2.3.1" 467 | }, 468 | "dist": { 469 | "type": "zip", 470 | "url": "https://api.github.com/repos/symfony/Debug/zipball/v2.3.1", 471 | "reference": "v2.3.1", 472 | "shasum": "" 473 | }, 474 | "require": { 475 | "php": ">=5.3.3" 476 | }, 477 | "require-dev": { 478 | "symfony/http-foundation": ">=2.1,<3.0", 479 | "symfony/http-kernel": ">=2.1,<3.0" 480 | }, 481 | "suggest": { 482 | "symfony/class-loader": "", 483 | "symfony/http-foundation": "", 484 | "symfony/http-kernel": "" 485 | }, 486 | "type": "library", 487 | "extra": { 488 | "branch-alias": { 489 | "dev-master": "2.3-dev" 490 | } 491 | }, 492 | "autoload": { 493 | "psr-0": { 494 | "Symfony\\Component\\Debug\\": "" 495 | } 496 | }, 497 | "notification-url": "https://packagist.org/downloads/", 498 | "license": [ 499 | "MIT" 500 | ], 501 | "authors": [ 502 | { 503 | "name": "Fabien Potencier", 504 | "email": "fabien@symfony.com" 505 | }, 506 | { 507 | "name": "Symfony Community", 508 | "homepage": "http://symfony.com/contributors" 509 | } 510 | ], 511 | "description": "Symfony Debug Component", 512 | "homepage": "http://symfony.com", 513 | "time": "2013-06-02 11:58:44" 514 | }, 515 | { 516 | "name": "symfony/event-dispatcher", 517 | "version": "v2.3.1", 518 | "target-dir": "Symfony/Component/EventDispatcher", 519 | "source": { 520 | "type": "git", 521 | "url": "https://github.com/symfony/EventDispatcher.git", 522 | "reference": "v2.3.1" 523 | }, 524 | "dist": { 525 | "type": "zip", 526 | "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.1", 527 | "reference": "v2.3.1", 528 | "shasum": "" 529 | }, 530 | "require": { 531 | "php": ">=5.3.3" 532 | }, 533 | "require-dev": { 534 | "symfony/dependency-injection": ">=2.0,<3.0" 535 | }, 536 | "suggest": { 537 | "symfony/dependency-injection": "", 538 | "symfony/http-kernel": "" 539 | }, 540 | "type": "library", 541 | "extra": { 542 | "branch-alias": { 543 | "dev-master": "2.3-dev" 544 | } 545 | }, 546 | "autoload": { 547 | "psr-0": { 548 | "Symfony\\Component\\EventDispatcher\\": "" 549 | } 550 | }, 551 | "notification-url": "https://packagist.org/downloads/", 552 | "license": [ 553 | "MIT" 554 | ], 555 | "authors": [ 556 | { 557 | "name": "Fabien Potencier", 558 | "email": "fabien@symfony.com" 559 | }, 560 | { 561 | "name": "Symfony Community", 562 | "homepage": "http://symfony.com/contributors" 563 | } 564 | ], 565 | "description": "Symfony EventDispatcher Component", 566 | "homepage": "http://symfony.com", 567 | "time": "2013-05-13 14:36:40" 568 | }, 569 | { 570 | "name": "symfony/filesystem", 571 | "version": "v2.3.1", 572 | "target-dir": "Symfony/Component/Filesystem", 573 | "source": { 574 | "type": "git", 575 | "url": "https://github.com/symfony/Filesystem.git", 576 | "reference": "v2.3.1" 577 | }, 578 | "dist": { 579 | "type": "zip", 580 | "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.1", 581 | "reference": "v2.3.1", 582 | "shasum": "" 583 | }, 584 | "require": { 585 | "php": ">=5.3.3" 586 | }, 587 | "type": "library", 588 | "extra": { 589 | "branch-alias": { 590 | "dev-master": "2.3-dev" 591 | } 592 | }, 593 | "autoload": { 594 | "psr-0": { 595 | "Symfony\\Component\\Filesystem\\": "" 596 | } 597 | }, 598 | "notification-url": "https://packagist.org/downloads/", 599 | "license": [ 600 | "MIT" 601 | ], 602 | "authors": [ 603 | { 604 | "name": "Fabien Potencier", 605 | "email": "fabien@symfony.com" 606 | }, 607 | { 608 | "name": "Symfony Community", 609 | "homepage": "http://symfony.com/contributors" 610 | } 611 | ], 612 | "description": "Symfony Filesystem Component", 613 | "homepage": "http://symfony.com", 614 | "time": "2013-06-04 15:02:05" 615 | }, 616 | { 617 | "name": "symfony/finder", 618 | "version": "v2.3.1", 619 | "target-dir": "Symfony/Component/Finder", 620 | "source": { 621 | "type": "git", 622 | "url": "https://github.com/symfony/Finder.git", 623 | "reference": "v2.3.1" 624 | }, 625 | "dist": { 626 | "type": "zip", 627 | "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.3.1", 628 | "reference": "v2.3.1", 629 | "shasum": "" 630 | }, 631 | "require": { 632 | "php": ">=5.3.3" 633 | }, 634 | "type": "library", 635 | "extra": { 636 | "branch-alias": { 637 | "dev-master": "2.3-dev" 638 | } 639 | }, 640 | "autoload": { 641 | "psr-0": { 642 | "Symfony\\Component\\Finder\\": "" 643 | } 644 | }, 645 | "notification-url": "https://packagist.org/downloads/", 646 | "license": [ 647 | "MIT" 648 | ], 649 | "authors": [ 650 | { 651 | "name": "Fabien Potencier", 652 | "email": "fabien@symfony.com" 653 | }, 654 | { 655 | "name": "Symfony Community", 656 | "homepage": "http://symfony.com/contributors" 657 | } 658 | ], 659 | "description": "Symfony Finder Component", 660 | "homepage": "http://symfony.com", 661 | "time": "2013-06-02 12:05:51" 662 | }, 663 | { 664 | "name": "symfony/http-foundation", 665 | "version": "v2.3.1", 666 | "target-dir": "Symfony/Component/HttpFoundation", 667 | "source": { 668 | "type": "git", 669 | "url": "https://github.com/symfony/HttpFoundation.git", 670 | "reference": "v2.3.1" 671 | }, 672 | "dist": { 673 | "type": "zip", 674 | "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.3.1", 675 | "reference": "v2.3.1", 676 | "shasum": "" 677 | }, 678 | "require": { 679 | "php": ">=5.3.3" 680 | }, 681 | "type": "library", 682 | "extra": { 683 | "branch-alias": { 684 | "dev-master": "2.3-dev" 685 | } 686 | }, 687 | "autoload": { 688 | "psr-0": { 689 | "Symfony\\Component\\HttpFoundation\\": "" 690 | }, 691 | "classmap": [ 692 | "Symfony/Component/HttpFoundation/Resources/stubs" 693 | ] 694 | }, 695 | "notification-url": "https://packagist.org/downloads/", 696 | "license": [ 697 | "MIT" 698 | ], 699 | "authors": [ 700 | { 701 | "name": "Fabien Potencier", 702 | "email": "fabien@symfony.com" 703 | }, 704 | { 705 | "name": "Symfony Community", 706 | "homepage": "http://symfony.com/contributors" 707 | } 708 | ], 709 | "description": "Symfony HttpFoundation Component", 710 | "homepage": "http://symfony.com", 711 | "time": "2013-05-10 06:00:03" 712 | }, 713 | { 714 | "name": "symfony/http-kernel", 715 | "version": "v2.3.1", 716 | "target-dir": "Symfony/Component/HttpKernel", 717 | "source": { 718 | "type": "git", 719 | "url": "https://github.com/symfony/HttpKernel.git", 720 | "reference": "v2.3.1" 721 | }, 722 | "dist": { 723 | "type": "zip", 724 | "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/v2.3.1", 725 | "reference": "v2.3.1", 726 | "shasum": "" 727 | }, 728 | "require": { 729 | "php": ">=5.3.3", 730 | "psr/log": ">=1.0,<2.0", 731 | "symfony/debug": ">=2.3,<3.0", 732 | "symfony/event-dispatcher": ">=2.1,<3.0", 733 | "symfony/http-foundation": ">=2.2,<3.0" 734 | }, 735 | "require-dev": { 736 | "symfony/browser-kit": "2.2.*", 737 | "symfony/class-loader": ">=2.1,<3.0", 738 | "symfony/config": ">=2.0,<3.0", 739 | "symfony/console": "2.2.*", 740 | "symfony/dependency-injection": ">=2.0,<3.0", 741 | "symfony/finder": ">=2.0,<3.0", 742 | "symfony/process": ">=2.0,<3.0", 743 | "symfony/routing": ">=2.2,<3.0", 744 | "symfony/stopwatch": ">=2.2,<3.0" 745 | }, 746 | "suggest": { 747 | "symfony/browser-kit": "", 748 | "symfony/class-loader": "", 749 | "symfony/config": "", 750 | "symfony/console": "", 751 | "symfony/dependency-injection": "", 752 | "symfony/finder": "" 753 | }, 754 | "type": "library", 755 | "extra": { 756 | "branch-alias": { 757 | "dev-master": "2.3-dev" 758 | } 759 | }, 760 | "autoload": { 761 | "psr-0": { 762 | "Symfony\\Component\\HttpKernel\\": "" 763 | } 764 | }, 765 | "notification-url": "https://packagist.org/downloads/", 766 | "license": [ 767 | "MIT" 768 | ], 769 | "authors": [ 770 | { 771 | "name": "Fabien Potencier", 772 | "email": "fabien@symfony.com" 773 | }, 774 | { 775 | "name": "Symfony Community", 776 | "homepage": "http://symfony.com/contributors" 777 | } 778 | ], 779 | "description": "Symfony HttpKernel Component", 780 | "homepage": "http://symfony.com", 781 | "time": "2013-06-11 11:46:38" 782 | }, 783 | { 784 | "name": "symfony/routing", 785 | "version": "v2.3.1", 786 | "target-dir": "Symfony/Component/Routing", 787 | "source": { 788 | "type": "git", 789 | "url": "https://github.com/symfony/Routing.git", 790 | "reference": "v2.3.1" 791 | }, 792 | "dist": { 793 | "type": "zip", 794 | "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.1", 795 | "reference": "v2.3.1", 796 | "shasum": "" 797 | }, 798 | "require": { 799 | "php": ">=5.3.3" 800 | }, 801 | "require-dev": { 802 | "doctrine/common": ">=2.2,<3.0", 803 | "psr/log": ">=1.0,<2.0", 804 | "symfony/config": ">=2.2,<3.0", 805 | "symfony/yaml": ">=2.0,<3.0" 806 | }, 807 | "suggest": { 808 | "doctrine/common": "", 809 | "symfony/config": "", 810 | "symfony/yaml": "" 811 | }, 812 | "type": "library", 813 | "extra": { 814 | "branch-alias": { 815 | "dev-master": "2.3-dev" 816 | } 817 | }, 818 | "autoload": { 819 | "psr-0": { 820 | "Symfony\\Component\\Routing\\": "" 821 | } 822 | }, 823 | "notification-url": "https://packagist.org/downloads/", 824 | "license": [ 825 | "MIT" 826 | ], 827 | "authors": [ 828 | { 829 | "name": "Fabien Potencier", 830 | "email": "fabien@symfony.com" 831 | }, 832 | { 833 | "name": "Symfony Community", 834 | "homepage": "http://symfony.com/contributors" 835 | } 836 | ], 837 | "description": "Symfony Routing Component", 838 | "homepage": "http://symfony.com", 839 | "time": "2013-05-20 08:57:26" 840 | }, 841 | { 842 | "name": "twig/twig", 843 | "version": "v1.13.1", 844 | "source": { 845 | "type": "git", 846 | "url": "https://github.com/fabpot/Twig.git", 847 | "reference": "v1.13.1" 848 | }, 849 | "dist": { 850 | "type": "zip", 851 | "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.1", 852 | "reference": "v1.13.1", 853 | "shasum": "" 854 | }, 855 | "require": { 856 | "php": ">=5.2.4" 857 | }, 858 | "type": "library", 859 | "extra": { 860 | "branch-alias": { 861 | "dev-master": "1.13-dev" 862 | } 863 | }, 864 | "autoload": { 865 | "psr-0": { 866 | "Twig_": "lib/" 867 | } 868 | }, 869 | "notification-url": "https://packagist.org/downloads/", 870 | "license": [ 871 | "BSD-3" 872 | ], 873 | "authors": [ 874 | { 875 | "name": "Fabien Potencier", 876 | "email": "fabien@symfony.com" 877 | }, 878 | { 879 | "name": "Armin Ronacher", 880 | "email": "armin.ronacher@active-4.com" 881 | } 882 | ], 883 | "description": "Twig, the flexible, fast, and secure template language for PHP", 884 | "homepage": "http://twig.sensiolabs.org", 885 | "keywords": [ 886 | "templating" 887 | ], 888 | "time": "2013-06-06 06:06:01" 889 | } 890 | ], 891 | "packages-dev": [ 892 | 893 | ], 894 | "aliases": [ 895 | 896 | ], 897 | "minimum-stability": "stable", 898 | "stability-flags": [ 899 | 900 | ], 901 | "platform": { 902 | "ext-curl": "*" 903 | }, 904 | "platform-dev": [ 905 | 906 | ] 907 | } 908 | -------------------------------------------------------------------------------- /config.ini.dist: -------------------------------------------------------------------------------- 1 | title="Composer Proxy JP" 2 | base_url="http://composer-proxy.jp/" 3 | 4 | ; Additional repositories 5 | ; repositories[packagist] = https://packagist.org 6 | -------------------------------------------------------------------------------- /console.php: -------------------------------------------------------------------------------- 1 | register('cache:clear-old-file') 20 | ->setDefinition(array( 21 | new InputOption('ttl', 't', InputOption::VALUE_OPTIONAL, 'ttl', 300), // 5 minutes 22 | new InputOption('dry-run', null, InputOption::VALUE_NONE, ''), 23 | new InputOption('without-hashed-file', null, InputOption::VALUE_NONE, ''), 24 | new InputOption('hashed-file-ttl', null, InputOption::VALUE_OPTIONAL, '', 60*60*24*30*6) //6 months 25 | )) 26 | ->setDescription('Clear old cache files') 27 | ->setCode(function (InputInterface $input, OutputInterface $output) use ($app) { 28 | $ttl = $input->getOption('ttl'); 29 | $dryRun = $input->getOption('dry-run'); 30 | $dryRunText = ''; 31 | if ($dryRun) { 32 | $dryRunText = ' (dry-run)'; 33 | } 34 | 35 | $finder = new Finder(); 36 | $fs = new Filesystem(); 37 | $finder->files() 38 | ->notName('/\$[0-9a-f]+\.json$/') 39 | ->date('until '.$ttl.' sec ago') 40 | ->in($app['cache_dir']); 41 | foreach ($finder as $file) { 42 | $output->writeln('Remove '.$file->getRealpath().$dryRunText.''); 43 | if (!$dryRun) { 44 | $fs->remove($file); 45 | } 46 | } 47 | 48 | if (!$input->getOption('without-hashed-file')) { 49 | $hashedFileFinder = new Finder(); 50 | $hashedFileTtl = $input->getOption('hashed-file-ttl'); 51 | $hashedFileFinder->files() 52 | ->name('/\$[0-9a-f]+\.json$/') 53 | ->date('until '.$hashedFileTtl.' sec ago') 54 | ->in($app['cache_dir']); 55 | foreach ($hashedFileFinder as $file) { 56 | $output->writeln('Remove '.$file->getRealpath().$dryRunText.''); 57 | if (!$dryRun) { 58 | $fs->remove($file); 59 | } 60 | } 61 | } 62 | }); 63 | 64 | $console 65 | ->register('cache:clear-all') 66 | ->setDefinition(array( 67 | new InputOption('dry-run', null, InputOption::VALUE_NONE, ''), 68 | )) 69 | ->setDescription('Clear all cache files') 70 | ->setCode(function (InputInterface $input, OutputInterface $output) use ($app) { 71 | $dryRun = $input->getOption('dry-run'); 72 | $dryRunText = ''; 73 | if ($dryRun) { 74 | $dryRunText = ' (dry-run)'; 75 | } 76 | $finder = new Finder(); 77 | $fs = new Filesystem(); 78 | $finder->files()->in($app['cache_dir']); 79 | foreach ($finder as $file) { 80 | $output->writeln('Remove '.$file->getRealpath().$dryRunText.''); 81 | if (!$dryRun) { 82 | $fs->remove($file); 83 | } 84 | } 85 | }); 86 | 87 | $console->run(); 88 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kawahara/composer-proxy/6a5f6831d2e995c56f8139b51d9afbc9f9efb5b3/logs/.gitkeep -------------------------------------------------------------------------------- /views/index.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ app.title }} 6 | 7 | 8 | 9 | 17 | 18 |
19 |
20 |
21 |
22 |

{{ app.title }}

23 |
24 |
25 |
26 |
27 | Shikumi 28 |
29 |
30 |

How to use?

31 | 1. Setup your $COMPOSER_HOME/config.json (You can edit by composer config -g -e). 32 |
{
33 |     "repositories": [
34 |         { "packagist": false },
35 |         {
36 |             "type": "composer",
37 |             "url": "{{ app.base_url }}proxy/packagist"
38 |         }
39 |     ]
40 | }
41 | 2. Enjoy 42 |

Notice

43 | When you use this proxy, you cannot use search and notice functions. I'll suport these functions in future. 44 |
45 |
46 |
47 | 48 |
49 | 56 | 57 |
58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Options -MultiViews 3 | 4 | RewriteEngine On 5 | RewriteBase / 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteRule ^ index.php [QSA,L] 8 | 9 | -------------------------------------------------------------------------------- /web/index.php: -------------------------------------------------------------------------------- 1 | run(); 16 | } else { 17 | $app['http_cache']->run(); 18 | } 19 | -------------------------------------------------------------------------------- /web/proxy/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kawahara/composer-proxy/6a5f6831d2e995c56f8139b51d9afbc9f9efb5b3/web/proxy/.gitkeep -------------------------------------------------------------------------------- /web/top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kawahara/composer-proxy/6a5f6831d2e995c56f8139b51d9afbc9f9efb5b3/web/top.jpg --------------------------------------------------------------------------------