1
0
Fork 0
mirror of https://codeberg.org/demostf/api.git synced 2026-06-03 18:04:08 +02:00
This commit is contained in:
Robin Appelman 2016-12-03 15:39:05 +01:00
commit 3061dda018
15 changed files with 1091 additions and 0 deletions

1
.dockerignore Normal file
View file

@ -0,0 +1 @@
.env

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.idea
.env
vendor

View file

@ -0,0 +1,72 @@
<?php namespace Controllers;
use Ehesp\SteamLogin\SteamLogin;
use Providers\AuthProvider;
use Providers\UserProvider;
class AuthController extends BaseController {
/**
* @var UserProvider
*/
private $userProvider;
/**
* @var AuthProvider
*/
private $authProvider;
/**
* AuthController constructor.
*
* @param UserProvider $userProvider
* @param AuthProvider $authProvider
*/
public function __construct(UserProvider $userProvider, AuthProvider $authProvider) {
$this->userProvider = $userProvider;
$this->authProvider = $authProvider;
}
public function token() {
echo $this->authProvider->generateToken();
}
public function get($token) {
$userData = $this->authProvider->getUser($token);
\Flight::json([
'token' => $token,
'steamid' => $userData['steamid'],
'name' => $userData['name'],
'key' => $userData['key']
]);
}
public function login($token) {
$_SESSION['return'] = $this->query('return', 'http://demos.tf');
$steam = new SteamLogin();
$url = $steam->url($_ENV['APP_ROOT'] . '/auth/handle/' . urlencode($token));
\Flight::redirect(str_replace('&amp;', '&', $url)); // headers make no sense
}
public function logout($token) {
$this->authProvider->logout($token);
\Flight::json([
'token' => $token,
'steamid' => null,
'name' => null,
'key' => null
]);
}
public function handle($token) {
$return = isset($_SESSION['return']) ? $_SESSION['return'] : 'http://demos.tf';
unset($_SESSION['return']);
$steam = new SteamLogin();
$steamId = $steam->validate();
if ($steamId) {
$steamIdObject = new \SteamId($steamId);
$key = $this->userProvider->store($steamIdObject);
$this->authProvider->setUser($token, $steamIdObject, $key);
}
\Flight::redirect($return);
}
}

View file

@ -0,0 +1,8 @@
<?php namespace Controllers;
class BaseController {
protected function query($name, $default) {
$request = \Flight::request();
return isset($request->query[$name]) ? $request->query[$name] : $default;
}
}

View file

@ -0,0 +1,82 @@
<?php namespace Controllers;
use flight\net\Route;
use Providers\DemoProvider;
use Providers\MatchProvider;
class DemoController extends BaseController {
/**
* @var \Providers\DemoProvider
*/
private $demoProvider;
public function __construct(DemoProvider $demoProvider) {
$this->demoProvider = $demoProvider;
}
/**
* @param string $id
*/
public function get($id) {
\Flight::json($this->demoProvider->get($id));
}
protected function getFilter() {
$map = $this->query('map', '');
$players = $this->query('players', '');
$type = $this->query('type', '');
$filter = [];
if ($map) {
$filter['map'] = $map;
}
if ($players) {
if (!is_array($players)) {
$players = explode(',', $players);
}
$players = array_filter($players);
$filter['players'] = $players;
}
switch ($type) {
case 'hl':
$filter['playerCount'] = [17, 18, 19];
break;
case '6v6':
$filter['playerCount'] = [11, 12, 13];
break;
case '4v4':
$filter['playerCount'] = [7, 8, 9];
break;
}
return $filter;
}
public function listDemos() {
$page = $this->query('page', 1);
\Flight::json($this->demoProvider->listDemos($page, $this->getFilter()));
}
public function listProfile($steamid) {
$page = $this->query('page', 1);
$where = $this->getFilter();
$where['players'][] = $steamid;
\Flight::json($this->demoProvider->listProfile($page, $where));
}
public function listUploads($steamid) {
$page = $this->query('page', 1);
\Flight::json($this->demoProvider->listUploads($steamid, $page, $this->getFilter()));
}
public function chat($demoId) {
\Flight::json($this->demoProvider->getChat($demoId));
}
public function listMaps() {
\Flight::json($this->demoProvider->listMaps());
}
public function stats() {
\Flight::json($this->demoProvider->getStats());
}
}

View file

@ -0,0 +1,30 @@
<?php namespace Controllers;
use Ehesp\SteamLogin\SteamLogin;
use Providers\AuthProvider;
use Providers\UserProvider;
class UserController extends BaseController {
/**
* @var UserProvider
*/
private $userProvider;
/**
* UserController constructor.
*
* @param UserProvider $userProvider
*/
public function __construct(UserProvider $userProvider) {
$this->userProvider = $userProvider;
}
public function get($steamid) {
\Flight::json($this->userProvider->get($steamid));
}
public function search() {
$query = $this->query('query', '');
\Flight::json($this->userProvider->search($query));
}
}

11
Dockerfile Normal file
View file

@ -0,0 +1,11 @@
FROM yavin/alpine-php-fpm:7.0
RUN apk add --no-cache php7-pdo_pgsql
COPY . /app/
RUN wget https://getcomposer.org/composer.phar \
&& php composer.phar -d=/app install --no-interaction \
&& rm composer.phar
RUN echo "clear_env = no" >> /etc/php7/php-fpm.conf

View file

@ -0,0 +1,37 @@
<?php namespace Providers;
use RandomLib\Generator;
class AuthProvider extends BaseProvider {
/**
* @var Generator
*/
private $generator;
public function __construct(\PDO $db, Generator $generator) {
parent::__construct($db);
$this->generator = $generator;
}
public function generateToken() {
return $this->generator->generateString(32, Generator::CHAR_ALNUM);
}
public function setUser($token, \SteamId $steamid, $key) {
apc_store($token, [
'name' => $steamid->getNickname(),
'steamid' => $steamid->getSteamId64(),
'key' => $key
]);
}
public function getUser($token) {
$found = true;
$result = apc_fetch($token, $found);
return ($found) ? $result : ['name' => null, 'steamid' => null, 'key' => null];
}
public function logout($token) {
apc_delete($token);
}
}

View file

@ -0,0 +1,59 @@
<?php namespace Providers;
use LessQL\Database;
class BaseProvider {
/**
* @var \PDO
*/
protected $pdo;
/**
* @var \LessQL\Database
*/
protected $db;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
$this->db = new Database($pdo);
$this->dbConfig();
}
private function dbConfig() {
$driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
if ($driver === 'mysql') {
$this->db->setIdentifierDelimiter("`");
} else {
$this->db->setIdentifierDelimiter('"');
}
$this->db->setRewrite(function ($table) {
$rawNames = ['chat'];
$aliases = [
];
if (isset($aliases[$table])) {
return $aliases[$table];
} else if (array_search($table, $rawNames) === false) {
return $table . 's';
} else {
return $table;
}
});
}
protected function query($sql, array $params = []) {
$delimiter = $this->db->getIdentifierDelimiter();
$driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
$sql = str_replace('`', $delimiter, $sql);
if ($driver === 'pgsql') {
$sql = str_replace('FROM_UNIXTIME(', 'to_timestamp(', $sql);
}
$query = $this->pdo->prepare($sql, $params);
$query->execute($params);
return $query;
}
}

165
Providers/DemoProvider.php Normal file
View file

@ -0,0 +1,165 @@
<?php namespace Providers;
class DemoProvider extends BaseProvider {
public function get($id) {
$demo = $this->db->demo()->where('id', $id);
// sql magic
$sql = 'WITH demokills AS (SELECT attacker_id, assister_id, victim_id FROM kills WHERE demo_id = ?)
SELECT players.id, user_id, players.name, team, class, users.steamid, users.avatar,
(SELECT COUNT(*) FROM demokills WHERE attacker_id=players.user_id) AS kills,
(SELECT COUNT(*) FROM demokills WHERE assister_id=players.user_id) AS assists,
(SELECT COUNT(*) FROM demokills WHERE victim_id=players.user_id) AS deaths
FROM players
INNER JOIN demos ON demos.id = players.demo_id
INNER JOIN users ON players.user_id = users.id
WHERE demo_id = ?
';
$uploader = $demo->user()->via('uploader')->fetch();
$demoData = $demo->fetch();
$playerQuery = $this->query($sql, [$demoData['id'], $demoData['id']]);
$players = $playerQuery->fetchAll(\PDO::FETCH_ASSOC);
$formattedDemo = $this->formatDemo($demoData);
$formattedDemo['players'] = $players;
$formattedDemo['uploader'] = [
'id' => $uploader['id'],
'steamid' => $uploader['steamid'],
'name' => $uploader['name']
];
return $formattedDemo;
}
public function listUploads($steamid, $page, $where = []) {
$user = $this->db->user()->where('steamid', $steamid);
$where['uploader'] = $user->fetch()->id;
return $this->listDemos($page, $where);
}
public function listProfile($page, $where = []) {
$users = $this->db->user()->where('steamid', $where['players']);
unset($where['players']);
$userIds = [];
foreach ($users as $user) {
$userIds[] = $user['id'];
}
$in = implode(', ', array_fill(0, count($userIds), '?'));
$sql = 'SELECT demos.id FROM demos INNER JOIN players ON players.demo_id = demos.id
WHERE players.user_id IN (' . $in . ') GROUP BY demos.id HAVING COUNT(user_id) = ? ORDER BY demos.id DESC LIMIT 50 OFFSET ' . ((int)$page - 1) * 50;
$params = $userIds;
$params[] = count($userIds);
$result = $this->query($sql, $params);
$demoIds = $result->fetchAll(\PDO::FETCH_COLUMN);
$demos = $this->db->demo()->where('id', $demoIds)
->where($where)
->orderBy('id', 'DESC');
return $this->formatList($demos);
}
public function listDemos($page, $where = []) {
if (isset($where['players']) and is_array($where['players']) and count($where['players']) > 0) {
return $this->listProfile($page, $where);
}
$offset = ($page - 1) * 50;
$params = [];
$sql = 'SELECT demos.* FROM demos LEFT OUTER JOIN upload_blacklist ON demos.uploader = uploader_id
WHERE upload_blacklist.id IS null';
if (isset($where['map'])) {
$sql .= ' AND demos.map = ?';
$params[] = $where['map'];
}
if (isset($where['playerCount'])) {
$placeholder = implode(', ', array_fill(0, count($where['playerCount']), '?'));
$sql .= ' AND "playerCount" IN (' . $placeholder . ')';
foreach ($where['playerCount'] as $playerCount) {
$params[] = $playerCount;
}
}
$sql .= ' ORDER BY demos.id DESC LIMIT 50 OFFSET ' . $offset;
$result = $this->query($sql, $params);
$demos = $result->fetchAll();
return $this->formatList($demos);
}
public function listMaps() {
$sql = 'SELECT DISTINCT(map), COUNT(map) AS count from demos GROUP BY map ORDER BY count DESC';
$result = $this->query($sql);
return $result->fetchAll(\PDO::FETCH_COLUMN);
}
public function getChat($demoId) {
$chat = $this->db->chat()->where('demo_id', $demoId);
$result = [];
foreach ($chat as $message) {
$result[] = [
'message' => $message['text'],
'user' => $message['from'],
'time' => $message['time']
];
}
return $result;
}
protected function formatList($demos) {
$result = [];
foreach ($demos as $demo) {
$result[] = $this->formatDemo($demo);
}
return $result;
}
private function formatDemo($demoData) {
return [
'id' => $demoData['id'],
'url' => $demoData['url'],
'name' => $demoData['name'],
'server' => $demoData['server'],
'duration' => $demoData['duration'],
'nick' => $demoData['nick'],
'map' => $demoData['map'],
'time' => strtotime($demoData['created_at']),
'red' => $demoData['red'],
'blue' => $demoData['blu'],
'redScore' => $demoData['scoreRed'],
'blueScore' => $demoData['scoreBlue'],
'playerCount' => $demoData['playerCount'],
'uploader' => $demoData['uploader']
];
}
private function formatTeam($teamInfo) {
if ($teamInfo === null) {
return $teamInfo;
}
return [
'id' => $teamInfo['id'],
'profileId' => $teamInfo['profile_id'],
'name' => $teamInfo['name'],
'tag' => $teamInfo['tag'],
'avatar' => $teamInfo['avatar'],
'steam' => $teamInfo['steam'],
'league' => $teamInfo['league'],
'division' => $teamInfo['division']
];
}
public function getStats() {
$demoCount = $this->db->demo()->count();
$playerCount = $this->db->user()->count();
$sql = 'SELECT count(user_id) FROM players GROUP BY user_id';
$result = $this->query($sql);
return [
'demos' => $demoCount,
'players' => $playerCount,
'uploaders' => $result->fetchColumn()
];
}
}

View file

@ -0,0 +1,81 @@
<?php namespace Providers;
use RandomLib\Generator;
class UserProvider extends BaseProvider {
/**
* @var Generator
*/
private $generator;
public function __construct(\PDO $db, Generator $generator) {
parent::__construct($db);
$this->generator = $generator;
}
public function store(\SteamId $steamId) {
$sql = 'INSERT INTO users(steamid, name, avatar, token)
SELECT ?, ?, ?, ? WHERE NOT EXISTS(SELECT id FROM users WHERE steamid = ?)';
$this->query($sql, [
$steamId->getSteamId64(),
$steamId->getNickname(),
$steamId->getMediumAvatarUrl(),
$this->generator->generateString(64),
$steamId->getSteamId64()
]);
$user = $this->db->user()->where('steamid', $steamId->getSteamId64());
return $user->fetch()->token;
}
public function get($steamid) {
$user = $this->db->user()->where('steamid', $steamid)->fetch();
if (count($user) < 1) {
return null;
}
return [
'id' => $user['id'],
'steamid' => $user['steamid'],
'name' => $user['name'],
'avatar' => $user['avatar']
];
}
public function search($query) {
$sql = 'SELECT user_id, players.name, count(demo_id) AS count, steamid,
1-(players.name <-> ?) AS sim FROM players
INNER JOIN users ON users.id = players.user_id
WHERE players.name % ? OR players.name ~* ?
GROUP BY players.name, user_id, steamid
ORDER BY count DESC
LIMIT 100';
$result = $this->query($sql, [$query, $query, $query]);
$players = $result->fetchAll(\PDO::FETCH_ASSOC);
usort($players, function ($b, $a) {
$countWeight = 1;
$simWeight = 5;
$diff = ($a['sim'] * $simWeight + $a['count'] * $countWeight) - ($b['sim'] * $simWeight + $b['count'] * $countWeight);
if ($diff === 0) {
return 0;
} else {
return ($diff < 0) ? -1 : 1;
}
});
$result = [];
foreach ($players as $player) {
$id = $player['user_id'];
if (!isset($result[$id])) {
$result[$id] = [
'id' => $id,
'name' => $player['name'],
'steamid' => $player['steamid']
];
}
}
$players = array_values($result);
return $players;
}
}

56
app.php Normal file
View file

@ -0,0 +1,56 @@
<?php
$autoloader = require 'vendor/autoload.php';
$autoloader->setPsr4('Providers\\', __DIR__ . '/Providers');
$autoloader->setPsr4('Controllers\\', __DIR__ . '/Controllers');
if (!getenv('DB_TYPE')) {
Dotenv::load(__DIR__);
}
$dsn = getenv('DB_TYPE') . ':dbname=' . getenv('DB_DATABASE') . ';host=' . getenv('DB_HOST');
$db = new \PDO($dsn, getenv('DB_USERNAME'), getenv('DB_PASSWORD'));
$demoProvider = new \Providers\DemoProvider($db);
$factory = new \RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
$authProvider = new \Providers\AuthProvider($db, $generator);
$userProvider = new \Providers\UserProvider($db, $generator);
$demoController = new \Controllers\DemoController($demoProvider);
$authController = new \Controllers\AuthController($userProvider, $authProvider);
$userController = new \Controllers\UserController($userProvider);
Flight::route('/*', function () {
header('Access-Control-Allow-Origin: *');
return true;
});
Flight::route('/auth/*', function () {
session_start();
return true;
});
Flight::route('/', function () {
echo 'hello world!';
});
Flight::route('/maps', [$demoController, 'listMaps']);
Flight::route('/stats', [$demoController, 'stats']);
Flight::route('/demos', [$demoController, 'listDemos']);
Flight::route('/demos/@id', [$demoController, 'get']);
Flight::route('/demos/@id/chat', [$demoController, 'chat']);
Flight::route('/profiles/@steamid', [$demoController, 'listProfile']);
Flight::route('/uploads/@steamid', [$demoController, 'listUploads']);
Flight::route('/users/search', [$userController, 'search']);
Flight::route('/users/@steamid', [$userController, 'get']);
Flight::route('/auth/token', [$authController, 'token']);
Flight::route('/auth/get/@token', [$authController, 'get']);
Flight::route('/auth/handle/@token', [$authController, 'handle']);
Flight::route('/auth/login/@token', [$authController, 'login']);
Flight::route('/auth/logout/@token', [$authController, 'logout']);
Flight::start();

16
composer.json Normal file
View file

@ -0,0 +1,16 @@
{
"require": {
"mikecao/flight": "^1.2",
"morris/lessql": "^0.3.0",
"vlucas/phpdotenv": "^1.1",
"symfony/var-dumper": "^2.6",
"ircmaxell/random-lib": "^1.1",
"ehesp/steam-login": "^1.0",
"koraktor/steam-condenser": "^1.3"
},
"autoload": {
"files": [
"vendor/koraktor/steam-condenser/lib/steam-condenser.php"
]
}
}

467
composer.lock generated Normal file
View file

@ -0,0 +1,467 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "f9c0deb7ba4faa02958b9793adf60e58",
"content-hash": "4db06a90a82f7878a5108f54ee134ee0",
"packages": [
{
"name": "ehesp/steam-login",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/Ehesp/Steam-Login.git",
"reference": "a126370d9befb103dcee2c75b70890543b365709"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Ehesp/Steam-Login/zipball/a126370d9befb103dcee2c75b70890543b365709",
"reference": "a126370d9befb103dcee2c75b70890543b365709",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"suggest": {
"koraktor/steam-condenser": "Library for querying the Steam Community, Source and GoldSrc game servers as well as the Steam master servers."
},
"type": "library",
"autoload": {
"psr-0": {
"Ehesp\\SteamLogin": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Elliot Hesp",
"email": "elliot.hesp@gmail.com"
}
],
"description": "A simple PHP Steam login and validation package",
"keywords": [
"steam"
],
"time": "2016-04-14 16:24:31"
},
{
"name": "ircmaxell/random-lib",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/ircmaxell/RandomLib.git",
"reference": "e9e0204f40e49fa4419946c677eccd3fa25b8cf4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ircmaxell/RandomLib/zipball/e9e0204f40e49fa4419946c677eccd3fa25b8cf4",
"reference": "e9e0204f40e49fa4419946c677eccd3fa25b8cf4",
"shasum": ""
},
"require": {
"ircmaxell/security-lib": "^1.1",
"php": ">=5.3.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^1.11",
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": "^4.8|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-0": {
"RandomLib": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Ferrara",
"email": "ircmaxell@ircmaxell.com",
"homepage": "http://blog.ircmaxell.com"
}
],
"description": "A Library For Generating Secure Random Numbers",
"homepage": "https://github.com/ircmaxell/RandomLib",
"keywords": [
"cryptography",
"random",
"random-numbers",
"random-strings"
],
"time": "2016-09-07 15:52:06"
},
{
"name": "ircmaxell/security-lib",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/ircmaxell/SecurityLib.git",
"reference": "f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ircmaxell/SecurityLib/zipball/f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5",
"reference": "f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"mikey179/vfsstream": "1.1.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"SecurityLib": "lib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Anthony Ferrara",
"email": "ircmaxell@ircmaxell.com",
"homepage": "http://blog.ircmaxell.com"
}
],
"description": "A Base Security Library",
"homepage": "https://github.com/ircmaxell/SecurityLib",
"time": "2015-03-20 14:31:23"
},
{
"name": "koraktor/steam-condenser",
"version": "1.3.10",
"source": {
"type": "git",
"url": "https://github.com/koraktor/steam-condenser-php.git",
"reference": "a75269e9ff9444d3bf1dfd49a0dfe072316373e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/koraktor/steam-condenser-php/zipball/a75269e9ff9444d3bf1dfd49a0dfe072316373e6",
"reference": "a75269e9ff9444d3bf1dfd49a0dfe072316373e6",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpunit/phpunit": "~3.7.0"
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"lib/"
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Staudt",
"email": "koraktor@gmail.com"
}
],
"description": "The Steam Condenser is a library for querying the Steam Community, Source and GoldSrc game servers",
"homepage": "http://koraktor.de/steam-condenser",
"keywords": [
"community",
"goldsrc",
"query",
"source",
"steam",
"webapi"
],
"time": "2015-03-19 09:43:24"
},
{
"name": "mikecao/flight",
"version": "v1.3.2",
"source": {
"type": "git",
"url": "https://github.com/mikecao/flight.git",
"reference": "c3c6f689099937e6e4ecf25b7fe8c780df1500f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mikecao/flight/zipball/c3c6f689099937e6e4ecf25b7fe8c780df1500f9",
"reference": "c3c6f689099937e6e4ecf25b7fe8c780df1500f9",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.6"
},
"type": "library",
"autoload": {
"files": [
"flight/autoload.php",
"flight/Flight.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike Cao",
"email": "mike@mikecao.com",
"homepage": "http://www.mikecao.com/",
"role": "Original Developer"
}
],
"description": "Flight is a fast, simple, extensible framework for PHP. Flight enables you to quickly and easily build RESTful web applications.",
"homepage": "http://flightphp.com",
"time": "2016-10-25 19:27:20"
},
{
"name": "morris/lessql",
"version": "v0.3.4",
"source": {
"type": "git",
"url": "https://github.com/morris/lessql.git",
"reference": "ff6c631e3abf1d3ee618f5262be4cc6ed09f6957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/morris/lessql/zipball/ff6c631e3abf1d3ee618f5262be4cc6ed09f6957",
"reference": "ff6c631e3abf1d3ee618f5262be4cc6ed09f6957",
"shasum": ""
},
"require": {
"php": ">=5.3.4"
},
"require-dev": {
"codeclimate/php-test-reporter": "dev-master",
"phpunit/phpunit": "~4.6"
},
"type": "library",
"autoload": {
"psr-0": {
"": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Morris Brodersen",
"homepage": "http://morrisbrodersen.de"
}
],
"description": "LessQL: The agile PHP ORM alternative",
"homepage": "http://github.com/morris/lessql",
"keywords": [
"database",
"notorm",
"orm",
"pdo",
"sql"
],
"time": "2016-07-06 15:10:11"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2016-11-14 01:06:16"
},
{
"name": "symfony/var-dumper",
"version": "v2.8.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "195c6238ec319cde9204b2d7f271654ceb69b71b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/195c6238ec319cde9204b2d7f271654ceb69b71b",
"reference": "195c6238ec319cde9204b2d7f271654ceb69b71b",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"twig/twig": "~1.20|~2.0"
},
"suggest": {
"ext-symfony_debug": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"files": [
"Resources/functions/dump.php"
],
"psr-4": {
"Symfony\\Component\\VarDumper\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony mechanism for exploring and dumping PHP variables",
"homepage": "https://symfony.com",
"keywords": [
"debug",
"dump"
],
"time": "2016-11-03 07:52:58"
},
{
"name": "vlucas/phpdotenv",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/vlucas/phpdotenv.git",
"reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa",
"reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Dotenv": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD"
],
"authors": [
{
"name": "Vance Lucas",
"email": "vance@vancelucas.com",
"homepage": "http://www.vancelucas.com"
}
],
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
"homepage": "http://github.com/vlucas/phpdotenv",
"keywords": [
"dotenv",
"env",
"environment"
],
"time": "2015-05-30 15:59:26"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}

3
public/index.php Normal file
View file

@ -0,0 +1,3 @@
<?php
require '../app.php';