mirror of
https://github.com/LBRYFoundation/lbry.com.git
synced 2025-08-23 09:37:26 +00:00
Adjust site to use PSR-2 coding standard
This commit is contained in:
parent
3acdae342e
commit
771b205d79
74 changed files with 3377 additions and 3739 deletions
121
autoload.php
121
autoload.php
|
@ -1,80 +1,71 @@
|
||||||
<?php
|
<?php
|
||||||
class Autoloader
|
class Autoloader
|
||||||
{
|
{
|
||||||
public static $classes = [];
|
public static $classes = [];
|
||||||
|
|
||||||
public static function autoload($class)
|
public static function autoload($class)
|
||||||
{
|
|
||||||
if (class_exists($class, false) || interface_exists($class, false))
|
|
||||||
{
|
{
|
||||||
return true;
|
if (class_exists($class, false) || interface_exists($class, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$class = strtolower($class);
|
||||||
|
$path = static::$classes[$class] ?? false;
|
||||||
|
|
||||||
|
if ($path) {
|
||||||
|
require_once $path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = strtolower($class);
|
public static function reload($reload = false)
|
||||||
$path = static::$classes[$class] ?? false;
|
|
||||||
|
|
||||||
if ($path)
|
|
||||||
{
|
{
|
||||||
require_once $path;
|
$key = 'lbry-classes-5';
|
||||||
return true;
|
if (ini_get('apc.enabled') && !$reload) {
|
||||||
|
$classes = apc_fetch($key, $success);
|
||||||
|
if ($success) {
|
||||||
|
static::$classes = $classes;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$classes = [];
|
||||||
|
|
||||||
|
$dir = new RecursiveDirectoryIterator(ROOT_DIR, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||||
|
$ite = new RecursiveIteratorIterator($dir);
|
||||||
|
$pathIterator = new RegexIterator($ite, '/.*\.php$/', RegexIterator::GET_MATCH);
|
||||||
|
foreach ($pathIterator as $paths) {
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
static::$classes += static::parseFile($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ini_get('apc.enabled')) {
|
||||||
|
apc_store($key, static::$classes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
protected static function parseFile($path)
|
||||||
}
|
|
||||||
|
|
||||||
public static function reload($reload = false)
|
|
||||||
{
|
|
||||||
$key = 'lbry-classes-5';
|
|
||||||
if (ini_get('apc.enabled') && !$reload)
|
|
||||||
{
|
{
|
||||||
$classes = apc_fetch($key, $success);
|
$mapping = [];
|
||||||
if ($success)
|
$classes = [];
|
||||||
{
|
|
||||||
static::$classes = $classes;
|
preg_match_all('~^\s*(?:namespace)\s+([^;]+)~mi', file_get_contents($path), $namespaces);
|
||||||
return;
|
preg_match_all('~^\s*(?:abstract\s+|final\s+)?(?:class|interface)\s+(\w+)~mi', file_get_contents($path), $classes);
|
||||||
}
|
|
||||||
|
if (isset($namespaces[1]) && count($namespaces[1]) > 2) {
|
||||||
|
throw new RuntimeException('Autoloader cannot handle 2 namespaces in the same file');
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = isset($namespaces[1]) && count($namespaces[1]) ? reset($namespaces[1]) . '\\' : '';
|
||||||
|
|
||||||
|
foreach ($classes[1] as $class) {
|
||||||
|
$mapping[strtolower($prefix . $class)] = $path;
|
||||||
|
}
|
||||||
|
return $mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
static::$classes = [];
|
|
||||||
|
|
||||||
$dir = new RecursiveDirectoryIterator(ROOT_DIR, RecursiveDirectoryIterator::SKIP_DOTS);
|
|
||||||
$ite = new RecursiveIteratorIterator($dir);
|
|
||||||
$pathIterator = new RegexIterator($ite, '/.*\.php$/', RegexIterator::GET_MATCH);
|
|
||||||
foreach($pathIterator as $paths)
|
|
||||||
{
|
|
||||||
foreach($paths as $path)
|
|
||||||
{
|
|
||||||
static::$classes += static::parseFile($path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ini_get('apc.enabled'))
|
|
||||||
{
|
|
||||||
apc_store($key, static::$classes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function parseFile($path)
|
|
||||||
{
|
|
||||||
$mapping = [];
|
|
||||||
$classes = [];
|
|
||||||
|
|
||||||
preg_match_all('~^\s*(?:namespace)\s+([^;]+)~mi', file_get_contents($path), $namespaces);
|
|
||||||
preg_match_all('~^\s*(?:abstract\s+|final\s+)?(?:class|interface)\s+(\w+)~mi', file_get_contents($path), $classes);
|
|
||||||
|
|
||||||
if (isset($namespaces[1]) && count($namespaces[1]) > 2)
|
|
||||||
{
|
|
||||||
throw new RuntimeException('Autoloader cannot handle 2 namespaces in the same file');
|
|
||||||
}
|
|
||||||
|
|
||||||
$prefix = isset($namespaces[1]) && count($namespaces[1]) ? reset($namespaces[1]) . '\\' : '';
|
|
||||||
|
|
||||||
foreach ($classes[1] as $class)
|
|
||||||
{
|
|
||||||
$mapping[strtolower($prefix . $class)] = $path;
|
|
||||||
}
|
|
||||||
return $mapping;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
define('ROOT_DIR', __DIR__);
|
define('ROOT_DIR', __DIR__);
|
||||||
date_default_timezone_set('Etc/UTC');
|
date_default_timezone_set('Etc/UTC');
|
||||||
require ROOT_DIR . '/autoload.php';
|
require ROOT_DIR . '/autoload.php';
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
class Actions
|
class Actions
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,208 +2,184 @@
|
||||||
|
|
||||||
class Controller
|
class Controller
|
||||||
{
|
{
|
||||||
const CACHE_CLEAR_PATH = '/clear-cache';
|
const CACHE_CLEAR_PATH = '/clear-cache';
|
||||||
|
|
||||||
protected static $queuedFunctions = [];
|
protected static $queuedFunctions = [];
|
||||||
|
|
||||||
public static function dispatch($uri)
|
public static function dispatch($uri)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (IS_PRODUCTION && function_exists('newrelic_name_transaction'))
|
try {
|
||||||
{
|
if (IS_PRODUCTION && function_exists('newrelic_name_transaction')) {
|
||||||
newrelic_name_transaction(Request::getMethod() . ' ' . strtolower($uri));
|
newrelic_name_transaction(Request::getMethod() . ' ' . strtolower($uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
$viewAndParams = static::execute(Request::getMethod(), $uri);
|
$viewAndParams = static::execute(Request::getMethod(), $uri);
|
||||||
$viewTemplate = $viewAndParams[0];
|
$viewTemplate = $viewAndParams[0];
|
||||||
$viewParameters = $viewAndParams[1] ?? [];
|
$viewParameters = $viewAndParams[1] ?? [];
|
||||||
if (!IS_PRODUCTION && isset($viewAndParams[2]))
|
if (!IS_PRODUCTION && isset($viewAndParams[2])) {
|
||||||
{
|
throw new Exception('use response::setheader instead of returning headers');
|
||||||
throw new Exception('use response::setheader instead of returning headers');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!$viewTemplate)
|
if (!$viewTemplate) {
|
||||||
{
|
if ($viewTemplate !== null) {
|
||||||
if ($viewTemplate !== null)
|
throw new LogicException('All execute methods must return a template or NULL.');
|
||||||
{
|
}
|
||||||
throw new LogicException('All execute methods must return a template or NULL.');
|
} else {
|
||||||
|
$layout = !(isset($viewParameters['_no_layout']) && $viewParameters['_no_layout']);
|
||||||
|
unset($viewParameters['_no_layout']);
|
||||||
|
|
||||||
|
$layoutParams = $viewParameters[View::LAYOUT_PARAMS] ?? [];
|
||||||
|
unset($viewParameters[View::LAYOUT_PARAMS]);
|
||||||
|
|
||||||
|
$content = View::render($viewTemplate, $viewParameters + ['fullPage' => true]);
|
||||||
|
|
||||||
|
Response::setContent($layout ? View::render('layout/basic', ['content' => $content] + $layoutParams) : $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::setDefaultSecurityHeaders();
|
||||||
|
if (Request::isGzipAccepted()) {
|
||||||
|
Response::gzipContentIfNotDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::send();
|
||||||
|
} catch (StopException $e) {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$layout = !(isset($viewParameters['_no_layout']) && $viewParameters['_no_layout']);
|
|
||||||
unset($viewParameters['_no_layout']);
|
|
||||||
|
|
||||||
$layoutParams = $viewParameters[View::LAYOUT_PARAMS] ?? [];
|
|
||||||
unset($viewParameters[View::LAYOUT_PARAMS]);
|
|
||||||
|
|
||||||
$content = View::render($viewTemplate, $viewParameters + ['fullPage' => true]);
|
|
||||||
|
|
||||||
Response::setContent($layout ? View::render('layout/basic', ['content' => $content] + $layoutParams) : $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
Response::setDefaultSecurityHeaders();
|
|
||||||
if (Request::isGzipAccepted())
|
|
||||||
{
|
|
||||||
Response::gzipContentIfNotDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
Response::send();
|
|
||||||
}
|
}
|
||||||
catch (StopException $e)
|
|
||||||
|
public static function execute($method, $uri)
|
||||||
{
|
{
|
||||||
|
$router = static::getRouterWithRoutes();
|
||||||
|
static::performSubdomainRedirects();
|
||||||
|
try {
|
||||||
|
$dispatcher = new Routing\Dispatcher($router->getData());
|
||||||
|
return $dispatcher->dispatch($method, $uri);
|
||||||
|
} catch (\Routing\HttpRouteNotFoundException $e) {
|
||||||
|
return NavActions::execute404();
|
||||||
|
} catch (\Routing\HttpMethodNotAllowedException $e) {
|
||||||
|
Response::setStatus(405);
|
||||||
|
Response::setHeader('Allow', implode(', ', $e->getAllowedMethods()));
|
||||||
|
return ['page/405'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function execute($method, $uri)
|
protected static function performSubdomainRedirects()
|
||||||
{
|
|
||||||
$router = static::getRouterWithRoutes();
|
|
||||||
static::performSubdomainRedirects();
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
$dispatcher = new Routing\Dispatcher($router->getData());
|
$subDomain = Request::getSubDomain();
|
||||||
return $dispatcher->dispatch($method, $uri);
|
|
||||||
}
|
|
||||||
catch (\Routing\HttpRouteNotFoundException $e)
|
|
||||||
{
|
|
||||||
return NavActions::execute404();
|
|
||||||
}
|
|
||||||
catch (\Routing\HttpMethodNotAllowedException $e)
|
|
||||||
{
|
|
||||||
Response::setStatus(405);
|
|
||||||
Response::setHeader('Allow', implode(', ', $e->getAllowedMethods()));
|
|
||||||
return ['page/405'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function performSubdomainRedirects()
|
switch ($subDomain) {
|
||||||
{
|
|
||||||
$subDomain = Request::getSubDomain();
|
|
||||||
|
|
||||||
switch($subDomain) {
|
|
||||||
case 'chat':
|
case 'chat':
|
||||||
case 'slack':
|
case 'slack':
|
||||||
return static::redirect('https://discord.gg/Z3bERWA');
|
return static::redirect('https://discord.gg/Z3bERWA');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getRouterWithRoutes(): \Routing\RouteCollector
|
|
||||||
{
|
|
||||||
$router = new Routing\RouteCollector();
|
|
||||||
|
|
||||||
$router->get(['/', 'home'], 'ContentActions::executeHome');
|
|
||||||
|
|
||||||
$router->get(['/get', 'get'], 'DownloadActions::executeGet');
|
|
||||||
$router->get(['/getrubin', 'getrubin'], 'DownloadActions::executeGet');
|
|
||||||
foreach(array_keys(OS::getAll()) as $os)
|
|
||||||
{
|
|
||||||
$router->get(['/' . $os, 'get-' . $os], 'DownloadActions::executeGet');
|
|
||||||
}
|
|
||||||
$router->get('/roadmap', 'ContentActions::executeRoadmap');
|
|
||||||
|
|
||||||
$router->post('/quickstart/auth', 'DeveloperActions::executeQuickstartAuth');
|
|
||||||
$router->get('/quickstart/{step}?', 'DeveloperActions::executeQuickstart');
|
|
||||||
$router->get('/quickstart/github/callback', 'DeveloperActions::executeQuickstartGithubCallback');
|
|
||||||
|
|
||||||
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');
|
|
||||||
|
|
||||||
$router->post('/postcommit', 'OpsActions::executePostCommit');
|
|
||||||
$router->post('/log-upload', 'OpsActions::executeLogUpload');
|
|
||||||
$router->get(static::CACHE_CLEAR_PATH, 'OpsActions::executeClearCache');
|
|
||||||
|
|
||||||
$router->any('/list/subscribe', 'MailActions::executeSubscribe');
|
|
||||||
$router->any('/list/subscribed', 'MailActions::executeSubscribed');
|
|
||||||
$router->get('/list/unsubscribe/{email}', 'MailActions::executeUnsubscribe');
|
|
||||||
|
|
||||||
$router->any('/dmca', 'ReportActions::executeDmca');
|
|
||||||
|
|
||||||
$router->any('/youtube/sub', 'AcquisitionActions::executeYouTubeSub');
|
|
||||||
$router->post('/youtube/edit', 'AcquisitionActions::executeYoutubeEdit');
|
|
||||||
$router->post('/youtube/token', 'AcquisitionActions::executeYoutubeToken');
|
|
||||||
$router->any('/youtube/status/{token}', 'AcquisitionActions::executeYoutubeStatus');
|
|
||||||
$router->any('/youtube', 'AcquisitionActions::executeYouTube');
|
|
||||||
$router->any('/youtube/status', 'AcquisitionActions::executeRedirectYoutube');
|
|
||||||
|
|
||||||
$router->get('/verify/{token}', 'AcquisitionActions::executeVerify');
|
|
||||||
|
|
||||||
|
|
||||||
$router->get('/news/category/{category}', 'ContentActions::executePostCategoryFilter');
|
|
||||||
|
|
||||||
$router->post('/set-culture', 'i18nActions::setCulture');
|
|
||||||
|
|
||||||
$permanentRedirectsPath = ROOT_DIR . '/data/redirect/permanent.yaml';
|
|
||||||
$tempRedirectsPath = ROOT_DIR . '/data/redirect/temporary.yaml';
|
|
||||||
|
|
||||||
$permanentRedirects = SpyC::YAMLLoadString(file_get_contents($permanentRedirectsPath));
|
|
||||||
$tempRedirects = SpyC::YAMLLoadString(file_get_contents($tempRedirectsPath));
|
|
||||||
|
|
||||||
foreach ([307 => $tempRedirects, 301 => $permanentRedirects] as $code => $redirects)
|
|
||||||
{
|
|
||||||
foreach ($redirects as $src => $target)
|
|
||||||
{
|
|
||||||
$router->any($src, function () use ($target, $code) { return static::redirect($target, $code); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$router->any('/get/lbry.pre.{ext:c}', 'DownloadActions::executeGetAppPrereleaseRedirect');
|
protected static function getRouterWithRoutes(): \Routing\RouteCollector
|
||||||
$router->any('/get/lbry.{ext:c}', 'DownloadActions::executeGetAppRedirect');
|
{
|
||||||
$router->any('/get/lbrynet.{os:c}.zip', 'DownloadActions::executeGetDaemonRedirect');
|
$router = new Routing\RouteCollector();
|
||||||
|
|
||||||
$router->get([ContentActions::URL_NEWS . '/{slug:c}?', 'news'], 'ContentActions::executeNews');
|
$router->get(['/', 'home'], 'ContentActions::executeHome');
|
||||||
$router->get([ContentActions::URL_FAQ . '/{slug:c}?', 'faq'], 'ContentActions::executeFaq');
|
|
||||||
$router->get([ContentActions::URL_BOUNTY . '/{slug:c}?', 'bounty'], 'ContentActions::executeBounty');
|
$router->get(['/get', 'get'], 'DownloadActions::executeGet');
|
||||||
$router->get([ContentActions::URL_PRESS . '/{slug:c}', 'press'], 'ContentActions::executePress');
|
$router->get(['/getrubin', 'getrubin'], 'DownloadActions::executeGet');
|
||||||
|
foreach (array_keys(OS::getAll()) as $os) {
|
||||||
|
$router->get(['/' . $os, 'get-' . $os], 'DownloadActions::executeGet');
|
||||||
|
}
|
||||||
|
$router->get('/roadmap', 'ContentActions::executeRoadmap');
|
||||||
|
|
||||||
|
$router->post('/quickstart/auth', 'DeveloperActions::executeQuickstartAuth');
|
||||||
|
$router->get('/quickstart/{step}?', 'DeveloperActions::executeQuickstart');
|
||||||
|
$router->get('/quickstart/github/callback', 'DeveloperActions::executeQuickstartGithubCallback');
|
||||||
|
|
||||||
|
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');
|
||||||
|
|
||||||
|
$router->post('/postcommit', 'OpsActions::executePostCommit');
|
||||||
|
$router->post('/log-upload', 'OpsActions::executeLogUpload');
|
||||||
|
$router->get(static::CACHE_CLEAR_PATH, 'OpsActions::executeClearCache');
|
||||||
|
|
||||||
|
$router->any('/list/subscribe', 'MailActions::executeSubscribe');
|
||||||
|
$router->any('/list/subscribed', 'MailActions::executeSubscribed');
|
||||||
|
$router->get('/list/unsubscribe/{email}', 'MailActions::executeUnsubscribe');
|
||||||
|
|
||||||
|
$router->any('/dmca', 'ReportActions::executeDmca');
|
||||||
|
|
||||||
|
$router->any('/youtube/sub', 'AcquisitionActions::executeYouTubeSub');
|
||||||
|
$router->post('/youtube/edit', 'AcquisitionActions::executeYoutubeEdit');
|
||||||
|
$router->post('/youtube/token', 'AcquisitionActions::executeYoutubeToken');
|
||||||
|
$router->any('/youtube/status/{token}', 'AcquisitionActions::executeYoutubeStatus');
|
||||||
|
$router->any('/youtube', 'AcquisitionActions::executeYouTube');
|
||||||
|
$router->any('/youtube/status', 'AcquisitionActions::executeRedirectYoutube');
|
||||||
|
|
||||||
|
$router->get('/verify/{token}', 'AcquisitionActions::executeVerify');
|
||||||
|
|
||||||
|
|
||||||
|
$router->get('/news/category/{category}', 'ContentActions::executePostCategoryFilter');
|
||||||
|
|
||||||
|
$router->post('/set-culture', 'i18nActions::setCulture');
|
||||||
|
|
||||||
|
$permanentRedirectsPath = ROOT_DIR . '/data/redirect/permanent.yaml';
|
||||||
|
$tempRedirectsPath = ROOT_DIR . '/data/redirect/temporary.yaml';
|
||||||
|
|
||||||
|
$permanentRedirects = SpyC::YAMLLoadString(file_get_contents($permanentRedirectsPath));
|
||||||
|
$tempRedirects = SpyC::YAMLLoadString(file_get_contents($tempRedirectsPath));
|
||||||
|
|
||||||
|
foreach ([307 => $tempRedirects, 301 => $permanentRedirects] as $code => $redirects) {
|
||||||
|
foreach ($redirects as $src => $target) {
|
||||||
|
$router->any($src, function () use ($target, $code) {
|
||||||
|
return static::redirect($target, $code);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$router->any('/get/lbry.pre.{ext:c}', 'DownloadActions::executeGetAppPrereleaseRedirect');
|
||||||
|
$router->any('/get/lbry.{ext:c}', 'DownloadActions::executeGetAppRedirect');
|
||||||
|
$router->any('/get/lbrynet.{os:c}.zip', 'DownloadActions::executeGetDaemonRedirect');
|
||||||
|
|
||||||
|
$router->get([ContentActions::URL_NEWS . '/{slug:c}?', 'news'], 'ContentActions::executeNews');
|
||||||
|
$router->get([ContentActions::URL_FAQ . '/{slug:c}?', 'faq'], 'ContentActions::executeFaq');
|
||||||
|
$router->get([ContentActions::URL_BOUNTY . '/{slug:c}?', 'bounty'], 'ContentActions::executeBounty');
|
||||||
|
$router->get([ContentActions::URL_PRESS . '/{slug:c}', 'press'], 'ContentActions::executePress');
|
||||||
// $router->get([ContentActions::URL_CREDIT_REPORTS . '/{slug:c}?', 'faq'], 'ContentActions::executeFaq');
|
// $router->get([ContentActions::URL_CREDIT_REPORTS . '/{slug:c}?', 'faq'], 'ContentActions::executeFaq');
|
||||||
$router->get(ContentActions::URL_CREDIT_REPORTS, 'ContentActions::executeCreditReports');
|
$router->get(ContentActions::URL_CREDIT_REPORTS, 'ContentActions::executeCreditReports');
|
||||||
$router->get([ContentActions::URL_CREDIT_REPORTS . '/{year:c}-q{quarter:c}', ContentActions::URL_CREDIT_REPORTS . '/{year:c}-Q{quarter:c}'], 'ContentActions::executeCreditReport');
|
$router->get([ContentActions::URL_CREDIT_REPORTS . '/{year:c}-q{quarter:c}', ContentActions::URL_CREDIT_REPORTS . '/{year:c}-Q{quarter:c}'], 'ContentActions::executeCreditReport');
|
||||||
|
|
||||||
$router->get('/{slug}', function (string $slug)
|
$router->get('/{slug}', function (string $slug) {
|
||||||
{
|
if (View::exists('page/' . $slug)) {
|
||||||
if (View::exists('page/' . $slug))
|
Response::enableHttpCache();
|
||||||
{
|
return ['page/' . $slug, []];
|
||||||
Response::enableHttpCache();
|
} else {
|
||||||
return ['page/' . $slug, []];
|
return NavActions::execute404();
|
||||||
}
|
}
|
||||||
else
|
});
|
||||||
{
|
|
||||||
return NavActions::execute404();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return $router;
|
return $router;
|
||||||
}
|
|
||||||
|
|
||||||
public static function redirect($url, $statusCode = 302)
|
|
||||||
{
|
|
||||||
if (!$url)
|
|
||||||
{
|
|
||||||
throw new InvalidArgumentException('Cannot redirect to an empty URL.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = str_replace('&', '&', $url);
|
public static function redirect($url, $statusCode = 302)
|
||||||
|
|
||||||
Response::setStatus($statusCode);
|
|
||||||
|
|
||||||
if ($statusCode == 201 || ($statusCode >= 300 && $statusCode < 400))
|
|
||||||
{
|
{
|
||||||
Response::setHeader(Response::HEADER_LOCATION, $url);
|
if (!$url) {
|
||||||
|
throw new InvalidArgumentException('Cannot redirect to an empty URL.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = str_replace('&', '&', $url);
|
||||||
|
|
||||||
|
Response::setStatus($statusCode);
|
||||||
|
|
||||||
|
if ($statusCode == 201 || ($statusCode >= 300 && $statusCode < 400)) {
|
||||||
|
Response::setHeader(Response::HEADER_LOCATION, $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['internal/redirect', ['url' => $url]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['internal/redirect', ['url' => $url]];
|
public static function queueToRunAfterResponse(callable $fn)
|
||||||
}
|
|
||||||
|
|
||||||
public static function queueToRunAfterResponse(callable $fn)
|
|
||||||
{
|
|
||||||
static::$queuedFunctions[] = $fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function shutdown()
|
|
||||||
{
|
|
||||||
while ($fn = array_shift(static::$queuedFunctions))
|
|
||||||
{
|
{
|
||||||
call_user_func($fn);
|
static::$queuedFunctions[] = $fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function shutdown()
|
||||||
|
{
|
||||||
|
while ($fn = array_shift(static::$queuedFunctions)) {
|
||||||
|
call_user_func($fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,161 +2,158 @@
|
||||||
|
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
const GET = 'GET';
|
const GET = 'GET';
|
||||||
const POST = 'POST';
|
const POST = 'POST';
|
||||||
const HEAD = 'HEAD';
|
const HEAD = 'HEAD';
|
||||||
const OPTIONS = 'OPTIONS';
|
const OPTIONS = 'OPTIONS';
|
||||||
|
|
||||||
protected static $method;
|
protected static $method;
|
||||||
|
|
||||||
public static function getParam(string $key, $default = null)
|
public static function getParam(string $key, $default = null)
|
||||||
{
|
|
||||||
return $_POST[$key] ?? $_GET[$key] ?? $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPostParam(string $key, $default = null)
|
|
||||||
{
|
|
||||||
return $_POST[$key] ?? $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getMethod(): string
|
|
||||||
{
|
|
||||||
if (!static::$method)
|
|
||||||
{
|
{
|
||||||
$method = static::getHeader('REQUEST_METHOD') ? strtoupper(static::getHeader('REQUEST_METHOD')) : null;
|
return $_POST[$key] ?? $_GET[$key] ?? $default;
|
||||||
|
|
||||||
static::$method = in_array($method, [static::GET, static::POST, static::HEAD, static::OPTIONS]) ? $method : static::GET;
|
|
||||||
}
|
}
|
||||||
return static::$method;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getHeader(string $name, $default = null)
|
public static function getPostParam(string $key, $default = null)
|
||||||
{
|
{
|
||||||
return $_SERVER[strtoupper($name)] ?? $default;
|
return $_POST[$key] ?? $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getHttpHeader(string $name, $default = null)
|
public static function getMethod(): string
|
||||||
{
|
{
|
||||||
$header = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
|
if (!static::$method) {
|
||||||
return isset($_SERVER[$header]) ? static::stripSlashes($_SERVER[$header]) : $default;
|
$method = static::getHeader('REQUEST_METHOD') ? strtoupper(static::getHeader('REQUEST_METHOD')) : null;
|
||||||
}
|
|
||||||
|
|
||||||
protected static function stripSlashes($value)
|
static::$method = in_array($method, [static::GET, static::POST, static::HEAD, static::OPTIONS]) ? $method : static::GET;
|
||||||
{
|
}
|
||||||
return is_array($value) ? array_map(get_called_class() . '::stripSlashes', $value) : stripslashes($value);
|
return static::$method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function getHeader(string $name, $default = null)
|
||||||
|
{
|
||||||
|
return $_SERVER[strtoupper($name)] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getHttpHeader(string $name, $default = null)
|
||||||
|
{
|
||||||
|
$header = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
|
||||||
|
return isset($_SERVER[$header]) ? static::stripSlashes($_SERVER[$header]) : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function stripSlashes($value)
|
||||||
|
{
|
||||||
|
return is_array($value) ? array_map(get_called_class() . '::stripSlashes', $value) : stripslashes($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function isGet(): bool
|
public static function isGet(): bool
|
||||||
{
|
{
|
||||||
return static::getMethod() == static::GET;
|
return static::getMethod() == static::GET;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isPost(): bool
|
public static function isPost(): bool
|
||||||
{
|
{
|
||||||
return static::getMethod() == static::POST;
|
return static::getMethod() == static::POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isCacheableMethod(): bool
|
public static function isCacheableMethod(): bool
|
||||||
{
|
{
|
||||||
return in_array(static::getMethod(), [static::GET, static::HEAD]);
|
return in_array(static::getMethod(), [static::GET, static::HEAD]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOriginalIp(): string
|
public static function getOriginalIp(): string
|
||||||
{
|
{
|
||||||
return static::getHttpHeader('X-Real-Ip') ??
|
return static::getHttpHeader('X-Real-Ip') ??
|
||||||
(static::getHttpHeader('X-Forwarded-For') ? trim(explode(',', static::getHttpHeader('X-Forwarded-For'))[0]) :
|
(static::getHttpHeader('X-Forwarded-For') ? trim(explode(',', static::getHttpHeader('X-Forwarded-For'))[0]) :
|
||||||
static::getHeader('REMOTE_ADDR', ''));
|
static::getHeader('REMOTE_ADDR', ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getUserAgent(): string
|
public static function getUserAgent(): string
|
||||||
{
|
|
||||||
return static::getHttpHeader('User-Agent') ?? '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getRoutingUri()
|
|
||||||
{
|
|
||||||
$host = preg_replace('/^www\./', '', static::getHost());
|
|
||||||
switch($host)
|
|
||||||
{
|
{
|
||||||
|
return static::getHttpHeader('User-Agent') ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRoutingUri()
|
||||||
|
{
|
||||||
|
$host = preg_replace('/^www\./', '', static::getHost());
|
||||||
|
switch ($host) {
|
||||||
case 'betteryoutube.com':
|
case 'betteryoutube.com':
|
||||||
case 'lbrycreators.com':
|
case 'lbrycreators.com':
|
||||||
return '/youtube';
|
return '/youtube';
|
||||||
}
|
}
|
||||||
return static::getRelativeUri();
|
return static::getRelativeUri();
|
||||||
}
|
|
||||||
|
|
||||||
public static function getHost(): string
|
|
||||||
{
|
|
||||||
// apparently trailing period is legal: http://www.dns-sd.org/TrailingDotsInDomainNames.html
|
|
||||||
return static::getHttpHeader('Host') ? rtrim(static::getHttpHeader('Host'), '.') : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSubDomain(): string
|
|
||||||
{
|
|
||||||
$host = static::getHost();
|
|
||||||
$domainParts = explode('.', $host);
|
|
||||||
$domainPartCount = count($domainParts);
|
|
||||||
|
|
||||||
if (count($domainParts) < 1)
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$isLocalhost = $domainParts[$domainPartCount - 1] === 'localhost';
|
public static function getHost(): string
|
||||||
|
|
||||||
if (count($domainParts) < ($isLocalhost ? 2 : 3))
|
|
||||||
{
|
{
|
||||||
return '';
|
// apparently trailing period is legal: http://www.dns-sd.org/TrailingDotsInDomainNames.html
|
||||||
|
return static::getHttpHeader('Host') ? rtrim(static::getHttpHeader('Host'), '.') : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $isLocalhost ?
|
public static function getSubDomain(): string
|
||||||
|
{
|
||||||
|
$host = static::getHost();
|
||||||
|
$domainParts = explode('.', $host);
|
||||||
|
$domainPartCount = count($domainParts);
|
||||||
|
|
||||||
|
if (count($domainParts) < 1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$isLocalhost = $domainParts[$domainPartCount - 1] === 'localhost';
|
||||||
|
|
||||||
|
if (count($domainParts) < ($isLocalhost ? 2 : 3)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isLocalhost ?
|
||||||
$domainParts[$domainPartCount - 2] :
|
$domainParts[$domainPartCount - 2] :
|
||||||
$domainParts[$domainPartCount - 3];
|
$domainParts[$domainPartCount - 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getHostAndProto(): string
|
public static function getHostAndProto(): string
|
||||||
{
|
{
|
||||||
return (static::isSSL() ? 'https' : 'http') . '://' . static::getHost();
|
return (static::isSSL() ? 'https' : 'http') . '://' . static::getHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isSSL(): bool
|
public static function isSSL(): bool
|
||||||
{
|
{
|
||||||
return static::getHeader('HTTPS') || strtolower(static::getHttpHeader('X_FORWARDED_PROTO')) == 'https';
|
return static::getHeader('HTTPS') || strtolower(static::getHttpHeader('X_FORWARDED_PROTO')) == 'https';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getServerName(): string
|
public static function getServerName(): string
|
||||||
{
|
{
|
||||||
return static::getHeader('SERVER_NAME');
|
return static::getHeader('SERVER_NAME');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getReferrer(string $fallback = '/')
|
public static function getReferrer(string $fallback = '/')
|
||||||
{
|
{
|
||||||
return Request::getHttpHeader('Referer', $fallback);
|
return Request::getHttpHeader('Referer', $fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getRelativeUri(): string
|
public static function getRelativeUri(): string
|
||||||
{
|
{
|
||||||
return static::getHeader('REQUEST_URI') ? parse_url(static::getHeader('REQUEST_URI'), PHP_URL_PATH) : '';
|
return static::getHeader('REQUEST_URI') ? parse_url(static::getHeader('REQUEST_URI'), PHP_URL_PATH) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isGzipAccepted(): bool
|
public static function isGzipAccepted(): bool
|
||||||
{
|
{
|
||||||
return static::getHttpHeader('Accept-Encoding') && strpos(strtolower(static::getHttpHeader('Accept-Encoding')), 'gzip') !== false;
|
return static::getHttpHeader('Accept-Encoding') && strpos(strtolower(static::getHttpHeader('Accept-Encoding')), 'gzip') !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isRobot()
|
public static function isRobot()
|
||||||
{
|
{
|
||||||
$bots = [
|
$bots = [
|
||||||
'bot', 'spider', 'crawler', 'siteexplorer', 'yahoo', 'slurp', 'dataaccessd', 'facebook', 'twitter', 'coccoc',
|
'bot', 'spider', 'crawler', 'siteexplorer', 'yahoo', 'slurp', 'dataaccessd', 'facebook', 'twitter', 'coccoc',
|
||||||
'calendar', 'curl', 'wget', 'panopta', 'blogtrottr', 'zapier', 'newrelic', 'luasocket',
|
'calendar', 'curl', 'wget', 'panopta', 'blogtrottr', 'zapier', 'newrelic', 'luasocket',
|
||||||
'okhttp', 'python'
|
'okhttp', 'python'
|
||||||
];
|
];
|
||||||
|
|
||||||
return preg_match('/(' . join('|', $bots) . ')/i', static::getUserAgent());
|
return preg_match('/(' . join('|', $bots) . ')/i', static::getUserAgent());
|
||||||
}
|
}
|
||||||
//Method that encode html tags to special character
|
//Method that encode html tags to special character
|
||||||
public static function encodeStringFromUser($string){
|
public static function encodeStringFromUser($string)
|
||||||
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
|
{
|
||||||
}
|
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Session
|
class Session
|
||||||
{
|
{
|
||||||
const KEY_DOWNLOAD_ACCESS_ERROR = 'download_error2',
|
const KEY_DOWNLOAD_ACCESS_ERROR = 'download_error2',
|
||||||
KEY_DOWNLOAD_ALLOWED = 'beta_download_allowed2',
|
KEY_DOWNLOAD_ALLOWED = 'beta_download_allowed2',
|
||||||
KEY_DEVELOPER_LAST_FORM = 'developer_last_form',
|
KEY_DEVELOPER_LAST_FORM = 'developer_last_form',
|
||||||
KEY_DEVELOPER_CREDITS_ERROR = 'developer_credits_error',
|
KEY_DEVELOPER_CREDITS_ERROR = 'developer_credits_error',
|
||||||
|
@ -12,95 +12,91 @@ class Session
|
||||||
KEY_LIST_SUB_ERROR = 'list_error',
|
KEY_LIST_SUB_ERROR = 'list_error',
|
||||||
KEY_USER_CULTURE = 'user_culture';
|
KEY_USER_CULTURE = 'user_culture';
|
||||||
|
|
||||||
const NAMESPACE_DEFAULT = 'default',
|
const NAMESPACE_DEFAULT = 'default',
|
||||||
NAMESPACE_FLASH = 'flash',
|
NAMESPACE_FLASH = 'flash',
|
||||||
NAMESPACE_FLASH_REMOVE = 'flash_remove';
|
NAMESPACE_FLASH_REMOVE = 'flash_remove';
|
||||||
|
|
||||||
public static function init()
|
public static function init()
|
||||||
{
|
{
|
||||||
ini_set('session.cookie_secure', IS_PRODUCTION); // send cookie over ssl only
|
ini_set('session.cookie_secure', IS_PRODUCTION); // send cookie over ssl only
|
||||||
ini_set('session.cookie_httponly', true); // no js access to cookies
|
ini_set('session.cookie_httponly', true); // no js access to cookies
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
if (!static::get('secure_and_httponly_set'))
|
if (!static::get('secure_and_httponly_set')) {
|
||||||
{
|
session_regenerate_id(); // ensure that old cookies get new settings
|
||||||
session_regenerate_id(); // ensure that old cookies get new settings
|
}
|
||||||
}
|
static::set('secure_and_httponly_set', true);
|
||||||
static::set('secure_and_httponly_set', true);
|
|
||||||
|
|
||||||
// migrate existing session data into namespaced session
|
// migrate existing session data into namespaced session
|
||||||
if (!static::getNamespace(static::NAMESPACE_DEFAULT))
|
if (!static::getNamespace(static::NAMESPACE_DEFAULT)) {
|
||||||
{
|
$oldSession = deserialize(serialize($_SESSION)) ?: [];
|
||||||
$oldSession = deserialize(serialize($_SESSION)) ?: [];
|
session_unset();
|
||||||
session_unset();
|
static::setNamespace(static::NAMESPACE_DEFAULT, $oldSession);
|
||||||
static::setNamespace(static::NAMESPACE_DEFAULT, $oldSession);
|
}
|
||||||
|
|
||||||
|
static::initFlashes();
|
||||||
}
|
}
|
||||||
|
|
||||||
static::initFlashes();
|
public static function get($key, $default = null, $ns = self::NAMESPACE_DEFAULT)
|
||||||
}
|
|
||||||
|
|
||||||
public static function get($key, $default = null, $ns = self::NAMESPACE_DEFAULT)
|
|
||||||
{
|
|
||||||
return $_SESSION[$ns][$key] ?? $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function set($key, $value, $ns = self::NAMESPACE_DEFAULT)
|
|
||||||
{
|
|
||||||
$_SESSION[$ns][$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function unsetKey($key, $ns = self::NAMESPACE_DEFAULT)
|
|
||||||
{
|
|
||||||
unset($_SESSION[$ns][$key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getNamespace($ns)
|
|
||||||
{
|
|
||||||
return $_SESSION[$ns] ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function setNamespace($ns, $value)
|
|
||||||
{
|
|
||||||
$_SESSION[$ns] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function unsetNamespace($ns)
|
|
||||||
{
|
|
||||||
unset($_SESSION[$ns]);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function initFlashes()
|
|
||||||
{
|
|
||||||
foreach(static::getNamespace(static::NAMESPACE_FLASH) as $key => $val)
|
|
||||||
{
|
{
|
||||||
static::set($key, true, static::NAMESPACE_FLASH_REMOVE);
|
return $_SESSION[$ns][$key] ?? $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller::queueToRunAfterResponse([__CLASS__, 'cleanupFlashes']);
|
public static function set($key, $value, $ns = self::NAMESPACE_DEFAULT)
|
||||||
}
|
|
||||||
|
|
||||||
public static function cleanupFlashes()
|
|
||||||
{
|
|
||||||
foreach(array_keys(static::getNamespace(static::NAMESPACE_FLASH_REMOVE)) as $flashName)
|
|
||||||
{
|
{
|
||||||
static::unsetKey($flashName, static::NAMESPACE_FLASH);
|
$_SESSION[$ns][$key] = $value;
|
||||||
static::unsetKey($flashName, static::NAMESPACE_FLASH_REMOVE);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function getFlash($name, $default = null)
|
public static function unsetKey($key, $ns = self::NAMESPACE_DEFAULT)
|
||||||
{
|
{
|
||||||
return static::get($name, $default, static::NAMESPACE_FLASH);
|
unset($_SESSION[$ns][$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setFlash($name, $value)
|
protected static function getNamespace($ns)
|
||||||
{
|
{
|
||||||
static::set($name, $value, static::NAMESPACE_FLASH);
|
return $_SESSION[$ns] ?? [];
|
||||||
static::unsetKey($name, static::NAMESPACE_FLASH_REMOVE);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function persistFlashes()
|
protected static function setNamespace($ns, $value)
|
||||||
{
|
{
|
||||||
static::unsetNamespace(static::NAMESPACE_FLASH_REMOVE);
|
$_SESSION[$ns] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function unsetNamespace($ns)
|
||||||
|
{
|
||||||
|
unset($_SESSION[$ns]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function initFlashes()
|
||||||
|
{
|
||||||
|
foreach (static::getNamespace(static::NAMESPACE_FLASH) as $key => $val) {
|
||||||
|
static::set($key, true, static::NAMESPACE_FLASH_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller::queueToRunAfterResponse([__CLASS__, 'cleanupFlashes']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cleanupFlashes()
|
||||||
|
{
|
||||||
|
foreach (array_keys(static::getNamespace(static::NAMESPACE_FLASH_REMOVE)) as $flashName) {
|
||||||
|
static::unsetKey($flashName, static::NAMESPACE_FLASH);
|
||||||
|
static::unsetKey($flashName, static::NAMESPACE_FLASH_REMOVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getFlash($name, $default = null)
|
||||||
|
{
|
||||||
|
return static::get($name, $default, static::NAMESPACE_FLASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setFlash($name, $value)
|
||||||
|
{
|
||||||
|
static::set($name, $value, static::NAMESPACE_FLASH);
|
||||||
|
static::unsetKey($name, static::NAMESPACE_FLASH_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function persistFlashes()
|
||||||
|
{
|
||||||
|
static::unsetNamespace(static::NAMESPACE_FLASH_REMOVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,138 +2,133 @@
|
||||||
|
|
||||||
class AcquisitionActions extends Actions
|
class AcquisitionActions extends Actions
|
||||||
{
|
{
|
||||||
public static function executeThanks()
|
public static function executeThanks()
|
||||||
{
|
{
|
||||||
return ['acquisition/thanks'];
|
return ['acquisition/thanks'];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeYouTubeSub()
|
|
||||||
{
|
|
||||||
if (!Request::isPost()) {
|
|
||||||
return Controller::redirect('/youtube');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$email = Request::getPostParam('email');
|
public static function executeYouTubeSub()
|
||||||
|
{
|
||||||
|
if (!Request::isPost()) {
|
||||||
|
return Controller::redirect('/youtube');
|
||||||
|
}
|
||||||
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
$email = Request::getPostParam('email');
|
||||||
Session::setFlash('error', 'Please enter a valid email.');
|
|
||||||
return Controller::redirect('/youtube');
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
Session::setFlash('error', 'Please enter a valid email.');
|
||||||
|
return Controller::redirect('/youtube');
|
||||||
|
}
|
||||||
|
|
||||||
|
Salesforce::createContact($email, SalesForce::DEFAULT_LIST_ID, 'YouTube Campaign');
|
||||||
|
Mailgun::sendYouTubeWarmLead(['email' => $email]);
|
||||||
|
|
||||||
|
Session::setFlash('success', 'Thanks! We\'ll be in touch. The good kind of touch.');
|
||||||
|
|
||||||
|
return Controller::redirect(Request::getReferrer(), 303);
|
||||||
}
|
}
|
||||||
|
|
||||||
Salesforce::createContact($email, SalesForce::DEFAULT_LIST_ID, 'YouTube Campaign');
|
public static function executeYouTube()
|
||||||
Mailgun::sendYouTubeWarmLead(['email' => $email]);
|
{
|
||||||
|
if (isset($_GET['error_message'])) {
|
||||||
|
$error_message = Request::encodeStringFromUser($_GET['error_message']);
|
||||||
|
}
|
||||||
|
|
||||||
Session::setFlash('success', 'Thanks! We\'ll be in touch. The good kind of touch.');
|
return ['acquisition/youtube', [
|
||||||
|
|
||||||
return Controller::redirect(Request::getReferrer(), 303);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeYouTube()
|
|
||||||
{
|
|
||||||
if(isset($_GET['error_message'])){
|
|
||||||
$error_message = Request::encodeStringFromUser($_GET['error_message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['acquisition/youtube', [
|
|
||||||
'reward' => LBRY::youtubeReward(),
|
'reward' => LBRY::youtubeReward(),
|
||||||
'error_message' => $error_message ?? ''
|
'error_message' => $error_message ?? ''
|
||||||
]];
|
]];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeVerify(string $token)
|
|
||||||
{
|
|
||||||
return ['acquisition/verify', ['token' => $token]];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeYoutubeToken()
|
|
||||||
{
|
|
||||||
return ['acquisition/youtube_token', ['_no_layout' => true]];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeYoutubeStatus(string $token)
|
|
||||||
{
|
|
||||||
if(isset($_GET['error_message'])){
|
|
||||||
$error_message = Request::encodeStringFromUser($_GET['error_message']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = LBRY::statusYoutube($token);
|
public static function executeVerify(string $token)
|
||||||
if ($data['success'] == false){
|
{
|
||||||
Controller::redirect('/youtube?error=true&error_message=' . $data['error']);
|
return ['acquisition/verify', ['token' => $token]];
|
||||||
}
|
}
|
||||||
return ['acquisition/youtube_status', [
|
|
||||||
|
public static function executeYoutubeToken()
|
||||||
|
{
|
||||||
|
return ['acquisition/youtube_token', ['_no_layout' => true]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function executeYoutubeStatus(string $token)
|
||||||
|
{
|
||||||
|
if (isset($_GET['error_message'])) {
|
||||||
|
$error_message = Request::encodeStringFromUser($_GET['error_message']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = LBRY::statusYoutube($token);
|
||||||
|
if ($data['success'] == false) {
|
||||||
|
Controller::redirect('/youtube?error=true&error_message=' . $data['error']);
|
||||||
|
}
|
||||||
|
return ['acquisition/youtube_status', [
|
||||||
'token' => $token,
|
'token' => $token,
|
||||||
'status_token' => $data,
|
'status_token' => $data,
|
||||||
'error_message' => $error_message ?? ''
|
'error_message' => $error_message ?? ''
|
||||||
]];
|
]];
|
||||||
}
|
|
||||||
|
|
||||||
public static function actionYoutubeToken(string $desired_lbry_channel_name)
|
|
||||||
{
|
|
||||||
|
|
||||||
$desired_lbry_channel_name_is_valid = static::lbry_channel_verification($desired_lbry_channel_name);
|
|
||||||
|
|
||||||
if ($desired_lbry_channel_name_is_valid) {
|
|
||||||
$token = LBRY::connectYoutube($desired_lbry_channel_name);
|
|
||||||
if ($token['success'] == false) {
|
|
||||||
Controller::redirect('/youtube?error=true&error_message=' . $token['error']);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Controller::redirect($token['data']);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
public static function actionYoutubeEdit($status_token, $channel_name, $email, $sync_consent)
|
public static function actionYoutubeToken(string $desired_lbry_channel_name)
|
||||||
{
|
|
||||||
$current_value = LBRY::statusYoutube($status_token);
|
|
||||||
if($current_value['data']['email'] == $email)
|
|
||||||
{
|
{
|
||||||
$status = LBRY::editYoutube($status_token, $channel_name, null, $sync_consent);
|
$desired_lbry_channel_name_is_valid = static::lbry_channel_verification($desired_lbry_channel_name);
|
||||||
|
|
||||||
|
if ($desired_lbry_channel_name_is_valid) {
|
||||||
|
$token = LBRY::connectYoutube($desired_lbry_channel_name);
|
||||||
|
if ($token['success'] == false) {
|
||||||
|
Controller::redirect('/youtube?error=true&error_message=' . $token['error']);
|
||||||
|
} else {
|
||||||
|
Controller::redirect($token['data']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
public static function actionYoutubeEdit($status_token, $channel_name, $email, $sync_consent)
|
||||||
{
|
{
|
||||||
$status = LBRY::editYoutube($status_token, $channel_name, $email, $sync_consent);
|
$current_value = LBRY::statusYoutube($status_token);
|
||||||
|
if ($current_value['data']['email'] == $email) {
|
||||||
|
$status = LBRY::editYoutube($status_token, $channel_name, null, $sync_consent);
|
||||||
|
} else {
|
||||||
|
$status = LBRY::editYoutube($status_token, $channel_name, $email, $sync_consent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status['success'] == false) {
|
||||||
|
Controller::redirect("/youtube/status/". $status_token . "?error=true&error_message=" . $status['error']);
|
||||||
|
} else {
|
||||||
|
Controller::redirect("/youtube/status/" . $status_token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function executeYoutubeEdit()
|
||||||
|
{
|
||||||
|
return ['acquisition/youtube_edit'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if($status['success'] == false){
|
public static function executeRedirectYoutube()
|
||||||
Controller::redirect("/youtube/status/". $status_token . "?error=true&error_message=" . $status['error']);
|
{
|
||||||
|
return ['acquisition/youtube_status_redirect'];
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
Controller::redirect("/youtube/status/" . $status_token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static function executeYoutubeEdit(){
|
|
||||||
return ['acquisition/youtube_edit'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeRedirectYoutube(){
|
protected static function email_verification($email)
|
||||||
return ['acquisition/youtube_status_redirect'];
|
{
|
||||||
}
|
if (preg_match('/\S+@\S+\.\S+/', $email)) {
|
||||||
|
return true;
|
||||||
protected static function email_verification($email)
|
} else {
|
||||||
{
|
return false;
|
||||||
if (preg_match('/\S+@\S+\.\S+/', $email)) {
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected static function youtube_channel_verification($youtube_channel_id)
|
protected static function youtube_channel_verification($youtube_channel_id)
|
||||||
{
|
{
|
||||||
if (preg_match('/^UC[A-Za-z0-9_-]{22}$/', $youtube_channel_id)) {
|
if (preg_match('/^UC[A-Za-z0-9_-]{22}$/', $youtube_channel_id)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected static function lbry_channel_verification($lbry_channel)
|
protected static function lbry_channel_verification($lbry_channel)
|
||||||
{
|
{
|
||||||
if (preg_match('/[1-z]+/', $lbry_channel)) {
|
if (preg_match('/[1-z]+/', $lbry_channel)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class ContentActions extends Actions
|
class ContentActions extends Actions
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
SLUG_RSS = 'rss.xml',
|
SLUG_RSS = 'rss.xml',
|
||||||
SLUG_NEWS = 'news',
|
SLUG_NEWS = 'news',
|
||||||
SLUG_FAQ = 'faq',
|
SLUG_FAQ = 'faq',
|
||||||
|
@ -26,67 +26,62 @@ class ContentActions extends Actions
|
||||||
VIEW_FOLDER_CREDIT_REPORTS = self::CONTENT_DIR . '/' . self::SLUG_CREDIT_REPORTS,
|
VIEW_FOLDER_CREDIT_REPORTS = self::CONTENT_DIR . '/' . self::SLUG_CREDIT_REPORTS,
|
||||||
VIEW_FOLDER_JOBS = self::CONTENT_DIR . '/' . self::SLUG_JOBS;
|
VIEW_FOLDER_JOBS = self::CONTENT_DIR . '/' . self::SLUG_JOBS;
|
||||||
|
|
||||||
public static function executeHome(): array
|
public static function executeHome(): array
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
return ['page/home'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeNews(string $slug = null): array
|
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
|
|
||||||
if (!$slug || $slug == static::SLUG_RSS)
|
|
||||||
{
|
{
|
||||||
$posts = array_filter(
|
Response::enableHttpCache();
|
||||||
Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC),
|
return ['page/home'];
|
||||||
function(Post $post) {
|
}
|
||||||
return !$post->getDate() || $post->getDate()->format('U') <= date('U');
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($slug == static::SLUG_RSS)
|
public static function executeNews(string $slug = null): array
|
||||||
{
|
{
|
||||||
Response::setHeader(Response::HEADER_CONTENT_TYPE, 'text/xml; charset=utf-8');
|
Response::enableHttpCache();
|
||||||
return ['content/rss', [
|
|
||||||
|
if (!$slug || $slug == static::SLUG_RSS) {
|
||||||
|
$posts = array_filter(
|
||||||
|
Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC),
|
||||||
|
function (Post $post) {
|
||||||
|
return !$post->getDate() || $post->getDate()->format('U') <= date('U');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($slug == static::SLUG_RSS) {
|
||||||
|
Response::setHeader(Response::HEADER_CONTENT_TYPE, 'text/xml; charset=utf-8');
|
||||||
|
return ['content/rss', [
|
||||||
'posts' => array_slice($posts, 0, 10),
|
'posts' => array_slice($posts, 0, 10),
|
||||||
'_no_layout' => true
|
'_no_layout' => true
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['content/news', [
|
return ['content/news', [
|
||||||
'posts' => $posts,
|
'posts' => $posts,
|
||||||
View::LAYOUT_PARAMS => [
|
View::LAYOUT_PARAMS => [
|
||||||
'showRssLink' => true
|
'showRssLink' => true
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
$post = Post::load(static::SLUG_NEWS . '/' . ltrim($slug, '/'));
|
||||||
$post = Post::load(static::SLUG_NEWS . '/' . ltrim($slug, '/'));
|
} catch (PostNotFoundException $e) {
|
||||||
}
|
return NavActions::execute404();
|
||||||
catch (PostNotFoundException $e)
|
}
|
||||||
{
|
|
||||||
return NavActions::execute404();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['content/news-post', [
|
return ['content/news-post', [
|
||||||
'post' => $post,
|
'post' => $post,
|
||||||
View::LAYOUT_PARAMS => [
|
View::LAYOUT_PARAMS => [
|
||||||
'showRssLink' => true
|
'showRssLink' => true
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function executeFaq(string $slug = null): array
|
public static function executeFaq(string $slug = null): array
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
|
|
||||||
if (!$slug)
|
|
||||||
{
|
{
|
||||||
$allPosts = Post::find(static::VIEW_FOLDER_FAQ, Post::SORT_ORD_ASC);
|
Response::enableHttpCache();
|
||||||
|
|
||||||
$allCategories = [
|
if (!$slug) {
|
||||||
|
$allPosts = Post::find(static::VIEW_FOLDER_FAQ, Post::SORT_ORD_ASC);
|
||||||
|
|
||||||
|
$allCategories = [
|
||||||
'LBRY 101' => 'Intro to LBRY',
|
'LBRY 101' => 'Intro to LBRY',
|
||||||
'getstarted' => 'Getting Started',
|
'getstarted' => 'Getting Started',
|
||||||
'setup' => 'Installing and Running LBRY',
|
'setup' => 'Installing and Running LBRY',
|
||||||
|
@ -100,190 +95,173 @@ class ContentActions extends Actions
|
||||||
'other' => 'Other Questions',
|
'other' => 'Other Questions',
|
||||||
] + Post::collectMetadata($allPosts, 'category');
|
] + Post::collectMetadata($allPosts, 'category');
|
||||||
|
|
||||||
$selectedCategory = Request::getParam('category');
|
$selectedCategory = Request::getParam('category');
|
||||||
$filters = array_filter([
|
$filters = array_filter([
|
||||||
'category' => $selectedCategory && isset($allCategories[$selectedCategory]) ? $selectedCategory : null,
|
'category' => $selectedCategory && isset($allCategories[$selectedCategory]) ? $selectedCategory : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$posts = $filters ? Post::filter($allPosts, $filters) : $allPosts;
|
$posts = $filters ? Post::filter($allPosts, $filters) : $allPosts;
|
||||||
|
|
||||||
$groups = array_fill_keys(array_keys($allCategories), []);
|
$groups = array_fill_keys(array_keys($allCategories), []);
|
||||||
|
|
||||||
foreach ($posts as $post)
|
foreach ($posts as $post) {
|
||||||
{
|
$groups[$post->getCategory()][] = $post;
|
||||||
$groups[$post->getCategory()][] = $post;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ['content/faq', [
|
return ['content/faq', [
|
||||||
'categories' => $allCategories,
|
'categories' => $allCategories,
|
||||||
'selectedCategory' => $selectedCategory,
|
'selectedCategory' => $selectedCategory,
|
||||||
'postGroups' => $groups
|
'postGroups' => $groups
|
||||||
]];
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$post = Post::load(static::SLUG_FAQ . '/' . ltrim($slug, '/'));
|
||||||
|
} catch (PostNotFoundException $e) {
|
||||||
|
return Controller::redirect('/' . static::SLUG_FAQ);
|
||||||
|
}
|
||||||
|
return ['content/faq-post', ['post' => $post]];
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
|
public static function executeCreditReports(string $year = null, string $month = null): array
|
||||||
{
|
{
|
||||||
$post = Post::load(static::SLUG_FAQ . '/' . ltrim($slug, '/'));
|
Response::enableHttpCache();
|
||||||
}
|
|
||||||
catch (PostNotFoundException $e)
|
|
||||||
{
|
|
||||||
return Controller::redirect('/' . static::SLUG_FAQ);
|
|
||||||
}
|
|
||||||
return ['content/faq-post', ['post' => $post]];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$posts = Post::find(static::VIEW_FOLDER_CREDIT_REPORTS);
|
||||||
|
|
||||||
public static function executeCreditReports(string $year = null, string $month = null): array
|
return ['content/credit-reports', [
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
|
|
||||||
$posts = Post::find(static::VIEW_FOLDER_CREDIT_REPORTS);
|
|
||||||
|
|
||||||
return ['content/credit-reports', [
|
|
||||||
'posts' => $posts
|
'posts' => $posts
|
||||||
]];
|
]];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeCreditReport(string $year = null, string $quarter = null): array
|
|
||||||
{
|
|
||||||
|
|
||||||
Response::enableHttpCache();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$post = Post::load(static::SLUG_CREDIT_REPORTS . '/' . $year . '-Q' . $quarter);
|
|
||||||
}
|
}
|
||||||
catch (PostNotFoundException $e)
|
|
||||||
|
public static function executeCreditReport(string $year = null, string $quarter = null): array
|
||||||
{
|
{
|
||||||
return Controller::redirect('/' . static::SLUG_CREDIT_REPORTS);
|
Response::enableHttpCache();
|
||||||
}
|
|
||||||
$metadata = $post->getMetadata();
|
try {
|
||||||
return ['content/credit-report', [
|
$post = Post::load(static::SLUG_CREDIT_REPORTS . '/' . $year . '-Q' . $quarter);
|
||||||
|
} catch (PostNotFoundException $e) {
|
||||||
|
return Controller::redirect('/' . static::SLUG_CREDIT_REPORTS);
|
||||||
|
}
|
||||||
|
$metadata = $post->getMetadata();
|
||||||
|
return ['content/credit-report', [
|
||||||
'post' => $post,
|
'post' => $post,
|
||||||
'sheetUrl' => $metadata['sheet']
|
'sheetUrl' => $metadata['sheet']
|
||||||
]];
|
]];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executePress(string $slug = null): array
|
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$post = Post::load(static::SLUG_PRESS . '/' . ltrim($slug, '/'));
|
|
||||||
}
|
}
|
||||||
catch (PostNotFoundException $e)
|
|
||||||
|
public static function executePress(string $slug = null): array
|
||||||
{
|
{
|
||||||
return NavActions::execute404();
|
Response::enableHttpCache();
|
||||||
|
try {
|
||||||
|
$post = Post::load(static::SLUG_PRESS . '/' . ltrim($slug, '/'));
|
||||||
|
} catch (PostNotFoundException $e) {
|
||||||
|
return NavActions::execute404();
|
||||||
|
}
|
||||||
|
return ['content/press-post', ['post' => $post]];
|
||||||
}
|
}
|
||||||
return ['content/press-post', ['post' => $post]];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function convertBountyAmount($amount)
|
protected static function convertBountyAmount($amount)
|
||||||
{
|
|
||||||
return is_numeric($amount) ? round($amount / LBRY::getLBCtoUSDRate(), -1) : $amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeBounty(string $slug = null): array
|
|
||||||
{
|
|
||||||
Response::enableHttpCache();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($slug)
|
|
||||||
{
|
{
|
||||||
list($metadata, $postHtml) = View::parseMarkdown(ContentActions::VIEW_FOLDER_BOUNTY . '/' . $slug . '.md');
|
return is_numeric($amount) ? round($amount / LBRY::getLBCtoUSDRate(), -1) : $amount;
|
||||||
|
}
|
||||||
|
|
||||||
$metadata['lbc_award'] = static::convertBountyAmount($metadata['award']);
|
public static function executeBounty(string $slug = null): array
|
||||||
|
{
|
||||||
|
Response::enableHttpCache();
|
||||||
|
|
||||||
if (!$postHtml)
|
|
||||||
{
|
|
||||||
return NavActions::execute404();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['bounty/show', [
|
|
||||||
|
if ($slug) {
|
||||||
|
list($metadata, $postHtml) = View::parseMarkdown(ContentActions::VIEW_FOLDER_BOUNTY . '/' . $slug . '.md');
|
||||||
|
|
||||||
|
$metadata['lbc_award'] = static::convertBountyAmount($metadata['award']);
|
||||||
|
|
||||||
|
if (!$postHtml) {
|
||||||
|
return NavActions::execute404();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['bounty/show', [
|
||||||
'postHtml' => $postHtml,
|
'postHtml' => $postHtml,
|
||||||
'metadata' => $metadata
|
'metadata' => $metadata
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$allBounties = Post::find(static::CONTENT_DIR . '/bounty');
|
$allBounties = Post::find(static::CONTENT_DIR . '/bounty');
|
||||||
|
|
||||||
$allCategories = ['' => ''] + Post::collectMetadata($allBounties, 'category');
|
$allCategories = ['' => ''] + Post::collectMetadata($allBounties, 'category');
|
||||||
$allStatuses = ['' => ''] + array_merge(Post::collectMetadata($allBounties, 'status'), ['complete' => 'unavailable']);
|
$allStatuses = ['' => ''] + array_merge(Post::collectMetadata($allBounties, 'status'), ['complete' => 'unavailable']);
|
||||||
|
|
||||||
$selectedStatus = Request::getParam('status', 'available');
|
$selectedStatus = Request::getParam('status', 'available');
|
||||||
$selectedCategory = Request::getParam('category');
|
$selectedCategory = Request::getParam('category');
|
||||||
|
|
||||||
$filters = array_filter([
|
$filters = array_filter([
|
||||||
'category' => $selectedCategory && isset($allCategories[$selectedCategory]) ? $selectedCategory : null,
|
'category' => $selectedCategory && isset($allCategories[$selectedCategory]) ? $selectedCategory : null,
|
||||||
'status' => $selectedStatus && isset($allStatuses[$selectedStatus]) ? $selectedStatus : null
|
'status' => $selectedStatus && isset($allStatuses[$selectedStatus]) ? $selectedStatus : null
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$bounties = $filters ? Post::filter($allBounties, $filters) : $allBounties;
|
$bounties = $filters ? Post::filter($allBounties, $filters) : $allBounties;
|
||||||
|
|
||||||
uasort($bounties, function($postA, $postB) {
|
uasort($bounties, function ($postA, $postB) {
|
||||||
$metadataA = $postA->getMetadata();
|
$metadataA = $postA->getMetadata();
|
||||||
$metadataB = $postB->getMetadata();
|
$metadataB = $postB->getMetadata();
|
||||||
$awardA = strpos('-', $metadataA['award']) !== false ? rtrim(explode('-', $metadataA['award'])[0], '+') : $metadataA['award'];
|
$awardA = strpos('-', $metadataA['award']) !== false ? rtrim(explode('-', $metadataA['award'])[0], '+') : $metadataA['award'];
|
||||||
$awardB = strpos('-', $metadataB['award']) !== false ? rtrim(explode('-', $metadataB['award'])[0], '+') : $metadataB['award'];
|
$awardB = strpos('-', $metadataB['award']) !== false ? rtrim(explode('-', $metadataB['award'])[0], '+') : $metadataB['award'];
|
||||||
if ($awardA != $awardB)
|
if ($awardA != $awardB) {
|
||||||
{
|
return $awardA > $awardB ? -1 : 1;
|
||||||
return $awardA > $awardB ? -1 : 1;
|
}
|
||||||
}
|
return $metadataA['title'] < $metadataB['title'] ? -1 : 1;
|
||||||
return $metadataA['title'] < $metadataB['title'] ? -1 : 1;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
foreach($bounties as $bounty) {
|
foreach ($bounties as $bounty) {
|
||||||
$metadata = $bounty->getMetadata();
|
$metadata = $bounty->getMetadata();
|
||||||
$bounty->setMetadataItem('lbc_award', static::convertBountyAmount($metadata['award']));
|
$bounty->setMetadataItem('lbc_award', static::convertBountyAmount($metadata['award']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['bounty/list', [
|
return ['bounty/list', [
|
||||||
'bounties' => $bounties,
|
'bounties' => $bounties,
|
||||||
'categories' => $allCategories,
|
'categories' => $allCategories,
|
||||||
'statuses' => $allStatuses,
|
'statuses' => $allStatuses,
|
||||||
'selectedCategory' => $selectedCategory,
|
'selectedCategory' => $selectedCategory,
|
||||||
'selectedStatus' => $selectedStatus
|
'selectedStatus' => $selectedStatus
|
||||||
]];
|
]];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeRoadmap()
|
|
||||||
{
|
|
||||||
$cache = !Request::getParam('nocache');
|
|
||||||
$githubItems = Github::listRoadmapChangesets($cache);
|
|
||||||
$projectMaxVersions = [];
|
|
||||||
foreach($githubItems as $group => $items)
|
|
||||||
{
|
|
||||||
if ($items)
|
|
||||||
{
|
|
||||||
$firstItem = reset($items);
|
|
||||||
$project = $firstItem['project'];
|
|
||||||
if (!isset($projectMaxVersions[$project]) || $firstItem['sort_key'] > $projectMaxVersions[$project])
|
|
||||||
{
|
|
||||||
$projectMaxVersions[$project] = $firstItem['sort_key'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$items = array_merge(Asana::listRoadmapTasks($cache), $githubItems);
|
public static function executeRoadmap()
|
||||||
return ['content/roadmap', [
|
{
|
||||||
|
$cache = !Request::getParam('nocache');
|
||||||
|
$githubItems = Github::listRoadmapChangesets($cache);
|
||||||
|
$projectMaxVersions = [];
|
||||||
|
foreach ($githubItems as $group => $items) {
|
||||||
|
if ($items) {
|
||||||
|
$firstItem = reset($items);
|
||||||
|
$project = $firstItem['project'];
|
||||||
|
if (!isset($projectMaxVersions[$project]) || $firstItem['sort_key'] > $projectMaxVersions[$project]) {
|
||||||
|
$projectMaxVersions[$project] = $firstItem['sort_key'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = array_merge(Asana::listRoadmapTasks($cache), $githubItems);
|
||||||
|
return ['content/roadmap', [
|
||||||
'projectMaxVersions' => $projectMaxVersions,
|
'projectMaxVersions' => $projectMaxVersions,
|
||||||
'items' => $items
|
'items' => $items
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function executePressKit(): array
|
public static function executePressKit(): array
|
||||||
{
|
{
|
||||||
$zipFileName = 'lbry-press-kit-' . date('Y-m-d') . '.zip';
|
$zipFileName = 'lbry-press-kit-' . date('Y-m-d') . '.zip';
|
||||||
$zipPath = tempnam('/tmp', $zipFileName);
|
$zipPath = tempnam('/tmp', $zipFileName);
|
||||||
|
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
$zip->open($zipPath, ZipArchive::OVERWRITE);
|
$zip->open($zipPath, ZipArchive::OVERWRITE);
|
||||||
|
|
||||||
// $pageHtml = View::render('page/press-kit', ['showHeader' => false]);
|
// $pageHtml = View::render('page/press-kit', ['showHeader' => false]);
|
||||||
// $html = <<<EOD
|
// $html = <<<EOD
|
||||||
//<!DOCTYPE html>
|
//<!DOCTYPE html>
|
||||||
//<html>
|
//<html>
|
||||||
// <head prefix="og: http://ogp.me/ns#">
|
// <head prefix="og: http://ogp.me/ns#">
|
||||||
// <title>LBRY Press Kit</title>
|
// <title>LBRY Press Kit</title>
|
||||||
// <link href='https://fonts.googleapis.com/css?family=Raleway:300,300italic,400,400italic,700' rel='stylesheet' type='text/css'>
|
// <link href='https://fonts.googleapis.com/css?family=Raleway:300,300italic,400,400italic,700' rel='stylesheet' type='text/css'>
|
||||||
|
@ -292,28 +270,26 @@ class ContentActions extends Actions
|
||||||
// <body>
|
// <body>
|
||||||
// $pageHtml
|
// $pageHtml
|
||||||
// </body>
|
// </body>
|
||||||
//</html>
|
//</html>
|
||||||
//EOD;
|
//EOD;
|
||||||
//
|
//
|
||||||
// $zip->addFromString('press.html', $html);
|
// $zip->addFromString('press.html', $html);
|
||||||
|
|
||||||
foreach (glob(ROOT_DIR . '/web/img/press/*') as $productImgPath)
|
foreach (glob(ROOT_DIR . '/web/img/press/*') as $productImgPath) {
|
||||||
{
|
$imgPathTokens = explode('/', $productImgPath);
|
||||||
$imgPathTokens = explode('/', $productImgPath);
|
$imgName = $imgPathTokens[count($imgPathTokens) - 1];
|
||||||
$imgName = $imgPathTokens[count($imgPathTokens) - 1];
|
$zip->addFile($productImgPath, '/logo_and_product/' . $imgName);
|
||||||
$zip->addFile($productImgPath, '/logo_and_product/' . $imgName);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach (glob(ContentActions::CONTENT_DIR . '/bio/*.md') as $bioPath)
|
foreach (glob(ContentActions::CONTENT_DIR . '/bio/*.md') as $bioPath) {
|
||||||
{
|
list($metadata, $bioHtml) = View::parseMarkdown($bioPath);
|
||||||
list($metadata, $bioHtml) = View::parseMarkdown($bioPath);
|
$zip->addFile($bioPath, '/team_bios/' . $metadata['name'] . ' - ' . $metadata['role'] . '.txt');
|
||||||
$zip->addFile($bioPath, '/team_bios/' . $metadata['name'] . ' - ' . $metadata['role'] . '.txt');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* team bio images are no longer included in press kit now that they've moved to spee.ch
|
* team bio images are no longer included in press kit now that they've moved to spee.ch
|
||||||
* this should be fixed if we care about the press-kit page
|
* this should be fixed if we care about the press-kit page
|
||||||
*/
|
*/
|
||||||
// foreach (array_filter(glob(ROOT_DIR . '/web/img/team/*.jpg'), function ($path)
|
// foreach (array_filter(glob(ROOT_DIR . '/web/img/team/*.jpg'), function ($path)
|
||||||
// {
|
// {
|
||||||
// return strpos($path, 'spooner') === false;
|
// return strpos($path, 'spooner') === false;
|
||||||
|
@ -325,35 +301,34 @@ class ContentActions extends Actions
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
Response::enableHttpCache();
|
Response::enableHttpCache();
|
||||||
Response::setDownloadHttpHeaders($zipFileName, 'application/zip', filesize($zipPath));
|
Response::setDownloadHttpHeaders($zipFileName, 'application/zip', filesize($zipPath));
|
||||||
|
|
||||||
return ['internal/zip', [
|
return ['internal/zip', [
|
||||||
'_no_layout' => true,
|
'_no_layout' => true,
|
||||||
'zipPath' => $zipPath
|
'zipPath' => $zipPath
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareBioPartial(array $vars): array
|
public static function prepareBioPartial(array $vars): array
|
||||||
{
|
{
|
||||||
$person = $vars['person'];
|
$person = $vars['person'];
|
||||||
$path = 'bio/' . $person . '.md';
|
$path = 'bio/' . $person . '.md';
|
||||||
list($metadata, $bioHtml) = View::parseMarkdown($path);
|
list($metadata, $bioHtml) = View::parseMarkdown($path);
|
||||||
$imgSrc = 'https://spee.ch/@lbryteam:6/' . $person . '.jpg';
|
$imgSrc = 'https://spee.ch/@lbryteam:6/' . $person . '.jpg';
|
||||||
return $vars + $metadata + [
|
return $vars + $metadata + [
|
||||||
'imgSrc' => $imgSrc,
|
'imgSrc' => $imgSrc,
|
||||||
'bioHtml' => $bioHtml,
|
'bioHtml' => $bioHtml,
|
||||||
'orientation' => 'vertical'
|
'orientation' => 'vertical'
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
public static function preparePostAuthorPartial(array $vars): array
|
||||||
|
{
|
||||||
public static function preparePostAuthorPartial(array $vars): array
|
$post = $vars['post'];
|
||||||
{
|
return [
|
||||||
$post = $vars['post'];
|
|
||||||
return [
|
|
||||||
'authorName' => $post->getAuthorName(),
|
'authorName' => $post->getAuthorName(),
|
||||||
'photoImgSrc' => $post->getAuthorPhoto(),
|
'photoImgSrc' => $post->getAuthorPhoto(),
|
||||||
'authorBioHtml' => $post->getAuthorBioHtml(),
|
'authorBioHtml' => $post->getAuthorBioHtml(),
|
||||||
|
@ -361,52 +336,55 @@ class ContentActions extends Actions
|
||||||
'authorTwitter' => $post->getAuthorTwitterID(),
|
'authorTwitter' => $post->getAuthorTwitterID(),
|
||||||
'authorEmail' => $post->getAuthorPostEmail()
|
'authorEmail' => $post->getAuthorPostEmail()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function preparePostListPartial(array $vars): array
|
public static function preparePostListPartial(array $vars): array
|
||||||
{
|
{
|
||||||
$count = $vars['count'] ?? 3;
|
$count = $vars['count'] ?? 3;
|
||||||
return [
|
return [
|
||||||
'posts' => array_slice(Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC), 0, $count)
|
'posts' => array_slice(Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC), 0, $count)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
public static function executePostCategoryFilter(string $category)
|
public static function executePostCategoryFilter(string $category)
|
||||||
{
|
{
|
||||||
Response::enableHttpCache();
|
Response::enableHttpCache();
|
||||||
|
|
||||||
$filter_post = [];
|
$filter_post = [];
|
||||||
|
|
||||||
$posts = array_filter(
|
$posts = array_filter(
|
||||||
Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC),
|
Post::find(static::VIEW_FOLDER_NEWS, Post::SORT_DATE_DESC),
|
||||||
function(Post $post) use ($category) {
|
function (Post $post) use ($category) {
|
||||||
return (($post->getCategory() === $category) && (!$post->getDate() || $post->getDate()->format('U') <= date('U')));
|
return (($post->getCategory() === $category) && (!$post->getDate() || $post->getDate()->format('U') <= date('U')));
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ['content/news', [
|
return ['content/news', [
|
||||||
'posts' => $posts,
|
'posts' => $posts,
|
||||||
View::LAYOUT_PARAMS => [
|
View::LAYOUT_PARAMS => [
|
||||||
'showRssLink' => true
|
'showRssLink' => true
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareJobsPartial(array $vars)
|
public static function prepareJobsPartial(array $vars)
|
||||||
{
|
{
|
||||||
$jobs =
|
$jobs =
|
||||||
array_filter(
|
array_filter(
|
||||||
array_map('View::parseMarkdown', glob(static::VIEW_FOLDER_JOBS . '/*')),
|
array_map('View::parseMarkdown', glob(static::VIEW_FOLDER_JOBS . '/*')),
|
||||||
function($job) { return $job[0]['status'] !== 'closed'; }
|
function ($job) {
|
||||||
|
return $job[0]['status'] !== 'closed';
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
usort($jobs, function($jobA, $jobB){
|
usort($jobs, function ($jobA, $jobB) {
|
||||||
if ($jobA[0]['status'] === 'active' xor $jobB[0]['status'] === 'active') {
|
if ($jobA[0]['status'] === 'active' xor $jobB[0]['status'] === 'active') {
|
||||||
return $jobA[0]['status'] === 'active' ? -1 : 1;
|
return $jobA[0]['status'] === 'active' ? -1 : 1;
|
||||||
}
|
}
|
||||||
return $jobA[0]['order'] <=> $jobB[0]['order'];
|
return $jobA[0]['order'] <=> $jobB[0]['order'];
|
||||||
});
|
});
|
||||||
|
|
||||||
return $vars + ['jobs' => $jobs];
|
return $vars + ['jobs' => $jobs];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,115 +2,108 @@
|
||||||
|
|
||||||
class DeveloperActions extends Actions
|
class DeveloperActions extends Actions
|
||||||
{
|
{
|
||||||
const DEVELOPER_REWARD = 10,
|
const DEVELOPER_REWARD = 10,
|
||||||
API_DOC_URL = 'https://lbryio.github.io/lbry/';
|
API_DOC_URL = 'https://lbryio.github.io/lbry/';
|
||||||
|
|
||||||
public static function executeQuickstart(string $step = null)
|
public static function executeQuickstart(string $step = null)
|
||||||
{
|
{
|
||||||
$stepLabels = [
|
$stepLabels = [
|
||||||
'' => 'Home',
|
'' => 'Home',
|
||||||
'install' => 'Installation',
|
'install' => 'Installation',
|
||||||
'api' => 'The API',
|
'api' => 'The API',
|
||||||
'credits' => 'Credits'
|
'credits' => 'Credits'
|
||||||
];
|
];
|
||||||
$allSteps = array_keys($stepLabels);
|
$allSteps = array_keys($stepLabels);
|
||||||
$currentStep = $step ?: $allSteps[0];
|
$currentStep = $step ?: $allSteps[0];
|
||||||
|
|
||||||
$viewParams = [
|
$viewParams = [
|
||||||
'currentStep' => $currentStep,
|
'currentStep' => $currentStep,
|
||||||
'stepLabels' => $stepLabels
|
'stepLabels' => $stepLabels
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($currentStep !== 'all')
|
if ($currentStep !== 'all') {
|
||||||
{
|
if (!isset($stepLabels[$currentStep])) {
|
||||||
if (!isset($stepLabels[$currentStep]))
|
Controller::redirect('/quickstart');
|
||||||
{
|
}
|
||||||
Controller::redirect('/quickstart');
|
|
||||||
}
|
|
||||||
|
|
||||||
$stepNum = array_flip($allSteps)[$currentStep];
|
$stepNum = array_flip($allSteps)[$currentStep];
|
||||||
|
|
||||||
$viewParams += [
|
$viewParams += [
|
||||||
'stepNum' => $stepNum,
|
'stepNum' => $stepNum,
|
||||||
'prevStep' => $stepNum === 0 ? null : $allSteps[$stepNum - 1],
|
'prevStep' => $stepNum === 0 ? null : $allSteps[$stepNum - 1],
|
||||||
'nextStep' => $stepNum + 1 >= count($allSteps) ? null : $allSteps[$stepNum + 1],
|
'nextStep' => $stepNum + 1 >= count($allSteps) ? null : $allSteps[$stepNum + 1],
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['developer/quickstart', $viewParams];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['developer/quickstart', $viewParams];
|
public static function prepareQuickstartHomePartial(array $vars)
|
||||||
}
|
{
|
||||||
|
return $vars + [
|
||||||
public static function prepareQuickstartHomePartial(array $vars)
|
|
||||||
{
|
|
||||||
return $vars + [
|
|
||||||
'usdValue' => static::DEVELOPER_REWARD * LBRY::getLBCtoUSDRate()
|
'usdValue' => static::DEVELOPER_REWARD * LBRY::getLBCtoUSDRate()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function prepareQuickstartInstallPartial(array $vars)
|
public static function prepareQuickstartInstallPartial(array $vars)
|
||||||
{
|
{
|
||||||
return $vars + ['versions' => [
|
return $vars + ['versions' => [
|
||||||
Os::OS_LINUX => Github::getDaemonReleaseProperty(OS::OS_LINUX, 'tag_name'),
|
Os::OS_LINUX => Github::getDaemonReleaseProperty(OS::OS_LINUX, 'tag_name'),
|
||||||
Os::OS_OSX => Github::getDaemonReleaseProperty(OS::OS_OSX, 'tag_name'),
|
Os::OS_OSX => Github::getDaemonReleaseProperty(OS::OS_OSX, 'tag_name'),
|
||||||
Os::OS_WINDOWS => Github::getDaemonReleaseProperty(OS::OS_WINDOWS, 'tag_name'),
|
Os::OS_WINDOWS => Github::getDaemonReleaseProperty(OS::OS_WINDOWS, 'tag_name'),
|
||||||
]];
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareFormNewDeveloperRewardPartial(array $vars)
|
public static function prepareFormNewDeveloperRewardPartial(array $vars)
|
||||||
{
|
{
|
||||||
return $vars + [
|
return $vars + [
|
||||||
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
|
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
|
||||||
'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_developer" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '',
|
'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_developer" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '',
|
||||||
'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=new_developer')
|
'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=new_developer')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareFormCreditsPublishPartial(array $vars)
|
public static function prepareFormCreditsPublishPartial(array $vars)
|
||||||
{
|
{
|
||||||
return $vars + [
|
return $vars + [
|
||||||
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
|
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
|
||||||
'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_publish" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '',
|
'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_publish" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '',
|
||||||
'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=first_publish')
|
'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=first_publish')
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeQuickstartAuth()
|
|
||||||
{
|
|
||||||
Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, trim(Request::getPostParam('wallet_address')));
|
|
||||||
Session::set(Session::KEY_DEVELOPER_LAST_FORM, Request::getPostParam('formName'));
|
|
||||||
|
|
||||||
if (Request::getPostParam('returnUrl'))
|
|
||||||
{
|
|
||||||
Session::set(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, Request::getPostParam('returnUrl'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID))
|
public static function executeQuickstartAuth()
|
||||||
{
|
{
|
||||||
throw new Exception('no github client id');
|
Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, trim(Request::getPostParam('wallet_address')));
|
||||||
}
|
Session::set(Session::KEY_DEVELOPER_LAST_FORM, Request::getPostParam('formName'));
|
||||||
|
|
||||||
$gitHubParams = [
|
if (Request::getPostParam('returnUrl')) {
|
||||||
|
Session::set(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, Request::getPostParam('returnUrl'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID)) {
|
||||||
|
throw new Exception('no github client id');
|
||||||
|
}
|
||||||
|
|
||||||
|
$gitHubParams = [
|
||||||
'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID),
|
'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID),
|
||||||
'redirect_uri' => Request::getHostAndProto() . '/quickstart/github/callback',
|
'redirect_uri' => Request::getHostAndProto() . '/quickstart/github/callback',
|
||||||
'scope' => 'user:email',
|
'scope' => 'user:email',
|
||||||
'allow_signup' => false
|
'allow_signup' => false
|
||||||
];
|
];
|
||||||
|
|
||||||
return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($gitHubParams));
|
return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($gitHubParams));
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeQuickstartGithubCallback()
|
|
||||||
{
|
|
||||||
$code = Request::getParam('code');
|
|
||||||
|
|
||||||
if (!$code)
|
|
||||||
{
|
|
||||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.');
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
public static function executeQuickstartGithubCallback()
|
||||||
{
|
{
|
||||||
$authResponseData = Curl::post('https://github.com/login/oauth/access_token', [
|
$code = Request::getParam('code');
|
||||||
|
|
||||||
|
if (!$code) {
|
||||||
|
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.');
|
||||||
|
} else {
|
||||||
|
$authResponseData = Curl::post('https://github.com/login/oauth/access_token', [
|
||||||
'code' => $code,
|
'code' => $code,
|
||||||
'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID),
|
'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID),
|
||||||
'client_secret' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_SECRET)
|
'client_secret' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_SECRET)
|
||||||
|
@ -119,20 +112,15 @@ class DeveloperActions extends Actions
|
||||||
'json_response' => true
|
'json_response' => true
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$authResponseData || !isset($authResponseData['access_token']))
|
if (!$authResponseData || !isset($authResponseData['access_token'])) {
|
||||||
{
|
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.');
|
||||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.');
|
} elseif (isset($authResponseData['error_description'])) {
|
||||||
}
|
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']);
|
||||||
elseif (isset($authResponseData['error_description']))
|
} else {
|
||||||
{
|
Session::set(Session::KEY_GITHUB_ACCESS_TOKEN, $authResponseData['access_token']);
|
||||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']);
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Session::set(Session::KEY_GITHUB_ACCESS_TOKEN, $authResponseData['access_token']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Controller::redirect(Session::get(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, '/quickstart/credits'));
|
return Controller::redirect(Session::get(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, '/quickstart/credits'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,120 +2,109 @@
|
||||||
|
|
||||||
class DownloadActions extends Actions
|
class DownloadActions extends Actions
|
||||||
{
|
{
|
||||||
public static function executeGetAppRedirect(string $ext)
|
public static function executeGetAppRedirect(string $ext)
|
||||||
{
|
|
||||||
return Controller::redirect(GitHub::getAppDownloadUrl(OS::getOsForExtension($ext)) ?: '/get', 302);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeGetAppPrereleaseRedirect(string $ext)
|
|
||||||
{
|
|
||||||
return Controller::redirect(GitHub::getAppPrereleaseDownloadUrl(OS::getOsForExtension($ext)) ?: '/get', 302);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function executeGetDaemonRedirect(string $os)
|
|
||||||
{
|
|
||||||
$uri = null;
|
|
||||||
$oses = Os::getAll();
|
|
||||||
|
|
||||||
if (isset($oses[$os]))
|
|
||||||
{
|
{
|
||||||
$uri = GitHub::getDaemonDownloadUrl($os);
|
return Controller::redirect(GitHub::getAppDownloadUrl(OS::getOsForExtension($ext)) ?: '/get', 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Controller::redirect($uri ?: '/quickstart', 302);
|
public static function executeGetAppPrereleaseRedirect(string $ext)
|
||||||
}
|
{
|
||||||
|
return Controller::redirect(GitHub::getAppPrereleaseDownloadUrl(OS::getOsForExtension($ext)) ?: '/get', 302);
|
||||||
public static function executeGet()
|
|
||||||
{
|
|
||||||
$osChoices = OS::getAll();
|
|
||||||
|
|
||||||
$os = static::guessOS();
|
|
||||||
|
|
||||||
if(isset($os) && isset($osChoices[$os])){
|
|
||||||
list($uri, $osTitle, $osIcon, $buttonLabel, $analyticsLabel) = $osChoices[$os];
|
|
||||||
$asset = Github::getAppAsset($os);
|
|
||||||
$param = ['osTitle' => $osTitle, 'osIcon' => $osIcon, 'os' => $os, 'downloadUrl' => $asset ? $asset['browser_download_url'] : null];
|
|
||||||
return ['download/get', $param];
|
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
return ['download/get-no-os'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function prepareListPartial(array $vars)
|
|
||||||
{
|
public static function executeGetDaemonRedirect(string $os)
|
||||||
return $vars + ['osChoices' => isset($vars['excludeOs']) ?
|
{
|
||||||
|
$uri = null;
|
||||||
|
$oses = Os::getAll();
|
||||||
|
|
||||||
|
if (isset($oses[$os])) {
|
||||||
|
$uri = GitHub::getDaemonDownloadUrl($os);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Controller::redirect($uri ?: '/quickstart', 302);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function executeGet()
|
||||||
|
{
|
||||||
|
$osChoices = OS::getAll();
|
||||||
|
|
||||||
|
$os = static::guessOS();
|
||||||
|
|
||||||
|
if (isset($os) && isset($osChoices[$os])) {
|
||||||
|
list($uri, $osTitle, $osIcon, $buttonLabel, $analyticsLabel) = $osChoices[$os];
|
||||||
|
$asset = Github::getAppAsset($os);
|
||||||
|
$param = ['osTitle' => $osTitle, 'osIcon' => $osIcon, 'os' => $os, 'downloadUrl' => $asset ? $asset['browser_download_url'] : null];
|
||||||
|
return ['download/get', $param];
|
||||||
|
} else {
|
||||||
|
return ['download/get-no-os'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function prepareListPartial(array $vars)
|
||||||
|
{
|
||||||
|
return $vars + ['osChoices' => isset($vars['excludeOs']) ?
|
||||||
array_diff_key(OS::getAll(), [$vars['excludeOs'] => null]) :
|
array_diff_key(OS::getAll(), [$vars['excludeOs'] => null]) :
|
||||||
OS::getAll()
|
OS::getAll()
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
protected static function guessOs()
|
|
||||||
{
|
|
||||||
//if exact OS is requested, use that
|
|
||||||
$uri = Request::getRelativeUri();
|
|
||||||
foreach (OS::getAll() as $os => $osChoice)
|
|
||||||
{
|
|
||||||
if ($osChoice[0] == $uri)
|
|
||||||
{
|
|
||||||
return $os;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Request::isRobot())
|
protected static function guessOs()
|
||||||
{
|
{
|
||||||
return null;
|
//if exact OS is requested, use that
|
||||||
}
|
$uri = Request::getRelativeUri();
|
||||||
|
foreach (OS::getAll() as $os => $osChoice) {
|
||||||
//otherwise guess from UA
|
if ($osChoice[0] == $uri) {
|
||||||
$ua = Request::getUserAgent();
|
return $os;
|
||||||
if (stripos($ua, 'OS X') !== false)
|
}
|
||||||
{
|
}
|
||||||
return strpos($ua, 'iPhone') !== false || stripos($ua, 'iPad') !== false ? OS::OS_IOS : OS::OS_OSX;
|
|
||||||
}
|
if (Request::isRobot()) {
|
||||||
if (stripos($ua, 'Linux') !== false || strpos($ua, 'X11') !== false)
|
return null;
|
||||||
{
|
}
|
||||||
return strpos($ua, 'Android') !== false ? OS::OS_ANDROID : OS::OS_LINUX;
|
|
||||||
}
|
//otherwise guess from UA
|
||||||
if (stripos($ua, 'Windows') !== false)
|
$ua = Request::getUserAgent();
|
||||||
{
|
if (stripos($ua, 'OS X') !== false) {
|
||||||
return OS::OS_WINDOWS;
|
return strpos($ua, 'iPhone') !== false || stripos($ua, 'iPad') !== false ? OS::OS_IOS : OS::OS_OSX;
|
||||||
}
|
}
|
||||||
}
|
if (stripos($ua, 'Linux') !== false || strpos($ua, 'X11') !== false) {
|
||||||
|
return strpos($ua, 'Android') !== false ? OS::OS_ANDROID : OS::OS_LINUX;
|
||||||
protected static function getEmailParam()
|
}
|
||||||
{
|
if (stripos($ua, 'Windows') !== false) {
|
||||||
$email = Request::getParam('e');
|
return OS::OS_WINDOWS;
|
||||||
|
|
||||||
if (!$email)
|
|
||||||
{
|
|
||||||
$encoded = Request::getParam('ec');
|
|
||||||
if ($encoded)
|
|
||||||
{
|
|
||||||
$email = Smaz::decode(Encoding::base64DecodeUrlsafe($encoded), Smaz::CODEBOOK_EMAIL);
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
|
|
||||||
{
|
|
||||||
$email = null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $email;
|
protected static function getEmailParam()
|
||||||
}
|
{
|
||||||
|
$email = Request::getParam('e');
|
||||||
|
|
||||||
public static function prepareDownloadButtonPartial(array $vars)
|
if (!$email) {
|
||||||
{
|
$encoded = Request::getParam('ec');
|
||||||
$osChoices = OS::getAll();
|
if ($encoded) {
|
||||||
|
$email = Smaz::decode(Encoding::base64DecodeUrlsafe($encoded), Smaz::CODEBOOK_EMAIL);
|
||||||
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$email = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$os = static::guessOS();
|
return $email;
|
||||||
|
}
|
||||||
|
|
||||||
if ($os && isset($osChoices[$os])) {
|
public static function prepareDownloadButtonPartial(array $vars)
|
||||||
list($uri, $osTitle, $osIcon, $buttonLabel, $analyticsLabel) = $osChoices[$os];
|
{
|
||||||
$release = Github::getAppRelease();
|
$osChoices = OS::getAll();
|
||||||
$asset = Github::getAppAsset($os);
|
|
||||||
|
|
||||||
$vars += [
|
$os = static::guessOS();
|
||||||
|
|
||||||
|
if ($os && isset($osChoices[$os])) {
|
||||||
|
list($uri, $osTitle, $osIcon, $buttonLabel, $analyticsLabel) = $osChoices[$os];
|
||||||
|
$release = Github::getAppRelease();
|
||||||
|
$asset = Github::getAppAsset($os);
|
||||||
|
|
||||||
|
$vars += [
|
||||||
'analyticsLabel' => $analyticsLabel,
|
'analyticsLabel' => $analyticsLabel,
|
||||||
'buttonLabel' => $buttonLabel,
|
'buttonLabel' => $buttonLabel,
|
||||||
'downloadUrl' => $asset ? $asset['browser_download_url'] : null,
|
'downloadUrl' => $asset ? $asset['browser_download_url'] : null,
|
||||||
|
@ -129,8 +118,8 @@ class DownloadActions extends Actions
|
||||||
'version' => $release ? $release['name'] : null,
|
'version' => $release ? $release['name'] : null,
|
||||||
'isAuto' => Request::getParam('auto'),
|
'isAuto' => Request::getParam('auto'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $vars;
|
return $vars;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,64 +2,61 @@
|
||||||
|
|
||||||
class MailActions extends Actions
|
class MailActions extends Actions
|
||||||
{
|
{
|
||||||
public static function executeSubscribe()
|
public static function executeSubscribe()
|
||||||
{
|
|
||||||
if (!Request::isPost())
|
|
||||||
{
|
{
|
||||||
return ['mail/subscribe'];
|
if (!Request::isPost()) {
|
||||||
|
return ['mail/subscribe'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$nextUrl = Request::getPostParam('returnUrl', '/');
|
||||||
|
if (!$nextUrl || $nextUrl[0] != '/' || !filter_var($nextUrl, FILTER_VALIDATE_URL)) {
|
||||||
|
$nextUrl = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$email = Request::getPostParam('email');
|
||||||
|
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
Session::set(
|
||||||
|
Session::KEY_LIST_SUB_ERROR,
|
||||||
|
$email ? __('Please provide a valid email address.') : __('Please provide an email address.')
|
||||||
|
);
|
||||||
|
|
||||||
|
return Controller::redirect(Request::getRelativeUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
$tag = Request::getPostParam('tag');
|
||||||
|
|
||||||
|
$response = LBRY::subscribe($email, $tag);
|
||||||
|
if ($response['error']) {
|
||||||
|
return ['mail/subscribe', ['error' => $response['error']]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['mail/subscribe', ['subscribeSuccess' => true, 'nextUrl' => $nextUrl]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$nextUrl = Request::getPostParam('returnUrl', '/');
|
public static function executeSubscribed()
|
||||||
if (!$nextUrl || $nextUrl[0] != '/' || !filter_var($nextUrl, FILTER_VALIDATE_URL))
|
|
||||||
{
|
{
|
||||||
$nextUrl = '/';
|
return ['mail/subscribe', ['confirmSuccess' => true, 'learnFooter' => true]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$email = Request::getPostParam('email');
|
|
||||||
if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL))
|
|
||||||
{
|
|
||||||
Session::set(Session::KEY_LIST_SUB_ERROR,
|
|
||||||
$email ? __('Please provide a valid email address.') : __('Please provide an email address.'));
|
|
||||||
|
|
||||||
return Controller::redirect(Request::getRelativeUri());
|
public static function prepareSubscribeFormPartial(array $vars)
|
||||||
|
{
|
||||||
|
$vars += ['btnClass' => 'btn-primary', 'returnUrl' => Request::getRelativeUri()];
|
||||||
|
|
||||||
|
$vars['error'] = Session::get(Session::KEY_LIST_SUB_ERROR);
|
||||||
|
Session::unsetKey(Session::KEY_LIST_SUB_ERROR);
|
||||||
|
|
||||||
|
return $vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tag = Request::getPostParam('tag');
|
public static function executeUnsubscribe(string $email)
|
||||||
|
|
||||||
$response = LBRY::subscribe($email, $tag);
|
|
||||||
if ($response['error'])
|
|
||||||
{
|
{
|
||||||
return ['mail/subscribe', ['error' => $response['error']]];
|
$decodedEmail = Encoding::base64DecodeUrlsafe(urldecode($email));
|
||||||
|
if (!$decodedEmail) {
|
||||||
|
return ['mail/unsubscribe', ['error' => 'Invalid unsubscribe link']];
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = LBRY::unsubscribe($decodedEmail);
|
||||||
|
return ['mail/unsubscribe', ['error' => $response['error']]];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return ['mail/subscribe', ['subscribeSuccess' => true, 'nextUrl' => $nextUrl]];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeSubscribed()
|
|
||||||
{
|
|
||||||
return ['mail/subscribe', ['confirmSuccess' => true, 'learnFooter' => true]];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function prepareSubscribeFormPartial(array $vars)
|
|
||||||
{
|
|
||||||
$vars += ['btnClass' => 'btn-primary', 'returnUrl' => Request::getRelativeUri()];
|
|
||||||
|
|
||||||
$vars['error'] = Session::get(Session::KEY_LIST_SUB_ERROR);
|
|
||||||
Session::unsetKey(Session::KEY_LIST_SUB_ERROR);
|
|
||||||
|
|
||||||
return $vars;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeUnsubscribe(string $email)
|
|
||||||
{
|
|
||||||
$decodedEmail = Encoding::base64DecodeUrlsafe(urldecode($email));
|
|
||||||
if (!$decodedEmail)
|
|
||||||
{
|
|
||||||
return ['mail/unsubscribe', ['error' => 'Invalid unsubscribe link']];
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = LBRY::unsubscribe($decodedEmail);
|
|
||||||
return ['mail/unsubscribe', ['error' => $response['error']]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,48 +2,48 @@
|
||||||
|
|
||||||
class NavActions extends Actions
|
class NavActions extends Actions
|
||||||
{
|
{
|
||||||
protected static $navUri;
|
protected static $navUri;
|
||||||
|
|
||||||
public static function setNavUri($uri)
|
public static function setNavUri($uri)
|
||||||
{
|
{
|
||||||
static::$navUri = $uri;
|
static::$navUri = $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getNavUri()
|
public static function getNavUri()
|
||||||
{
|
{
|
||||||
return static::$navUri ?: Request::getRelativeUri();
|
return static::$navUri ?: Request::getRelativeUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareFooterPartial(array $vars)
|
public static function prepareFooterPartial(array $vars)
|
||||||
{
|
{
|
||||||
return $vars + [
|
return $vars + [
|
||||||
'isDark' => false,
|
'isDark' => false,
|
||||||
'showLearnFooter' => false,
|
'showLearnFooter' => false,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function prepareGlobalItemsPartial(array $vars)
|
public static function prepareGlobalItemsPartial(array $vars)
|
||||||
{
|
{
|
||||||
return $vars += [
|
return $vars += [
|
||||||
'selectedItem' => static::getNavUri(),
|
'selectedItem' => static::getNavUri(),
|
||||||
'selectedCulture' => i18n::getLanguage() . '_' . i18n::getCountry(),
|
'selectedCulture' => i18n::getLanguage() . '_' . i18n::getCountry(),
|
||||||
'cultures' => i18n::getAllCultures()
|
'cultures' => i18n::getAllCultures()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function execute400(array $vars)
|
public static function execute400(array $vars)
|
||||||
{
|
{
|
||||||
Response::setStatus(400);
|
Response::setStatus(400);
|
||||||
return ['page/400', ['error' => $vars['error'] ?? null]];
|
return ['page/400', ['error' => $vars['error'] ?? null]];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function execute404()
|
public static function execute404()
|
||||||
{
|
{
|
||||||
// $uri = Request::getRelativeUri();
|
// $uri = Request::getRelativeUri();
|
||||||
// Controller::queueToRunAfterResponse(function() use($uri) {
|
// Controller::queueToRunAfterResponse(function() use($uri) {
|
||||||
// Slack::sendErrorIfProd('404 for url ' . $uri, false);
|
// Slack::sendErrorIfProd('404 for url ' . $uri, false);
|
||||||
// });
|
// });
|
||||||
Response::setStatus(404);
|
Response::setStatus(404);
|
||||||
return ['page/404'];
|
return ['page/404'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,103 +2,89 @@
|
||||||
|
|
||||||
class OpsActions extends Actions
|
class OpsActions extends Actions
|
||||||
{
|
{
|
||||||
public static function executeClearCache(): array
|
public static function executeClearCache(): array
|
||||||
{
|
|
||||||
if (!ini_get('apc.enabled') || !function_exists('apc_clear_cache'))
|
|
||||||
{
|
{
|
||||||
return View::renderJson(['success' => false, 'error' => 'Cache not enabled']);
|
if (!ini_get('apc.enabled') || !function_exists('apc_clear_cache')) {
|
||||||
|
return View::renderJson(['success' => false, 'error' => 'Cache not enabled']);
|
||||||
|
}
|
||||||
|
|
||||||
|
apc_clear_cache();
|
||||||
|
apc_clear_cache('user');
|
||||||
|
apc_clear_cache('opcode');
|
||||||
|
|
||||||
|
return View::renderJson(['success' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
apc_clear_cache();
|
public static function executePostCommit(): array
|
||||||
apc_clear_cache('user');
|
|
||||||
apc_clear_cache('opcode');
|
|
||||||
|
|
||||||
return View::renderJson(['success' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executePostCommit(): array
|
|
||||||
{
|
|
||||||
$payload = Request::getParam('payload');
|
|
||||||
if (!$payload)
|
|
||||||
{
|
{
|
||||||
return NavActions::execute400(['error' => 'No payload']);
|
$payload = Request::getParam('payload');
|
||||||
|
if (!$payload) {
|
||||||
|
return NavActions::execute400(['error' => 'No payload']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
if ($payload['ref'] === 'refs/heads/master') {
|
||||||
|
$sig = Request::getHttpHeader('X-Hub-Signature');
|
||||||
|
if (!$sig) {
|
||||||
|
return NavActions::execute400(['error' => "HTTP header 'X-Hub-Signature' is missing."]);
|
||||||
|
}
|
||||||
|
|
||||||
|
list($algo, $hash) = explode('=', Request::getHttpHeader('X-Hub-Signature'), 2) + ['', ''];
|
||||||
|
if (!in_array($algo, hash_algos(), true)) {
|
||||||
|
return NavActions::execute400(['error' => 'Invalid hash algorithm "' . htmlspecialchars($algo) . '"']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawPost = file_get_contents('php://input');
|
||||||
|
$secret = Config::get(Config::GITHUB_KEY);
|
||||||
|
if ($hash !== hash_hmac($algo, $rawPost, $secret)) {
|
||||||
|
return NavActions::execute400(['error' => 'Hash does not match.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents(ROOT_DIR . '/data/writeable/NEEDS_UPDATE', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [null, []];
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = json_decode($payload, true);
|
public static function executeLogUpload(): array
|
||||||
if ($payload['ref'] === 'refs/heads/master')
|
|
||||||
{
|
{
|
||||||
$sig = Request::getHttpHeader('X-Hub-Signature');
|
$log = Request::getPostParam('log') ? urldecode(Request::getPostParam('log')) : null;
|
||||||
if (!$sig)
|
if (Request::getPostParam('name')) {
|
||||||
{
|
$name = substr(trim(urldecode(Request::getPostParam('name'))), 0, 50);
|
||||||
return NavActions::execute400(['error' => "HTTP header 'X-Hub-Signature' is missing."]);
|
} elseif (Request::getPostParam('date')) {
|
||||||
}
|
$name = substr(trim(urldecode(Request::getPostParam('date'))), 0, 20) . '_' .
|
||||||
|
|
||||||
list($algo, $hash) = explode('=', Request::getHttpHeader('X-Hub-Signature'), 2) + ['', ''];
|
|
||||||
if (!in_array($algo, hash_algos(), true))
|
|
||||||
{
|
|
||||||
return NavActions::execute400(['error' => 'Invalid hash algorithm "' . htmlspecialchars($algo) . '"']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$rawPost = file_get_contents('php://input');
|
|
||||||
$secret = Config::get(Config::GITHUB_KEY);
|
|
||||||
if ($hash !== hash_hmac($algo, $rawPost, $secret))
|
|
||||||
{
|
|
||||||
return NavActions::execute400(['error' => 'Hash does not match.']);
|
|
||||||
}
|
|
||||||
|
|
||||||
file_put_contents(ROOT_DIR . '/data/writeable/NEEDS_UPDATE', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return [null, []];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function executeLogUpload(): array
|
|
||||||
{
|
|
||||||
$log = Request::getPostParam('log') ? urldecode(Request::getPostParam('log')) : null;
|
|
||||||
if (Request::getPostParam('name'))
|
|
||||||
{
|
|
||||||
$name = substr(trim(urldecode(Request::getPostParam('name'))), 0, 50);
|
|
||||||
}
|
|
||||||
elseif (Request::getPostParam('date'))
|
|
||||||
{
|
|
||||||
$name = substr(trim(urldecode(Request::getPostParam('date'))), 0, 20) . '_' .
|
|
||||||
substr(trim(urldecode(Request::getPostParam('hash'))), 0, 20) . '_' .
|
substr(trim(urldecode(Request::getPostParam('hash'))), 0, 20) . '_' .
|
||||||
substr(trim(urldecode(Request::getPostParam('sys'))), 0, 50) . '_' .
|
substr(trim(urldecode(Request::getPostParam('sys'))), 0, 50) . '_' .
|
||||||
substr(trim(urldecode(Request::getPostParam('type'))), 0, 20);
|
substr(trim(urldecode(Request::getPostParam('type'))), 0, 20);
|
||||||
|
} else {
|
||||||
|
$name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = preg_replace('/[^A-Za-z0-9_-]+/', '', $name);
|
||||||
|
|
||||||
|
if (!$log || !$name) {
|
||||||
|
return NavActions::execute400(['error' => "Required params: log, name"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$awsKey = Config::get(Config::AWS_LOG_ACCESS_KEY);
|
||||||
|
$awsSecret = Config::get(Config::AWS_LOG_SECRET_KEY);
|
||||||
|
|
||||||
|
if (!$log || !$name) {
|
||||||
|
throw new RuntimeException('Missing AWS credentials');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpFile = tempnam(sys_get_temp_dir(), 'lbryinstalllog');
|
||||||
|
file_put_contents($tmpFile, $log);
|
||||||
|
|
||||||
|
if (filesize($tmpFile) > 1024 * 1024 * 2) {
|
||||||
|
return NavActions::execute400(['error' => 'Log file is too large']);
|
||||||
|
}
|
||||||
|
|
||||||
|
S3::$useExceptions = true;
|
||||||
|
S3::setAuth($awsKey, $awsSecret);
|
||||||
|
S3::putObject(S3::inputFile($tmpFile, false), 'lbry-install-logs', $name);
|
||||||
|
unlink($tmpFile);
|
||||||
|
|
||||||
|
return [null, []];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
$name = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = preg_replace('/[^A-Za-z0-9_-]+/', '', $name);
|
|
||||||
|
|
||||||
if (!$log || !$name)
|
|
||||||
{
|
|
||||||
return NavActions::execute400(['error' => "Required params: log, name"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$awsKey = Config::get(Config::AWS_LOG_ACCESS_KEY);
|
|
||||||
$awsSecret = Config::get(Config::AWS_LOG_SECRET_KEY);
|
|
||||||
|
|
||||||
if (!$log || !$name)
|
|
||||||
{
|
|
||||||
throw new RuntimeException('Missing AWS credentials');
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmpFile = tempnam(sys_get_temp_dir(), 'lbryinstalllog');
|
|
||||||
file_put_contents($tmpFile, $log);
|
|
||||||
|
|
||||||
if (filesize($tmpFile) > 1024 * 1024 * 2)
|
|
||||||
{
|
|
||||||
return NavActions::execute400(['error' => 'Log file is too large']);
|
|
||||||
}
|
|
||||||
|
|
||||||
S3::$useExceptions = true;
|
|
||||||
S3::setAuth($awsKey, $awsSecret);
|
|
||||||
S3::putObject(S3::inputFile($tmpFile, false), 'lbry-install-logs', $name);
|
|
||||||
unlink($tmpFile);
|
|
||||||
|
|
||||||
return [null, []];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,41 +2,35 @@
|
||||||
|
|
||||||
class ReportActions extends Actions
|
class ReportActions extends Actions
|
||||||
{
|
{
|
||||||
public static function executeDmca()
|
public static function executeDmca()
|
||||||
{
|
|
||||||
Response::setHeader(Response::HEADER_CROSS_ORIGIN, "*");
|
|
||||||
if (!Request::isPost())
|
|
||||||
{
|
{
|
||||||
return ['report/dmca'];
|
Response::setHeader(Response::HEADER_CROSS_ORIGIN, "*");
|
||||||
|
if (!Request::isPost()) {
|
||||||
|
return ['report/dmca'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = [];
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
foreach (['name', 'email', 'rightsholder', 'identifier'] as $field) {
|
||||||
|
$value = Request::getPostParam($field);
|
||||||
|
|
||||||
|
if (!$value) {
|
||||||
|
$errors[$field] = __('form_error.required');
|
||||||
|
} elseif ($field == 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors[$field] = __('form_error.invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
$values[$field] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$values['report_id'] = Encoding::base58Encode(random_bytes(6));
|
||||||
|
Mailgun::sendDmcaReport($values);
|
||||||
|
Session::setFlash('success', '<h3>Report Submitted</h3><p>We will respond shortly.</p><p>This ID for this report is <strong>' . $values['report_id'] . '</strong>. Please reference this ID when contacting us regarding this report.</p>');
|
||||||
|
return Controller::redirect(Request::getRelativeUri(), 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['report/dmca', ['errors' => $errors, 'values' => $values]];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$values = [];
|
|
||||||
$errors = [];
|
|
||||||
|
|
||||||
foreach (['name', 'email', 'rightsholder', 'identifier'] as $field)
|
|
||||||
{
|
|
||||||
$value = Request::getPostParam($field);
|
|
||||||
|
|
||||||
if (!$value)
|
|
||||||
{
|
|
||||||
$errors[$field] = __('form_error.required');
|
|
||||||
}
|
|
||||||
elseif($field == 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL))
|
|
||||||
{
|
|
||||||
$errors[$field] = __('form_error.invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
$values[$field] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$errors)
|
|
||||||
{
|
|
||||||
$values['report_id'] = Encoding::base58Encode(random_bytes(6));
|
|
||||||
Mailgun::sendDmcaReport($values);
|
|
||||||
Session::setFlash('success', '<h3>Report Submitted</h3><p>We will respond shortly.</p><p>This ID for this report is <strong>' . $values['report_id'] . '</strong>. Please reference this ID when contacting us regarding this report.</p>');
|
|
||||||
return Controller::redirect(Request::getRelativeUri(), 303);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['report/dmca', ['errors' => $errors, 'values' => $values]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,28 +2,24 @@
|
||||||
|
|
||||||
class i18nActions extends Actions
|
class i18nActions extends Actions
|
||||||
{
|
{
|
||||||
public static function setCulture()
|
public static function setCulture()
|
||||||
{
|
|
||||||
$culture = Request::getPostParam('culture');
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if ($culture && !in_array($culture, i18n::getAllCultures()))
|
|
||||||
{
|
{
|
||||||
$culture = null;
|
$culture = Request::getPostParam('culture');
|
||||||
}
|
|
||||||
|
|
||||||
if ($culture)
|
// Validate
|
||||||
{
|
if ($culture && !in_array($culture, i18n::getAllCultures())) {
|
||||||
Session::set(Session::KEY_USER_CULTURE, $culture);
|
$culture = null;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Session::unsetKey(Session::KEY_USER_CULTURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if session changes update domain
|
if ($culture) {
|
||||||
//english language = www
|
Session::set(Session::KEY_USER_CULTURE, $culture);
|
||||||
|
} else {
|
||||||
|
Session::unsetKey(Session::KEY_USER_CULTURE);
|
||||||
|
}
|
||||||
|
|
||||||
return Controller::redirect(Request::getReferrer());
|
//if session changes update domain
|
||||||
}
|
//english language = www
|
||||||
|
|
||||||
|
return Controller::redirect(Request::getReferrer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
lib/cache/Apc.class.php
vendored
10
lib/cache/Apc.class.php
vendored
|
@ -8,8 +8,8 @@
|
||||||
*/
|
*/
|
||||||
class Apc
|
class Apc
|
||||||
{
|
{
|
||||||
public static function isEnabled()
|
public static function isEnabled()
|
||||||
{
|
{
|
||||||
return extension_loaded('apc') && ini_get('apc.enabled');
|
return extension_loaded('apc') && ini_get('apc.enabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,4 @@
|
||||||
|
|
||||||
class StopException extends Exception
|
class StopException extends Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,134 +5,119 @@
|
||||||
*/
|
*/
|
||||||
function __($msg, $args = [])
|
function __($msg, $args = [])
|
||||||
{
|
{
|
||||||
return strtr(i18n::translate($msg), $args);
|
return strtr(i18n::translate($msg), $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
class i18n
|
class i18n
|
||||||
{
|
{
|
||||||
protected static
|
protected static $language = null;
|
||||||
$language = null,
|
protected static $translations = [];
|
||||||
$translations = [],
|
protected static $country = null;
|
||||||
$country = null,
|
protected static $cultures = ['pt_PT', 'en_US'];
|
||||||
$cultures = ['pt_PT', 'en_US'];
|
|
||||||
|
|
||||||
public static function register() /*needed to trigger class include, presumably setup would happen here*/
|
public static function register() /*needed to trigger class include, presumably setup would happen here*/
|
||||||
{
|
|
||||||
$culture = static::deduceCulture();
|
|
||||||
|
|
||||||
list($language, $country) = explode('_', $culture);
|
|
||||||
static::$language = $language;
|
|
||||||
static::$country = $country;
|
|
||||||
|
|
||||||
setlocale(LC_MONETARY, $culture . '.UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getLanguage()
|
|
||||||
{
|
|
||||||
return static::$language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getCountry()
|
|
||||||
{
|
|
||||||
return static::$country;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAllCultures()
|
|
||||||
{
|
|
||||||
return static::$cultures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function formatCurrency($amount, $currency = 'USD')
|
|
||||||
{
|
|
||||||
return '<span class="formatted-currency">' . money_format('%.2n', $amount) . '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function formatCredits($amount)
|
|
||||||
{
|
|
||||||
return '<span class="formatted-credits">' . (is_numeric($amount) ? number_format($amount, 1) : $amount) . ' LBC</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function translate($token, $language = null)
|
|
||||||
{
|
|
||||||
$language = $language === null ? static::$language : $language;
|
|
||||||
if (!isset(static::$translations[$language]))
|
|
||||||
{
|
{
|
||||||
$path = ROOT_DIR . '/data/i18n/' . $language . '.yaml';
|
$culture = static::deduceCulture();
|
||||||
|
|
||||||
static::$translations[$language] = file_exists($path) ? Spyc::YAMLLoadString(file_get_contents($path)) : [];
|
list($language, $country) = explode('_', $culture);
|
||||||
}
|
static::$language = $language;
|
||||||
$scope = static::$translations[$language];
|
static::$country = $country;
|
||||||
foreach (explode('.', $token) as $level)
|
|
||||||
{
|
|
||||||
if (isset($scope[$level]))
|
|
||||||
{
|
|
||||||
$scope = $scope[$level];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$scope = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$scope && $language != 'en')
|
|
||||||
{
|
|
||||||
return static::translate($token, 'en');
|
|
||||||
}
|
|
||||||
return $scope ?: $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function deduceCulture()
|
setlocale(LC_MONETARY, $culture . '.UTF-8');
|
||||||
{
|
|
||||||
$candidates = [];
|
|
||||||
|
|
||||||
//url trumps everything
|
|
||||||
$urlTokens = Request::getHost() ? explode('.', Request::getHost()) : [];
|
|
||||||
$code = $urlTokens ? reset($urlTokens) : null;
|
|
||||||
if ($code !== 'www')
|
|
||||||
{
|
|
||||||
$candidates[] = $code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//then session
|
public static function getLanguage()
|
||||||
$candidates[] = Session::get(Session::KEY_USER_CULTURE);
|
|
||||||
|
|
||||||
// then headers
|
|
||||||
// http://www.thefutureoftheweb.com/blog/use-accept-language-header
|
|
||||||
if (Request::getHttpHeader('Accept-Language'))
|
|
||||||
{
|
{
|
||||||
// break up string into pieces (languages and q factors)
|
return static::$language;
|
||||||
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', Request::getHttpHeader('Accept-Language'), $languages);
|
}
|
||||||
|
|
||||||
if (isset($languages[1]) && count($languages[1]))
|
public static function getCountry()
|
||||||
{
|
{
|
||||||
// create a list like "en" => 0.8
|
return static::$country;
|
||||||
$langs = array_combine($languages[1], $languages[4]);
|
}
|
||||||
|
|
||||||
// set default to 1 for any without q factor
|
public static function getAllCultures()
|
||||||
foreach ($langs as $lang => $val)
|
{
|
||||||
{
|
return static::$cultures;
|
||||||
if ($val === '')
|
}
|
||||||
{
|
|
||||||
$langs[$lang] = 1;
|
public static function formatCurrency($amount, $currency = 'USD')
|
||||||
}
|
{
|
||||||
|
return '<span class="formatted-currency">' . money_format('%.2n', $amount) . '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function formatCredits($amount)
|
||||||
|
{
|
||||||
|
return '<span class="formatted-credits">' . (is_numeric($amount) ? number_format($amount, 1) : $amount) . ' LBC</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function translate($token, $language = null)
|
||||||
|
{
|
||||||
|
$language = $language === null ? static::$language : $language;
|
||||||
|
if (!isset(static::$translations[$language])) {
|
||||||
|
$path = ROOT_DIR . '/data/i18n/' . $language . '.yaml';
|
||||||
|
|
||||||
|
static::$translations[$language] = file_exists($path) ? Spyc::YAMLLoadString(file_get_contents($path)) : [];
|
||||||
|
}
|
||||||
|
$scope = static::$translations[$language];
|
||||||
|
foreach (explode('.', $token) as $level) {
|
||||||
|
if (isset($scope[$level])) {
|
||||||
|
$scope = $scope[$level];
|
||||||
|
} else {
|
||||||
|
$scope = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$scope && $language != 'en') {
|
||||||
|
return static::translate($token, 'en');
|
||||||
|
}
|
||||||
|
return $scope ?: $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function deduceCulture()
|
||||||
|
{
|
||||||
|
$candidates = [];
|
||||||
|
|
||||||
|
//url trumps everything
|
||||||
|
$urlTokens = Request::getHost() ? explode('.', Request::getHost()) : [];
|
||||||
|
$code = $urlTokens ? reset($urlTokens) : null;
|
||||||
|
if ($code !== 'www') {
|
||||||
|
$candidates[] = $code;
|
||||||
}
|
}
|
||||||
|
|
||||||
arsort($langs, SORT_NUMERIC);
|
//then session
|
||||||
|
$candidates[] = Session::get(Session::KEY_USER_CULTURE);
|
||||||
|
|
||||||
$candidates = array_merge($candidates, array_keys($langs));
|
// then headers
|
||||||
}
|
// http://www.thefutureoftheweb.com/blog/use-accept-language-header
|
||||||
}
|
if (Request::getHttpHeader('Accept-Language')) {
|
||||||
|
// break up string into pieces (languages and q factors)
|
||||||
|
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', Request::getHttpHeader('Accept-Language'), $languages);
|
||||||
|
|
||||||
foreach ($candidates as $candidate)
|
if (isset($languages[1]) && count($languages[1])) {
|
||||||
{
|
// create a list like "en" => 0.8
|
||||||
foreach (static::getAllCultures() as $culture)
|
$langs = array_combine($languages[1], $languages[4]);
|
||||||
{
|
|
||||||
if ($candidate === $culture || substr($culture, 0, 2) === $candidate)
|
// set default to 1 for any without q factor
|
||||||
{
|
foreach ($langs as $lang => $val) {
|
||||||
return $culture;
|
if ($val === '') {
|
||||||
|
$langs[$lang] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arsort($langs, SORT_NUMERIC);
|
||||||
|
|
||||||
|
$candidates = array_merge($candidates, array_keys($langs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'en_US';
|
foreach ($candidates as $candidate) {
|
||||||
}
|
foreach (static::getAllCultures() as $culture) {
|
||||||
|
if ($candidate === $culture || substr($culture, 0, 2) === $candidate) {
|
||||||
|
return $culture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'en_US';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
namespace Routing;
|
namespace Routing;
|
||||||
|
|
||||||
class RouterBadRouteException extends \LogicException {}
|
class RouterBadRouteException extends \LogicException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -4,227 +4,205 @@ namespace Routing;
|
||||||
|
|
||||||
class Dispatcher
|
class Dispatcher
|
||||||
{
|
{
|
||||||
|
private $staticRouteMap;
|
||||||
|
private $variableRouteData;
|
||||||
|
private $filters;
|
||||||
|
private $handlerResolver;
|
||||||
|
public $matchedRoute;
|
||||||
|
|
||||||
private $staticRouteMap;
|
/**
|
||||||
private $variableRouteData;
|
* Create a new route dispatcher.
|
||||||
private $filters;
|
*
|
||||||
private $handlerResolver;
|
* @param RouteDataInterface $data
|
||||||
public $matchedRoute;
|
* @param HandlerResolverInterface $resolver
|
||||||
|
*/
|
||||||
/**
|
public function __construct(RouteData $data, HandlerResolverInterface $resolver = null)
|
||||||
* Create a new route dispatcher.
|
|
||||||
*
|
|
||||||
* @param RouteDataInterface $data
|
|
||||||
* @param HandlerResolverInterface $resolver
|
|
||||||
*/
|
|
||||||
public function __construct(RouteData $data, HandlerResolverInterface $resolver = null)
|
|
||||||
{
|
|
||||||
$this->staticRouteMap = $data->getStaticRoutes();
|
|
||||||
|
|
||||||
$this->variableRouteData = $data->getVariableRoutes();
|
|
||||||
|
|
||||||
$this->filters = $data->getFilters();
|
|
||||||
|
|
||||||
if ($resolver === null)
|
|
||||||
{
|
{
|
||||||
$this->handlerResolver = new HandlerResolver();
|
$this->staticRouteMap = $data->getStaticRoutes();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->handlerResolver = $resolver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$this->variableRouteData = $data->getVariableRoutes();
|
||||||
* Dispatch a route for the given HTTP Method / URI.
|
|
||||||
*
|
|
||||||
* @param $httpMethod
|
|
||||||
* @param $uri
|
|
||||||
*
|
|
||||||
* @return mixed|null
|
|
||||||
*/
|
|
||||||
public function dispatch($httpMethod, $uri)
|
|
||||||
{
|
|
||||||
list($handler, $filters, $vars) = $this->dispatchRoute($httpMethod, trim($uri, '/'));
|
|
||||||
|
|
||||||
list($beforeFilter, $afterFilter) = $this->parseFilters($filters);
|
$this->filters = $data->getFilters();
|
||||||
|
|
||||||
if (($response = $this->dispatchFilters($beforeFilter)) !== null)
|
if ($resolver === null) {
|
||||||
{
|
$this->handlerResolver = new HandlerResolver();
|
||||||
return $response;
|
} else {
|
||||||
}
|
$this->handlerResolver = $resolver;
|
||||||
|
|
||||||
$resolvedHandler = $this->handlerResolver->resolve($handler);
|
|
||||||
|
|
||||||
$response = call_user_func_array($resolvedHandler, $vars);
|
|
||||||
|
|
||||||
return $this->dispatchFilters($afterFilter, $response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatch a route filter.
|
|
||||||
*
|
|
||||||
* @param $filters
|
|
||||||
* @param null $response
|
|
||||||
*
|
|
||||||
* @return mixed|null
|
|
||||||
*/
|
|
||||||
private function dispatchFilters($filters, $response = null)
|
|
||||||
{
|
|
||||||
while ($filter = array_shift($filters))
|
|
||||||
{
|
|
||||||
$handler = $this->handlerResolver->resolve($filter);
|
|
||||||
|
|
||||||
if (($filteredResponse = call_user_func($handler, $response)) !== null)
|
|
||||||
{
|
|
||||||
return $filteredResponse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalise the array filters attached to the route and merge with any global filters.
|
|
||||||
*
|
|
||||||
* @param $filters
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function parseFilters($filters)
|
|
||||||
{
|
|
||||||
$beforeFilter = [];
|
|
||||||
$afterFilter = [];
|
|
||||||
|
|
||||||
if (isset($filters[Route::BEFORE]))
|
|
||||||
{
|
|
||||||
$beforeFilter = array_intersect_key($this->filters, array_flip((array)$filters[Route::BEFORE]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($filters[Route::AFTER]))
|
|
||||||
{
|
|
||||||
$afterFilter = array_intersect_key($this->filters, array_flip((array)$filters[Route::AFTER]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$beforeFilter, $afterFilter];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the route dispatching. Check static routes first followed by variable routes.
|
|
||||||
*
|
|
||||||
* @param $httpMethod
|
|
||||||
* @param $uri
|
|
||||||
*
|
|
||||||
* @throws Exception\HttpRouteNotFoundException
|
|
||||||
*/
|
|
||||||
private function dispatchRoute($httpMethod, $uri)
|
|
||||||
{
|
|
||||||
if (isset($this->staticRouteMap[$uri]))
|
|
||||||
{
|
|
||||||
return $this->dispatchStaticRoute($httpMethod, $uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->dispatchVariableRoute($httpMethod, $uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the dispatching of static routes.
|
|
||||||
*
|
|
||||||
* @param $httpMethod
|
|
||||||
* @param $uri
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
* @throws Exception\HttpMethodNotAllowedException
|
|
||||||
*/
|
|
||||||
private function dispatchStaticRoute($httpMethod, $uri)
|
|
||||||
{
|
|
||||||
$routes = $this->staticRouteMap[$uri];
|
|
||||||
|
|
||||||
if (!isset($routes[$httpMethod]))
|
|
||||||
{
|
|
||||||
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $routes[$httpMethod];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check fallback routes: HEAD for GET requests followed by the ANY attachment.
|
|
||||||
*
|
|
||||||
* @param $routes
|
|
||||||
* @param $httpMethod
|
|
||||||
*
|
|
||||||
* @throws Exception\HttpMethodNotAllowedException
|
|
||||||
*/
|
|
||||||
private function checkFallbacks($routes, $httpMethod)
|
|
||||||
{
|
|
||||||
$additional = [Route::ANY];
|
|
||||||
|
|
||||||
if ($httpMethod === Route::HEAD)
|
|
||||||
{
|
|
||||||
$additional[] = Route::GET;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($additional as $method)
|
|
||||||
{
|
|
||||||
if (isset($routes[$method]))
|
|
||||||
{
|
|
||||||
return $method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->matchedRoute = $routes;
|
|
||||||
|
|
||||||
throw new HttpMethodNotAllowedException(array_keys($routes), 'Method not allowed');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the dispatching of variable routes.
|
|
||||||
*
|
|
||||||
* @param $httpMethod
|
|
||||||
* @param $uri
|
|
||||||
*
|
|
||||||
* @throws Exception\HttpMethodNotAllowedException
|
|
||||||
* @throws Exception\HttpRouteNotFoundException
|
|
||||||
*/
|
|
||||||
private function dispatchVariableRoute($httpMethod, $uri)
|
|
||||||
{
|
|
||||||
foreach ($this->variableRouteData as $data)
|
|
||||||
{
|
|
||||||
if (!preg_match($data['regex'], $uri, $matches))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$count = count($matches);
|
|
||||||
|
|
||||||
while (!isset($data['routeMap'][$count++]))
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
$routes = $data['routeMap'][$count - 1];
|
|
||||||
|
|
||||||
if (!isset($routes[$httpMethod]))
|
|
||||||
{
|
|
||||||
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (array_values($routes[$httpMethod][2]) as $i => $varName)
|
|
||||||
{
|
|
||||||
if (!isset($matches[$i + 1]) || $matches[$i + 1] === '')
|
|
||||||
{
|
|
||||||
unset($routes[$httpMethod][2][$varName]);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
$routes[$httpMethod][2][$varName] = $matches[$i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $routes[$httpMethod];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new HttpRouteNotFoundException('Route ' . $uri . ' does not exist');
|
/**
|
||||||
}
|
* Dispatch a route for the given HTTP Method / URI.
|
||||||
|
*
|
||||||
|
* @param $httpMethod
|
||||||
|
* @param $uri
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function dispatch($httpMethod, $uri)
|
||||||
|
{
|
||||||
|
list($handler, $filters, $vars) = $this->dispatchRoute($httpMethod, trim($uri, '/'));
|
||||||
|
|
||||||
|
list($beforeFilter, $afterFilter) = $this->parseFilters($filters);
|
||||||
|
|
||||||
|
if (($response = $this->dispatchFilters($beforeFilter)) !== null) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolvedHandler = $this->handlerResolver->resolve($handler);
|
||||||
|
|
||||||
|
$response = call_user_func_array($resolvedHandler, $vars);
|
||||||
|
|
||||||
|
return $this->dispatchFilters($afterFilter, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a route filter.
|
||||||
|
*
|
||||||
|
* @param $filters
|
||||||
|
* @param null $response
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
private function dispatchFilters($filters, $response = null)
|
||||||
|
{
|
||||||
|
while ($filter = array_shift($filters)) {
|
||||||
|
$handler = $this->handlerResolver->resolve($filter);
|
||||||
|
|
||||||
|
if (($filteredResponse = call_user_func($handler, $response)) !== null) {
|
||||||
|
return $filteredResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalise the array filters attached to the route and merge with any global filters.
|
||||||
|
*
|
||||||
|
* @param $filters
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function parseFilters($filters)
|
||||||
|
{
|
||||||
|
$beforeFilter = [];
|
||||||
|
$afterFilter = [];
|
||||||
|
|
||||||
|
if (isset($filters[Route::BEFORE])) {
|
||||||
|
$beforeFilter = array_intersect_key($this->filters, array_flip((array)$filters[Route::BEFORE]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filters[Route::AFTER])) {
|
||||||
|
$afterFilter = array_intersect_key($this->filters, array_flip((array)$filters[Route::AFTER]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$beforeFilter, $afterFilter];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the route dispatching. Check static routes first followed by variable routes.
|
||||||
|
*
|
||||||
|
* @param $httpMethod
|
||||||
|
* @param $uri
|
||||||
|
*
|
||||||
|
* @throws Exception\HttpRouteNotFoundException
|
||||||
|
*/
|
||||||
|
private function dispatchRoute($httpMethod, $uri)
|
||||||
|
{
|
||||||
|
if (isset($this->staticRouteMap[$uri])) {
|
||||||
|
return $this->dispatchStaticRoute($httpMethod, $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->dispatchVariableRoute($httpMethod, $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the dispatching of static routes.
|
||||||
|
*
|
||||||
|
* @param $httpMethod
|
||||||
|
* @param $uri
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
* @throws Exception\HttpMethodNotAllowedException
|
||||||
|
*/
|
||||||
|
private function dispatchStaticRoute($httpMethod, $uri)
|
||||||
|
{
|
||||||
|
$routes = $this->staticRouteMap[$uri];
|
||||||
|
|
||||||
|
if (!isset($routes[$httpMethod])) {
|
||||||
|
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $routes[$httpMethod];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check fallback routes: HEAD for GET requests followed by the ANY attachment.
|
||||||
|
*
|
||||||
|
* @param $routes
|
||||||
|
* @param $httpMethod
|
||||||
|
*
|
||||||
|
* @throws Exception\HttpMethodNotAllowedException
|
||||||
|
*/
|
||||||
|
private function checkFallbacks($routes, $httpMethod)
|
||||||
|
{
|
||||||
|
$additional = [Route::ANY];
|
||||||
|
|
||||||
|
if ($httpMethod === Route::HEAD) {
|
||||||
|
$additional[] = Route::GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($additional as $method) {
|
||||||
|
if (isset($routes[$method])) {
|
||||||
|
return $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->matchedRoute = $routes;
|
||||||
|
|
||||||
|
throw new HttpMethodNotAllowedException(array_keys($routes), 'Method not allowed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the dispatching of variable routes.
|
||||||
|
*
|
||||||
|
* @param $httpMethod
|
||||||
|
* @param $uri
|
||||||
|
*
|
||||||
|
* @throws Exception\HttpMethodNotAllowedException
|
||||||
|
* @throws Exception\HttpRouteNotFoundException
|
||||||
|
*/
|
||||||
|
private function dispatchVariableRoute($httpMethod, $uri)
|
||||||
|
{
|
||||||
|
foreach ($this->variableRouteData as $data) {
|
||||||
|
if (!preg_match($data['regex'], $uri, $matches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = count($matches);
|
||||||
|
|
||||||
|
while (!isset($data['routeMap'][$count++])) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
$routes = $data['routeMap'][$count - 1];
|
||||||
|
|
||||||
|
if (!isset($routes[$httpMethod])) {
|
||||||
|
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_values($routes[$httpMethod][2]) as $i => $varName) {
|
||||||
|
if (!isset($matches[$i + 1]) || $matches[$i + 1] === '') {
|
||||||
|
unset($routes[$httpMethod][2][$varName]);
|
||||||
|
} else {
|
||||||
|
$routes[$httpMethod][2][$varName] = $matches[$i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $routes[$httpMethod];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new HttpRouteNotFoundException('Route ' . $uri . ' does not exist');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,12 @@ namespace Routing;
|
||||||
|
|
||||||
class HandlerResolver implements HandlerResolverInterface
|
class HandlerResolver implements HandlerResolverInterface
|
||||||
{
|
{
|
||||||
public function resolve($handler)
|
public function resolve($handler)
|
||||||
{
|
|
||||||
if (is_array($handler) && is_string($handler[0]))
|
|
||||||
{
|
{
|
||||||
$handler[0] = new $handler[0];
|
if (is_array($handler) && is_string($handler[0])) {
|
||||||
}
|
$handler[0] = new $handler[0];
|
||||||
|
}
|
||||||
|
|
||||||
return $handler;
|
return $handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ namespace Routing;
|
||||||
|
|
||||||
interface HandlerResolverInterface
|
interface HandlerResolverInterface
|
||||||
{
|
{
|
||||||
public function resolve($handler);
|
public function resolve($handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
namespace Routing;
|
namespace Routing;
|
||||||
|
|
||||||
class HttpException extends \Exception {}
|
class HttpException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -4,16 +4,16 @@ namespace Routing;
|
||||||
|
|
||||||
class HttpMethodNotAllowedException extends HttpException
|
class HttpMethodNotAllowedException extends HttpException
|
||||||
{
|
{
|
||||||
protected $allowedMethods;
|
protected $allowedMethods;
|
||||||
|
|
||||||
public function __construct(array $allowedMethods, $message = "", $code = 0, Exception $previous = null)
|
public function __construct(array $allowedMethods, $message = "", $code = 0, Exception $previous = null)
|
||||||
{
|
{
|
||||||
$this->allowedMethods = $allowedMethods;
|
$this->allowedMethods = $allowedMethods;
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllowedMethods()
|
public function getAllowedMethods()
|
||||||
{
|
{
|
||||||
return $this->allowedMethods;
|
return $this->allowedMethods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
|
|
||||||
namespace Routing;
|
namespace Routing;
|
||||||
|
|
||||||
class HttpRouteNotFoundException extends HttpException {}
|
class HttpRouteNotFoundException extends HttpException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -4,23 +4,22 @@ namespace Routing;
|
||||||
|
|
||||||
class Route
|
class Route
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constants for before and after filters
|
* Constants for before and after filters
|
||||||
*/
|
*/
|
||||||
const BEFORE = 'before';
|
const BEFORE = 'before';
|
||||||
const AFTER = 'after';
|
const AFTER = 'after';
|
||||||
const PREFIX = 'prefix';
|
const PREFIX = 'prefix';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants for common HTTP methods
|
* Constants for common HTTP methods
|
||||||
*/
|
*/
|
||||||
const ANY = 'ANY';
|
const ANY = 'ANY';
|
||||||
const GET = 'GET';
|
const GET = 'GET';
|
||||||
const HEAD = 'HEAD';
|
const HEAD = 'HEAD';
|
||||||
const POST = 'POST';
|
const POST = 'POST';
|
||||||
const PUT = 'PUT';
|
const PUT = 'PUT';
|
||||||
const PATCH = 'PATCH';
|
const PATCH = 'PATCH';
|
||||||
const DELETE = 'DELETE';
|
const DELETE = 'DELETE';
|
||||||
const OPTIONS = 'OPTIONS';
|
const OPTIONS = 'OPTIONS';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,266 +4,247 @@ namespace Routing;
|
||||||
|
|
||||||
class RouteCollector
|
class RouteCollector
|
||||||
{
|
{
|
||||||
const DEFAULT_CONTROLLER_ROUTE = 'index';
|
const DEFAULT_CONTROLLER_ROUTE = 'index';
|
||||||
|
|
||||||
const APPROX_CHUNK_SIZE = 10;
|
const APPROX_CHUNK_SIZE = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var RouteParser
|
* @var RouteParser
|
||||||
*/
|
*/
|
||||||
private $routeParser;
|
private $routeParser;
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $filters = [];
|
private $filters = [];
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $staticRoutes = [];
|
private $staticRoutes = [];
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $regexToRoutesMap = [];
|
private $regexToRoutesMap = [];
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $reverse = [];
|
private $reverse = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $globalFilters = [];
|
private $globalFilters = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $globalRoutePrefix = '';
|
private $globalRoutePrefix = '';
|
||||||
|
|
||||||
public function __construct(RouteParser $routeParser = null)
|
public function __construct(RouteParser $routeParser = null)
|
||||||
{
|
|
||||||
$this->routeParser = $routeParser ?: new RouteParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasRoute(string $name): bool
|
|
||||||
{
|
|
||||||
return isset($this->reverse[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function route(string $name, array $args = null): string
|
|
||||||
{
|
|
||||||
$url = [];
|
|
||||||
|
|
||||||
$replacements = is_null($args) ? [] : array_values($args);
|
|
||||||
|
|
||||||
$variable = 0;
|
|
||||||
|
|
||||||
foreach ($this->reverse[$name] as $part)
|
|
||||||
{
|
{
|
||||||
if (!$part['variable'])
|
$this->routeParser = $routeParser ?: new RouteParser();
|
||||||
{
|
}
|
||||||
$url[] = $part['value'];
|
|
||||||
}
|
public function hasRoute(string $name): bool
|
||||||
elseif (isset($replacements[$variable]))
|
{
|
||||||
{
|
return isset($this->reverse[$name]);
|
||||||
if ($part['optional'])
|
}
|
||||||
{
|
|
||||||
$url[] = '/';
|
public function route(string $name, array $args = null): string
|
||||||
|
{
|
||||||
|
$url = [];
|
||||||
|
|
||||||
|
$replacements = is_null($args) ? [] : array_values($args);
|
||||||
|
|
||||||
|
$variable = 0;
|
||||||
|
|
||||||
|
foreach ($this->reverse[$name] as $part) {
|
||||||
|
if (!$part['variable']) {
|
||||||
|
$url[] = $part['value'];
|
||||||
|
} elseif (isset($replacements[$variable])) {
|
||||||
|
if ($part['optional']) {
|
||||||
|
$url[] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$url[] = $replacements[$variable++];
|
||||||
|
} elseif (!$part['optional']) {
|
||||||
|
throw new BadRouteException("Expecting route variable '{$part['name']}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$url[] = $replacements[$variable++];
|
return implode('', $url);
|
||||||
}
|
|
||||||
elseif (!$part['optional'])
|
|
||||||
{
|
|
||||||
throw new BadRouteException("Expecting route variable '{$part['name']}'");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode('', $url);
|
public function addRoute(string $httpMethod, $route, $handler, array $filters = []): RouteCollector
|
||||||
}
|
|
||||||
|
|
||||||
public function addRoute(string $httpMethod, $route, $handler, array $filters = []): RouteCollector
|
|
||||||
{
|
|
||||||
|
|
||||||
if (is_array($route))
|
|
||||||
{
|
{
|
||||||
list($route, $name) = $route;
|
if (is_array($route)) {
|
||||||
}
|
list($route, $name) = $route;
|
||||||
|
}
|
||||||
|
|
||||||
$route = $this->addPrefix($this->trim($route));
|
$route = $this->addPrefix($this->trim($route));
|
||||||
|
|
||||||
list($routeData, $reverseData) = $this->routeParser->parse($route);
|
list($routeData, $reverseData) = $this->routeParser->parse($route);
|
||||||
|
|
||||||
if (isset($name))
|
if (isset($name)) {
|
||||||
{
|
$this->reverse[$name] = $reverseData;
|
||||||
$this->reverse[$name] = $reverseData;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$filters = array_merge_recursive($this->globalFilters, $filters);
|
$filters = array_merge_recursive($this->globalFilters, $filters);
|
||||||
|
|
||||||
isset($routeData[1]) ?
|
isset($routeData[1]) ?
|
||||||
$this->addVariableRoute($httpMethod, $routeData, $handler, $filters) :
|
$this->addVariableRoute($httpMethod, $routeData, $handler, $filters) :
|
||||||
$this->addStaticRoute($httpMethod, $routeData, $handler, $filters);
|
$this->addStaticRoute($httpMethod, $routeData, $handler, $filters);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
|
||||||
|
|
||||||
private function addStaticRoute(string $httpMethod, $routeData, $handler, $filters)
|
|
||||||
{
|
|
||||||
$routeStr = $routeData[0];
|
|
||||||
|
|
||||||
if (isset($this->staticRoutes[$routeStr][$httpMethod]))
|
|
||||||
{
|
|
||||||
throw new BadRouteException("Cannot register two routes matching '$routeStr' for method '$httpMethod'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->regexToRoutesMap as $regex => $routes)
|
private function addStaticRoute(string $httpMethod, $routeData, $handler, $filters)
|
||||||
{
|
{
|
||||||
if (isset($routes[$httpMethod]) && preg_match('~^' . $regex . '$~', $routeStr))
|
$routeStr = $routeData[0];
|
||||||
{
|
|
||||||
throw new BadRouteException("Static route '$routeStr' is shadowed by previously defined variable route '$regex' for method '$httpMethod'");
|
if (isset($this->staticRoutes[$routeStr][$httpMethod])) {
|
||||||
}
|
throw new BadRouteException("Cannot register two routes matching '$routeStr' for method '$httpMethod'");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->regexToRoutesMap as $regex => $routes) {
|
||||||
|
if (isset($routes[$httpMethod]) && preg_match('~^' . $regex . '$~', $routeStr)) {
|
||||||
|
throw new BadRouteException("Static route '$routeStr' is shadowed by previously defined variable route '$regex' for method '$httpMethod'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->staticRoutes[$routeStr][$httpMethod] = [$handler, $filters, []];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->staticRoutes[$routeStr][$httpMethod] = [$handler, $filters, []];
|
private function addVariableRoute(string $httpMethod, $routeData, $handler, $filters)
|
||||||
}
|
|
||||||
|
|
||||||
private function addVariableRoute(string $httpMethod, $routeData, $handler, $filters)
|
|
||||||
{
|
|
||||||
list($regex, $variables) = $routeData;
|
|
||||||
|
|
||||||
if (isset($this->regexToRoutesMap[$regex][$httpMethod]))
|
|
||||||
{
|
{
|
||||||
throw new BadRouteException("Cannot register two routes matching '$regex' for method '$httpMethod'");
|
list($regex, $variables) = $routeData;
|
||||||
|
|
||||||
|
if (isset($this->regexToRoutesMap[$regex][$httpMethod])) {
|
||||||
|
throw new BadRouteException("Cannot register two routes matching '$regex' for method '$httpMethod'");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->regexToRoutesMap[$regex][$httpMethod] = [$handler, $filters, $variables];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->regexToRoutesMap[$regex][$httpMethod] = [$handler, $filters, $variables];
|
public function group(array $filters, \Closure $callback)
|
||||||
}
|
{
|
||||||
|
$oldGlobalFilters = $this->globalFilters;
|
||||||
|
|
||||||
public function group(array $filters, \Closure $callback)
|
$oldGlobalPrefix = $this->globalRoutePrefix;
|
||||||
{
|
|
||||||
$oldGlobalFilters = $this->globalFilters;
|
|
||||||
|
|
||||||
$oldGlobalPrefix = $this->globalRoutePrefix;
|
$this->globalFilters =
|
||||||
|
|
||||||
$this->globalFilters =
|
|
||||||
array_merge_recursive($this->globalFilters, array_intersect_key($filters, [Route::AFTER => 1, Route::BEFORE => 1]));
|
array_merge_recursive($this->globalFilters, array_intersect_key($filters, [Route::AFTER => 1, Route::BEFORE => 1]));
|
||||||
|
|
||||||
$newPrefix = isset($filters[Route::PREFIX]) ? $this->trim($filters[Route::PREFIX]) : null;
|
$newPrefix = isset($filters[Route::PREFIX]) ? $this->trim($filters[Route::PREFIX]) : null;
|
||||||
|
|
||||||
$this->globalRoutePrefix = $this->addPrefix($newPrefix);
|
$this->globalRoutePrefix = $this->addPrefix($newPrefix);
|
||||||
|
|
||||||
$callback($this);
|
$callback($this);
|
||||||
|
|
||||||
$this->globalFilters = $oldGlobalFilters;
|
$this->globalFilters = $oldGlobalFilters;
|
||||||
|
|
||||||
$this->globalRoutePrefix = $oldGlobalPrefix;
|
$this->globalRoutePrefix = $oldGlobalPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addPrefix(string $route)
|
private function addPrefix(string $route)
|
||||||
{
|
|
||||||
return $this->trim($this->trim($this->globalRoutePrefix) . '/' . $route);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function filter(string $name, $handler)
|
|
||||||
{
|
|
||||||
$this->filters[$name] = $handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function get($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::GET, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function head($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::HEAD, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function post($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::POST, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function put($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::PUT, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function patch($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::PATCH, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::DELETE, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function options($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::OPTIONS, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function any($route, $handler, array $filters = [])
|
|
||||||
{
|
|
||||||
return $this->addRoute(Route::ANY, $route, $handler, $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function controller(string $route, string $classname, array $filters = []): RouteCollector
|
|
||||||
{
|
|
||||||
$reflection = new ReflectionClass($classname);
|
|
||||||
|
|
||||||
$validMethods = $this->getValidMethods();
|
|
||||||
|
|
||||||
$sep = $route === '/' ? '' : '/';
|
|
||||||
|
|
||||||
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
|
|
||||||
{
|
{
|
||||||
foreach ($validMethods as $valid)
|
return $this->trim($this->trim($this->globalRoutePrefix) . '/' . $route);
|
||||||
{
|
}
|
||||||
if (stripos($method->name, $valid) === 0)
|
|
||||||
{
|
|
||||||
$methodName = $this->camelCaseToDashed(substr($method->name, strlen($valid)));
|
|
||||||
|
|
||||||
$params = $this->buildControllerParameters($method);
|
public function filter(string $name, $handler)
|
||||||
|
{
|
||||||
|
$this->filters[$name] = $handler;
|
||||||
|
}
|
||||||
|
|
||||||
if ($methodName === self::DEFAULT_CONTROLLER_ROUTE)
|
|
||||||
{
|
|
||||||
$this->addRoute($valid, $route . $params, [$classname, $method->name], $filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addRoute($valid, $route . $sep . $methodName . $params, [$classname, $method->name], $filters);
|
public function get($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::GET, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
public function head($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::HEAD, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::POST, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function put($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::PUT, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patch($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::PATCH, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::DELETE, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function options($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::OPTIONS, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function any($route, $handler, array $filters = [])
|
||||||
|
{
|
||||||
|
return $this->addRoute(Route::ANY, $route, $handler, $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function controller(string $route, string $classname, array $filters = []): RouteCollector
|
||||||
|
{
|
||||||
|
$reflection = new ReflectionClass($classname);
|
||||||
|
|
||||||
|
$validMethods = $this->getValidMethods();
|
||||||
|
|
||||||
|
$sep = $route === '/' ? '' : '/';
|
||||||
|
|
||||||
|
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
||||||
|
foreach ($validMethods as $valid) {
|
||||||
|
if (stripos($method->name, $valid) === 0) {
|
||||||
|
$methodName = $this->camelCaseToDashed(substr($method->name, strlen($valid)));
|
||||||
|
|
||||||
|
$params = $this->buildControllerParameters($method);
|
||||||
|
|
||||||
|
if ($methodName === self::DEFAULT_CONTROLLER_ROUTE) {
|
||||||
|
$this->addRoute($valid, $route . $params, [$classname, $method->name], $filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addRoute($valid, $route . $sep . $methodName . $params, [$classname, $method->name], $filters);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
private function buildControllerParameters(ReflectionMethod $method): string
|
||||||
}
|
|
||||||
|
|
||||||
private function buildControllerParameters(ReflectionMethod $method): string
|
|
||||||
{
|
|
||||||
$params = '';
|
|
||||||
|
|
||||||
foreach ($method->getParameters() as $param)
|
|
||||||
{
|
{
|
||||||
$params .= "/{" . $param->getName() . "}" . ($param->isOptional() ? '?' : '');
|
$params = '';
|
||||||
|
|
||||||
|
foreach ($method->getParameters() as $param) {
|
||||||
|
$params .= "/{" . $param->getName() . "}" . ($param->isOptional() ? '?' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $params;
|
private function camelCaseToDashed(string $string): string
|
||||||
}
|
{
|
||||||
|
return strtolower(preg_replace('/([A-Z])/', '-$1', lcfirst($string)));
|
||||||
|
}
|
||||||
|
|
||||||
private function camelCaseToDashed(string $string): string
|
public function getValidMethods(): array
|
||||||
{
|
{
|
||||||
return strtolower(preg_replace('/([A-Z])/', '-$1', lcfirst($string)));
|
return [
|
||||||
}
|
|
||||||
|
|
||||||
public function getValidMethods(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
Route::ANY,
|
Route::ANY,
|
||||||
Route::GET,
|
Route::GET,
|
||||||
Route::POST,
|
Route::POST,
|
||||||
|
@ -273,53 +254,51 @@ class RouteCollector
|
||||||
Route::HEAD,
|
Route::HEAD,
|
||||||
Route::OPTIONS,
|
Route::OPTIONS,
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function getData(): RouteData
|
|
||||||
{
|
|
||||||
return new RouteData($this->staticRoutes, $this->regexToRoutesMap ? $this->generateVariableRouteData() : [], $this->filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function trim(string $route): string
|
|
||||||
{
|
|
||||||
return trim($route, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateVariableRouteData(): array
|
|
||||||
{
|
|
||||||
$chunkSize = $this->computeChunkSize(count($this->regexToRoutesMap));
|
|
||||||
$chunks = array_chunk($this->regexToRoutesMap, $chunkSize, true);
|
|
||||||
return array_map([$this, 'processChunk'], $chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function computeChunkSize(int $count): float
|
|
||||||
{
|
|
||||||
$numParts = max(1, round($count / self::APPROX_CHUNK_SIZE));
|
|
||||||
return ceil($count / $numParts);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function processChunk($regexToRoutesMap): array
|
|
||||||
{
|
|
||||||
$routeMap = [];
|
|
||||||
$regexes = [];
|
|
||||||
$numGroups = 0;
|
|
||||||
foreach ($regexToRoutesMap as $regex => $routes)
|
|
||||||
{
|
|
||||||
$firstRoute = reset($routes);
|
|
||||||
$numVariables = count($firstRoute[2]);
|
|
||||||
$numGroups = max($numGroups, $numVariables);
|
|
||||||
|
|
||||||
$regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
|
|
||||||
|
|
||||||
foreach ($routes as $httpMethod => $route)
|
|
||||||
{
|
|
||||||
$routeMap[$numGroups + 1][$httpMethod] = $route;
|
|
||||||
}
|
|
||||||
|
|
||||||
$numGroups++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
public function getData(): RouteData
|
||||||
return ['regex' => $regex, 'routeMap' => $routeMap];
|
{
|
||||||
}
|
return new RouteData($this->staticRoutes, $this->regexToRoutesMap ? $this->generateVariableRouteData() : [], $this->filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function trim(string $route): string
|
||||||
|
{
|
||||||
|
return trim($route, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateVariableRouteData(): array
|
||||||
|
{
|
||||||
|
$chunkSize = $this->computeChunkSize(count($this->regexToRoutesMap));
|
||||||
|
$chunks = array_chunk($this->regexToRoutesMap, $chunkSize, true);
|
||||||
|
return array_map([$this, 'processChunk'], $chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function computeChunkSize(int $count): float
|
||||||
|
{
|
||||||
|
$numParts = max(1, round($count / self::APPROX_CHUNK_SIZE));
|
||||||
|
return ceil($count / $numParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processChunk($regexToRoutesMap): array
|
||||||
|
{
|
||||||
|
$routeMap = [];
|
||||||
|
$regexes = [];
|
||||||
|
$numGroups = 0;
|
||||||
|
foreach ($regexToRoutesMap as $regex => $routes) {
|
||||||
|
$firstRoute = reset($routes);
|
||||||
|
$numVariables = count($firstRoute[2]);
|
||||||
|
$numGroups = max($numGroups, $numVariables);
|
||||||
|
|
||||||
|
$regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
|
||||||
|
|
||||||
|
foreach ($routes as $httpMethod => $route) {
|
||||||
|
$routeMap[$numGroups + 1][$httpMethod] = $route;
|
||||||
|
}
|
||||||
|
|
||||||
|
$numGroups++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
||||||
|
return ['regex' => $regex, 'routeMap' => $routeMap];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,56 +4,56 @@ namespace Routing;
|
||||||
|
|
||||||
class RouteData
|
class RouteData
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $variableRoutes;
|
private $variableRoutes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $staticRoutes;
|
private $staticRoutes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $filters;
|
private $filters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $staticRoutes
|
* @param array $staticRoutes
|
||||||
* @param array $variableRoutes
|
* @param array $variableRoutes
|
||||||
* @param array $filters
|
* @param array $filters
|
||||||
*/
|
*/
|
||||||
public function __construct(array $staticRoutes, array $variableRoutes, array $filters)
|
public function __construct(array $staticRoutes, array $variableRoutes, array $filters)
|
||||||
{
|
{
|
||||||
$this->staticRoutes = $staticRoutes;
|
$this->staticRoutes = $staticRoutes;
|
||||||
|
|
||||||
$this->variableRoutes = $variableRoutes;
|
$this->variableRoutes = $variableRoutes;
|
||||||
|
|
||||||
$this->filters = $filters;
|
$this->filters = $filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getStaticRoutes()
|
public function getStaticRoutes()
|
||||||
{
|
{
|
||||||
return $this->staticRoutes;
|
return $this->staticRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getVariableRoutes()
|
public function getVariableRoutes()
|
||||||
{
|
{
|
||||||
return $this->variableRoutes;
|
return $this->variableRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFilters()
|
public function getFilters()
|
||||||
{
|
{
|
||||||
return $this->filters;
|
return $this->filters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ class RouteParser
|
||||||
*
|
*
|
||||||
* Finally we look for an optional '?' which is used to signify an optional route.
|
* Finally we look for an optional '?' which is used to signify an optional route.
|
||||||
*/
|
*/
|
||||||
const VARIABLE_REGEX =
|
const VARIABLE_REGEX =
|
||||||
"~\{
|
"~\{
|
||||||
\s* ([a-zA-Z0-9_]*) \s*
|
\s* ([a-zA-Z0-9_]*) \s*
|
||||||
(?:
|
(?:
|
||||||
|
@ -30,185 +30,176 @@ class RouteParser
|
||||||
)?
|
)?
|
||||||
\}\??~x";
|
\}\??~x";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default parameter character restriction (One or more characters that is not a '/').
|
* The default parameter character restriction (One or more characters that is not a '/').
|
||||||
*/
|
*/
|
||||||
const DEFAULT_DISPATCH_REGEX = '[^/]+';
|
const DEFAULT_DISPATCH_REGEX = '[^/]+';
|
||||||
|
|
||||||
private $parts;
|
private $parts;
|
||||||
|
|
||||||
private $reverseParts;
|
private $reverseParts;
|
||||||
|
|
||||||
private $partsCounter;
|
private $partsCounter;
|
||||||
|
|
||||||
private $variables;
|
private $variables;
|
||||||
|
|
||||||
private $regexOffset;
|
private $regexOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handy parameter type restrictions.
|
* Handy parameter type restrictions.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $regexShortcuts = [
|
private $regexShortcuts = [
|
||||||
':i}' => ':[0-9]+}',
|
':i}' => ':[0-9]+}',
|
||||||
':a}' => ':[0-9A-Za-z]+}',
|
':a}' => ':[0-9A-Za-z]+}',
|
||||||
':h}' => ':[0-9A-Fa-f]+}',
|
':h}' => ':[0-9A-Fa-f]+}',
|
||||||
':c}' => ':[a-zA-Z0-9+_\-\.]+}'
|
':c}' => ':[a-zA-Z0-9+_\-\.]+}'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a route returning the correct data format to pass to the dispatch engine.
|
* Parse a route returning the correct data format to pass to the dispatch engine.
|
||||||
*
|
*
|
||||||
* @param $route
|
* @param $route
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function parse($route)
|
public function parse($route)
|
||||||
{
|
|
||||||
$this->reset();
|
|
||||||
|
|
||||||
$route = strtr($route, $this->regexShortcuts);
|
|
||||||
|
|
||||||
if (!$matches = $this->extractVariableRouteParts($route))
|
|
||||||
{
|
{
|
||||||
$reverse = [
|
$this->reset();
|
||||||
|
|
||||||
|
$route = strtr($route, $this->regexShortcuts);
|
||||||
|
|
||||||
|
if (!$matches = $this->extractVariableRouteParts($route)) {
|
||||||
|
$reverse = [
|
||||||
'variable' => false,
|
'variable' => false,
|
||||||
'value' => $route
|
'value' => $route
|
||||||
];
|
];
|
||||||
|
|
||||||
return [[$route], [$reverse]];
|
return [[$route], [$reverse]];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($matches as $set)
|
foreach ($matches as $set) {
|
||||||
{
|
$this->staticParts($route, $set[0][1]);
|
||||||
|
|
||||||
$this->staticParts($route, $set[0][1]);
|
$this->validateVariable($set[1][0]);
|
||||||
|
|
||||||
$this->validateVariable($set[1][0]);
|
$regexPart = (isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX);
|
||||||
|
|
||||||
$regexPart = (isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX);
|
$this->regexOffset = $set[0][1] + strlen($set[0][0]);
|
||||||
|
|
||||||
$this->regexOffset = $set[0][1] + strlen($set[0][0]);
|
$match = '(' . $regexPart . ')';
|
||||||
|
|
||||||
$match = '(' . $regexPart . ')';
|
$isOptional = substr($set[0][0], -1) === '?';
|
||||||
|
|
||||||
$isOptional = substr($set[0][0], -1) === '?';
|
if ($isOptional) {
|
||||||
|
$match = $this->makeOptional($match);
|
||||||
|
}
|
||||||
|
|
||||||
if ($isOptional)
|
$this->reverseParts[$this->partsCounter] = [
|
||||||
{
|
|
||||||
$match = $this->makeOptional($match);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->reverseParts[$this->partsCounter] = [
|
|
||||||
'variable' => true,
|
'variable' => true,
|
||||||
'optional' => $isOptional,
|
'optional' => $isOptional,
|
||||||
'name' => $set[1][0]
|
'name' => $set[1][0]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->parts[$this->partsCounter++] = $match;
|
$this->parts[$this->partsCounter++] = $match;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->staticParts($route, strlen($route));
|
||||||
|
|
||||||
|
return [[implode('', $this->parts), $this->variables], array_values($this->reverseParts)];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->staticParts($route, strlen($route));
|
/**
|
||||||
|
* Reset the parser ready for the next route.
|
||||||
return [[implode('', $this->parts), $this->variables], array_values($this->reverseParts)];
|
*/
|
||||||
}
|
private function reset()
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the parser ready for the next route.
|
|
||||||
*/
|
|
||||||
private function reset()
|
|
||||||
{
|
|
||||||
$this->parts = [];
|
|
||||||
|
|
||||||
$this->reverseParts = [];
|
|
||||||
|
|
||||||
$this->partsCounter = 0;
|
|
||||||
|
|
||||||
$this->variables = [];
|
|
||||||
|
|
||||||
$this->regexOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return any variable route portions from the given route.
|
|
||||||
*
|
|
||||||
* @param $route
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
private function extractVariableRouteParts($route)
|
|
||||||
{
|
|
||||||
if (preg_match_all(self::VARIABLE_REGEX, $route, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
|
|
||||||
{
|
{
|
||||||
return $matches;
|
$this->parts = [];
|
||||||
|
|
||||||
|
$this->reverseParts = [];
|
||||||
|
|
||||||
|
$this->partsCounter = 0;
|
||||||
|
|
||||||
|
$this->variables = [];
|
||||||
|
|
||||||
|
$this->regexOffset = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $route
|
* Return any variable route portions from the given route.
|
||||||
* @param $nextOffset
|
*
|
||||||
*/
|
* @param $route
|
||||||
private function staticParts($route, $nextOffset)
|
*
|
||||||
{
|
* @return mixed
|
||||||
$static = preg_split('~(/)~u', substr($route, $this->regexOffset, $nextOffset - $this->regexOffset), 0, PREG_SPLIT_DELIM_CAPTURE);
|
*/
|
||||||
|
private function extractVariableRouteParts($route)
|
||||||
foreach ($static as $staticPart)
|
|
||||||
{
|
{
|
||||||
if ($staticPart)
|
if (preg_match_all(self::VARIABLE_REGEX, $route, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||||
{
|
return $matches;
|
||||||
$quotedPart = $this->quote($staticPart);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->parts[$this->partsCounter] = $quotedPart;
|
/**
|
||||||
|
* @param $route
|
||||||
|
* @param $nextOffset
|
||||||
|
*/
|
||||||
|
private function staticParts($route, $nextOffset)
|
||||||
|
{
|
||||||
|
$static = preg_split('~(/)~u', substr($route, $this->regexOffset, $nextOffset - $this->regexOffset), 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
|
||||||
$this->reverseParts[$this->partsCounter] = [
|
foreach ($static as $staticPart) {
|
||||||
|
if ($staticPart) {
|
||||||
|
$quotedPart = $this->quote($staticPart);
|
||||||
|
|
||||||
|
$this->parts[$this->partsCounter] = $quotedPart;
|
||||||
|
|
||||||
|
$this->reverseParts[$this->partsCounter] = [
|
||||||
'variable' => false,
|
'variable' => false,
|
||||||
'value' => $staticPart
|
'value' => $staticPart
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->partsCounter++;
|
$this->partsCounter++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $varName
|
* @param $varName
|
||||||
*/
|
*/
|
||||||
private function validateVariable($varName)
|
private function validateVariable($varName)
|
||||||
{
|
|
||||||
if (isset($this->variables[$varName]))
|
|
||||||
{
|
{
|
||||||
throw new BadRouteException("Cannot use the same placeholder '$varName' twice");
|
if (isset($this->variables[$varName])) {
|
||||||
|
throw new BadRouteException("Cannot use the same placeholder '$varName' twice");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->variables[$varName] = $varName;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->variables[$varName] = $varName;
|
/**
|
||||||
}
|
* @param $match
|
||||||
|
*
|
||||||
/**
|
* @return string
|
||||||
* @param $match
|
*/
|
||||||
*
|
private function makeOptional($match)
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function makeOptional($match)
|
|
||||||
{
|
|
||||||
$previous = $this->partsCounter - 1;
|
|
||||||
|
|
||||||
if (isset($this->parts[$previous]) && $this->parts[$previous] === '/')
|
|
||||||
{
|
{
|
||||||
$this->partsCounter--;
|
$previous = $this->partsCounter - 1;
|
||||||
$match = '(?:/' . $match . ')';
|
|
||||||
|
if (isset($this->parts[$previous]) && $this->parts[$previous] === '/') {
|
||||||
|
$this->partsCounter--;
|
||||||
|
$match = '(?:/' . $match . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $match . '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $match . '?';
|
/**
|
||||||
}
|
* @param $part
|
||||||
|
*
|
||||||
/**
|
* @return string
|
||||||
* @param $part
|
*/
|
||||||
*
|
private function quote($part)
|
||||||
* @return string
|
{
|
||||||
*/
|
return preg_quote($part, '~');
|
||||||
private function quote($part)
|
}
|
||||||
{
|
|
||||||
return preg_quote($part, '~');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
101
lib/thirdparty/Asana.class.php
vendored
101
lib/thirdparty/Asana.class.php
vendored
|
@ -2,82 +2,77 @@
|
||||||
|
|
||||||
class Asana
|
class Asana
|
||||||
{
|
{
|
||||||
protected static $curlOptions = ['json_response' => true, 'cache' => true, 'timeout' => 10];
|
protected static $curlOptions = ['json_response' => true, 'cache' => true, 'timeout' => 10];
|
||||||
|
|
||||||
public static function listRoadmapTasks($cache = true)
|
public static function listRoadmapTasks($cache = true)
|
||||||
{
|
{
|
||||||
// Use print_r(static::get('/projects')) to get project IDs
|
// Use print_r(static::get('/projects')) to get project IDs
|
||||||
|
|
||||||
$roadmapProjectId = 502841492992874;
|
$roadmapProjectId = 502841492992874;
|
||||||
$tasks = [];
|
$tasks = [];
|
||||||
|
|
||||||
$allTasks = array_reduce(
|
$allTasks = array_reduce(
|
||||||
static::get('/projects/' . $roadmapProjectId . '/tasks', [], $cache),
|
static::get('/projects/' . $roadmapProjectId . '/tasks', [], $cache),
|
||||||
function($carry, $task) use($cache) {
|
function ($carry, $task) use ($cache) {
|
||||||
$fullTask = static::get('/tasks/' . $task['id'], [], $cache);
|
$fullTask = static::get('/tasks/' . $task['id'], [], $cache);
|
||||||
if ($fullTask['name']) {
|
if ($fullTask['name']) {
|
||||||
$carry[] = $fullTask;
|
$carry[] = $fullTask;
|
||||||
}
|
}
|
||||||
return $carry;
|
return $carry;
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($allTasks as $task)
|
foreach ($allTasks as $task) {
|
||||||
{
|
$badge = "Planned";
|
||||||
$badge = "Planned";
|
if ($task['completed']) {
|
||||||
if ($task['completed'])
|
$badge = "Complete";
|
||||||
{
|
} elseif (in_array("In Progress", array_map(function ($tag) {
|
||||||
$badge = "Complete";
|
return $tag['name'];
|
||||||
}
|
}, $task['tags'] ?? []))) {
|
||||||
else if (in_array("In Progress", array_map(function($tag) { return $tag['name']; }, $task['tags'] ?? [])))
|
$badge = "In Progress";
|
||||||
{
|
}
|
||||||
$badge = "In Progress";
|
$taskDueTime = strtotime($task['due_on']);
|
||||||
}
|
$year = date('Y', $taskDueTime);
|
||||||
$taskDueTime = strtotime($task['due_on']);
|
$tasks[' ' . $year . ' '][] = array_intersect_key($task, ['name' => null]) + [
|
||||||
$year = date('Y', $taskDueTime);
|
|
||||||
$tasks[' ' . $year . ' '][] = array_intersect_key($task, ['name' => null]) + [
|
|
||||||
'badge' => $badge,
|
'badge' => $badge,
|
||||||
'date' => $task['due_on'] ?? null,
|
'date' => $task['due_on'] ?? null,
|
||||||
'body' => nl2br($task['notes']),
|
'body' => nl2br($task['notes']),
|
||||||
// 'assignee' => $fullTask['assignee'] ? ucwords($fullTask['assignee']['name']) : '',
|
// 'assignee' => $fullTask['assignee'] ? ucwords($fullTask['assignee']['name']) : '',
|
||||||
'quarter_date' => 'Q' . static::dateToQuarter($task['due_on']) . ' ' . $year
|
'quarter_date' => 'Q' . static::dateToQuarter($task['due_on']) . ' ' . $year
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($tasks as &$groupTasks)
|
|
||||||
{
|
|
||||||
usort($groupTasks, function ($tA, $tB)
|
|
||||||
{
|
|
||||||
if ($tA['date'] xor $tB['date'])
|
|
||||||
{
|
|
||||||
return $tA['date'] ? -1 : 1;
|
|
||||||
}
|
}
|
||||||
return $tA['date'] < $tB['date'] ? -1 : 1;
|
|
||||||
});
|
foreach ($tasks as &$groupTasks) {
|
||||||
|
usort($groupTasks, function ($tA, $tB) {
|
||||||
|
if ($tA['date'] xor $tB['date']) {
|
||||||
|
return $tA['date'] ? -1 : 1;
|
||||||
|
}
|
||||||
|
return $tA['date'] < $tB['date'] ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $tasks;
|
protected static function get($endpoint, array $data = [], $cache = true)
|
||||||
}
|
{
|
||||||
|
$apiKey = Config::get(Config::ASANA_KEY);
|
||||||
|
|
||||||
protected static function get($endpoint, array $data = [], $cache = true)
|
$options = [
|
||||||
{
|
|
||||||
$apiKey = Config::get(Config::ASANA_KEY);
|
|
||||||
|
|
||||||
$options = [
|
|
||||||
'headers' => ['Authorization: Bearer ' . $apiKey],
|
'headers' => ['Authorization: Bearer ' . $apiKey],
|
||||||
'cache' => $cache
|
'cache' => $cache
|
||||||
] + static::$curlOptions;
|
] + static::$curlOptions;
|
||||||
|
|
||||||
$responseData = CurlWithCache::get('https://app.asana.com/api/1.0' . $endpoint, $data, $options);
|
$responseData = CurlWithCache::get('https://app.asana.com/api/1.0' . $endpoint, $data, $options);
|
||||||
return $responseData['data'] ?? [];
|
return $responseData['data'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts date to quarter
|
// Converts date to quarter
|
||||||
protected static function dateToQuarter($date)
|
protected static function dateToQuarter($date)
|
||||||
{
|
{
|
||||||
return (string)ceil(date('m', strtotime($date))/3);
|
return (string)ceil(date('m', strtotime($date))/3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsanaException extends Exception
|
class AsanaException extends Exception
|
||||||
|
|
261
lib/thirdparty/Github.class.php
vendored
261
lib/thirdparty/Github.class.php
vendored
|
@ -2,155 +2,135 @@
|
||||||
|
|
||||||
class Github
|
class Github
|
||||||
{
|
{
|
||||||
protected static function findReleaseAssetForOs(array $release, string $os)
|
protected static function findReleaseAssetForOs(array $release, string $os)
|
||||||
{
|
|
||||||
if (!in_array($os, array_keys(OS::getAll())))
|
|
||||||
{
|
{
|
||||||
throw new DomainException('Unknown OS');
|
if (!in_array($os, array_keys(OS::getAll()))) {
|
||||||
}
|
throw new DomainException('Unknown OS');
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($release['assets'] as $asset)
|
foreach ($release['assets'] as $asset) {
|
||||||
{
|
$ext = substr($asset['name'], -4);
|
||||||
$ext = substr($asset['name'], -4);
|
if (
|
||||||
if (
|
|
||||||
($os == OS::OS_LINUX &&
|
($os == OS::OS_LINUX &&
|
||||||
($ext == '.deb' || in_array($asset['content_type'], ['application/x-debian-package', 'application/x-deb']))) ||
|
($ext == '.deb' || in_array($asset['content_type'], ['application/x-debian-package', 'application/x-deb']))) ||
|
||||||
($os == OS::OS_OSX &&
|
($os == OS::OS_OSX &&
|
||||||
($ext == '.dmg' || in_array($asset['content_type'], ['application/x-diskcopy', 'application/x-apple-diskimage']))) ||
|
($ext == '.dmg' || in_array($asset['content_type'], ['application/x-diskcopy', 'application/x-apple-diskimage']))) ||
|
||||||
($os == OS::OS_WINDOWS && $ext == '.exe')
|
($os == OS::OS_WINDOWS && $ext == '.exe')
|
||||||
)
|
) {
|
||||||
{
|
return $asset;
|
||||||
return $asset;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAppRelease($cache = true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return static::get('/repos/lbryio/lbry-app/releases/latest', [], $cache);
|
|
||||||
}
|
|
||||||
catch (Exception $e)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public static function getAppRelease($cache = true)
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAppAsset($os, $cache = true)
|
|
||||||
{
|
|
||||||
$release = static::getAppRelease($cache);
|
|
||||||
return $release ? static::findReleaseAssetForOs($release, $os) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function getAppDownloadUrl($os, $cache = true)
|
|
||||||
{
|
|
||||||
$asset = static::getAppAsset($os, $cache);
|
|
||||||
return $asset ? $asset['browser_download_url'] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getAppPrereleaseDownloadUrl($os, $cache = true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
$releases = static::get('/repos/lbryio/lbry-app/releases', [], $cache);
|
try {
|
||||||
if (count($releases))
|
return static::get('/repos/lbryio/lbry-app/releases/latest', [], $cache);
|
||||||
{
|
} catch (Exception $e) {
|
||||||
$asset = static::findReleaseAssetForOs($releases[0], $os);
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAppAsset($os, $cache = true)
|
||||||
|
{
|
||||||
|
$release = static::getAppRelease($cache);
|
||||||
|
return $release ? static::findReleaseAssetForOs($release, $os) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getAppDownloadUrl($os, $cache = true)
|
||||||
|
{
|
||||||
|
$asset = static::getAppAsset($os, $cache);
|
||||||
return $asset ? $asset['browser_download_url'] : null;
|
return $asset ? $asset['browser_download_url'] : null;
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception $e)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public static function getAppPrereleaseDownloadUrl($os, $cache = true)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function getDaemonReleaseProperty($os, $property, $isAssetProperty = false, $cache = true)
|
|
||||||
{
|
|
||||||
if (!in_array($os, array_keys(OS::getAll())))
|
|
||||||
{
|
{
|
||||||
throw new DomainException('Unknown OS');
|
try {
|
||||||
|
$releases = static::get('/repos/lbryio/lbry-app/releases', [], $cache);
|
||||||
|
if (count($releases)) {
|
||||||
|
$asset = static::findReleaseAssetForOs($releases[0], $os);
|
||||||
|
return $asset ? $asset['browser_download_url'] : null;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
|
public static function getDaemonReleaseProperty($os, $property, $isAssetProperty = false, $cache = true)
|
||||||
{
|
{
|
||||||
$releaseData = static::get('/repos/lbryio/lbry/releases/latest', [], $cache);
|
if (!in_array($os, array_keys(OS::getAll()))) {
|
||||||
foreach ($releaseData['assets'] as $asset)
|
throw new DomainException('Unknown OS');
|
||||||
{
|
}
|
||||||
if (
|
|
||||||
|
try {
|
||||||
|
$releaseData = static::get('/repos/lbryio/lbry/releases/latest', [], $cache);
|
||||||
|
foreach ($releaseData['assets'] as $asset) {
|
||||||
|
if (
|
||||||
($os == OS::OS_LINUX && stripos($asset['browser_download_url'], 'linux') !== false) ||
|
($os == OS::OS_LINUX && stripos($asset['browser_download_url'], 'linux') !== false) ||
|
||||||
($os == OS::OS_OSX && stripos($asset['browser_download_url'], 'macos') !== false) ||
|
($os == OS::OS_OSX && stripos($asset['browser_download_url'], 'macos') !== false) ||
|
||||||
($os == OS::OS_WINDOWS && strpos($asset['browser_download_url'], 'windows') !== false)
|
($os == OS::OS_WINDOWS && strpos($asset['browser_download_url'], 'windows') !== false)
|
||||||
)
|
) {
|
||||||
{
|
return $isAssetProperty ? $asset[$property] : $releaseData[$property];
|
||||||
return $isAssetProperty ? $asset[$property] : $releaseData[$property];
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
return null;
|
||||||
catch (Exception $e)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public static function getDaemonDownloadUrl($os, $cache = true)
|
||||||
}
|
|
||||||
|
|
||||||
public static function getDaemonDownloadUrl($os, $cache = true)
|
|
||||||
{
|
|
||||||
return static::getDaemonReleaseProperty($os, 'browser_download_url', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function get($endpoint, array $params = [], $cache = true)
|
|
||||||
{
|
|
||||||
$twoHoursInSeconds = 7200;
|
|
||||||
return CurlWithCache::get('https://api.github.com' . $endpoint . '?' . http_build_query($params), [],
|
|
||||||
['headers' => ['Accept: application/vnd.github.v3.html+json'],'user_agent' => 'LBRY', 'json_response' => true, 'cache' => $cache === true ? $twoHoursInSeconds : $cache]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function listRoadmapChangesets($cache = true)
|
|
||||||
{
|
|
||||||
$sets = [];
|
|
||||||
$allReleases = [];
|
|
||||||
|
|
||||||
$projects = ['lbry' => 'LBRY Protocol', 'lbry-app' => 'LBRY App'];
|
|
||||||
|
|
||||||
foreach($projects as $project => $projectLabel)
|
|
||||||
{
|
{
|
||||||
$page = 1;
|
return static::getDaemonReleaseProperty($os, 'browser_download_url', true);
|
||||||
do
|
|
||||||
{
|
|
||||||
$releases = static::get('/repos/lbryio/' . $project . '/releases', ['page' => $page], $cache);
|
|
||||||
$page++;
|
|
||||||
$allReleases = array_merge($allReleases, array_map(function ($release) use ($project, $projectLabel)
|
|
||||||
{
|
|
||||||
return $release + ['project' => $projectLabel];
|
|
||||||
}, array_filter($releases, function ($release)
|
|
||||||
{
|
|
||||||
return isset($release['tag_name']) && isset($release['published_at']) && $release['published_at'];
|
|
||||||
})));
|
|
||||||
} while (count($releases) >= 30);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function get($endpoint, array $params = [], $cache = true)
|
||||||
* This logic is likely overly convoluted at this point. It used to group releases by project before going
|
|
||||||
* to strictly by time. - Jeremy
|
|
||||||
*/
|
|
||||||
|
|
||||||
foreach ($allReleases as $release)
|
|
||||||
{
|
{
|
||||||
$group = null;
|
$twoHoursInSeconds = 7200;
|
||||||
$matches = null;
|
return CurlWithCache::get(
|
||||||
if (preg_match('/^v(\d+)\.(\d+)\./', $release['tag_name'] ?? '', $matches))
|
'https://api.github.com' . $endpoint . '?' . http_build_query($params),
|
||||||
{
|
[],
|
||||||
$group = $release['project'] . ' v' . $matches[1] . '.' . $matches[2];
|
['headers' => ['Accept: application/vnd.github.v3.html+json'],'user_agent' => 'LBRY', 'json_response' => true, 'cache' => $cache === true ? $twoHoursInSeconds : $cache]
|
||||||
}
|
);
|
||||||
if ($group)
|
}
|
||||||
{
|
|
||||||
$sets[$group][] = array_intersect_key($release, [
|
public static function listRoadmapChangesets($cache = true)
|
||||||
|
{
|
||||||
|
$sets = [];
|
||||||
|
$allReleases = [];
|
||||||
|
|
||||||
|
$projects = ['lbry' => 'LBRY Protocol', 'lbry-app' => 'LBRY App'];
|
||||||
|
|
||||||
|
foreach ($projects as $project => $projectLabel) {
|
||||||
|
$page = 1;
|
||||||
|
do {
|
||||||
|
$releases = static::get('/repos/lbryio/' . $project . '/releases', ['page' => $page], $cache);
|
||||||
|
$page++;
|
||||||
|
$allReleases = array_merge($allReleases, array_map(function ($release) use ($project, $projectLabel) {
|
||||||
|
return $release + ['project' => $projectLabel];
|
||||||
|
}, array_filter($releases, function ($release) {
|
||||||
|
return isset($release['tag_name']) && isset($release['published_at']) && $release['published_at'];
|
||||||
|
})));
|
||||||
|
} while (count($releases) >= 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This logic is likely overly convoluted at this point. It used to group releases by project before going
|
||||||
|
* to strictly by time. - Jeremy
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach ($allReleases as $release) {
|
||||||
|
$group = null;
|
||||||
|
$matches = null;
|
||||||
|
if (preg_match('/^v(\d+)\.(\d+)\./', $release['tag_name'] ?? '', $matches)) {
|
||||||
|
$group = $release['project'] . ' v' . $matches[1] . '.' . $matches[2];
|
||||||
|
}
|
||||||
|
if ($group) {
|
||||||
|
$sets[$group][] = array_intersect_key($release, [
|
||||||
'prerelease' => null, 'tag_name' => null, 'published_at' => null, 'project' => null
|
'prerelease' => null, 'tag_name' => null, 'published_at' => null, 'project' => null
|
||||||
]) + [
|
]) + [
|
||||||
'created_at' => strtotime($release['created_at']),
|
'created_at' => strtotime($release['created_at']),
|
||||||
|
@ -165,23 +145,22 @@ class Github
|
||||||
'version' => $matches[1] . '.' . $matches[2] . '.' . (isset($matches[3]) ? $matches[3] : ''),
|
'version' => $matches[1] . '.' . $matches[2] . '.' . (isset($matches[3]) ? $matches[3] : ''),
|
||||||
'body' => $release['body_html']
|
'body' => $release['body_html']
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($sets, function ($sA, $sB) {
|
||||||
|
if ($sA[0]['project'] != $sB[0]['project']) {
|
||||||
|
return $sA[0]['project'] < $sB[0]['project'] ? -1 : 1;
|
||||||
|
}
|
||||||
|
return $sB[0]['sort_key'] <=> $sA[0]['sort_key'];
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($sets as $group => &$groupSet) {
|
||||||
|
usort($groupSet, function ($rA, $rB) {
|
||||||
|
return $rB['created_at'] <=> $rA['created_at'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sets;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
uasort($sets, function ($sA, $sB)
|
|
||||||
{
|
|
||||||
if ($sA[0]['project'] != $sB[0]['project'])
|
|
||||||
{
|
|
||||||
return $sA[0]['project'] < $sB[0]['project'] ? -1 : 1;
|
|
||||||
}
|
|
||||||
return $sB[0]['sort_key'] <=> $sA[0]['sort_key'];
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach ($sets as $group => &$groupSet)
|
|
||||||
{
|
|
||||||
usort($groupSet, function ($rA, $rB) { return $rB['created_at'] <=> $rA['created_at']; });
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
84
lib/thirdparty/LBRY.class.php
vendored
84
lib/thirdparty/LBRY.class.php
vendored
|
@ -3,58 +3,56 @@
|
||||||
|
|
||||||
class LBRY
|
class LBRY
|
||||||
{
|
{
|
||||||
public static function getApiUrl($endpoint)
|
public static function getApiUrl($endpoint)
|
||||||
{
|
{
|
||||||
return Config::get(Config::LBRY_API_SERVER) . $endpoint;
|
return Config::get(Config::LBRY_API_SERVER) . $endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getLBCtoUSDRate()
|
public static function getLBCtoUSDRate()
|
||||||
{
|
{
|
||||||
$response = CurlWithCache::get(static::getApiUrl('/lbc/exchange_rate'), [], [
|
$response = CurlWithCache::get(static::getApiUrl('/lbc/exchange_rate'), [], [
|
||||||
'cache' => 3600, //one hour
|
'cache' => 3600, //one hour
|
||||||
'json_response' => true
|
'json_response' => true
|
||||||
]);
|
]);
|
||||||
return $response['data']['lbc_usd'] ?? 0;
|
return $response['data']['lbc_usd'] ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function subscribe($email, $tag = null)
|
public static function subscribe($email, $tag = null)
|
||||||
{
|
{
|
||||||
return Curl::post(static::getApiUrl('/list/subscribe'), array_filter([
|
return Curl::post(static::getApiUrl('/list/subscribe'), array_filter([
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'tag' => $tag,
|
'tag' => $tag,
|
||||||
]), ['json_response' => true]);
|
]), ['json_response' => true]);
|
||||||
}
|
|
||||||
|
|
||||||
public static function unsubscribe($email)
|
|
||||||
{
|
|
||||||
return Curl::post(static::getApiUrl('/list/unsubscribe'), ['email' => $email], ['json_response' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function connectYoutube($channel_name)
|
|
||||||
{
|
|
||||||
$type = 'sync';
|
|
||||||
return Curl::post(static::getApiUrl('/yt/new'), ['desired_lbry_channel_name' => $channel_name, 'type' => $type], ['json_response' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the sync status
|
|
||||||
public static function statusYoutube($status_token)
|
|
||||||
{
|
|
||||||
return Curl::get(static::getApiUrl('/yt/status'), ['status_token' => $status_token], ['json_response' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function youtubeReward()
|
|
||||||
{
|
|
||||||
return CurlWithCache::post(static::getApiUrl('/yt/rewards'), [], ['cache' => 3600, 'json_response' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function editYouTube($status_token, $channel_name, $email, $sync_consent)
|
|
||||||
{
|
|
||||||
if ($email == null){
|
|
||||||
return Curl::post(static::getApiUrl("/yt/update"),['status_token' => $status_token, 'new_preferred_channel' => $channel_name, 'sync_consent' => $sync_consent],['json_response' => true]);
|
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
|
|
||||||
return Curl::post(static::getApiUrl("/yt/update"), ['status_token' => $status_token, 'new_email' => $email, 'new_preferred_channel' => $channel_name, 'sync_consent' => $sync_consent], ['json_response' => true]);
|
public static function unsubscribe($email)
|
||||||
|
{
|
||||||
|
return Curl::post(static::getApiUrl('/list/unsubscribe'), ['email' => $email], ['json_response' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function connectYoutube($channel_name)
|
||||||
|
{
|
||||||
|
$type = 'sync';
|
||||||
|
return Curl::post(static::getApiUrl('/yt/new'), ['desired_lbry_channel_name' => $channel_name, 'type' => $type], ['json_response' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the sync status
|
||||||
|
public static function statusYoutube($status_token)
|
||||||
|
{
|
||||||
|
return Curl::get(static::getApiUrl('/yt/status'), ['status_token' => $status_token], ['json_response' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function youtubeReward()
|
||||||
|
{
|
||||||
|
return CurlWithCache::post(static::getApiUrl('/yt/rewards'), [], ['cache' => 3600, 'json_response' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function editYouTube($status_token, $channel_name, $email, $sync_consent)
|
||||||
|
{
|
||||||
|
if ($email == null) {
|
||||||
|
return Curl::post(static::getApiUrl("/yt/update"), ['status_token' => $status_token, 'new_preferred_channel' => $channel_name, 'sync_consent' => $sync_consent], ['json_response' => true]);
|
||||||
|
} else {
|
||||||
|
return Curl::post(static::getApiUrl("/yt/update"), ['status_token' => $status_token, 'new_email' => $email, 'new_preferred_channel' => $channel_name, 'sync_consent' => $sync_consent], ['json_response' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
62
lib/thirdparty/Mailgun.class.php
vendored
62
lib/thirdparty/Mailgun.class.php
vendored
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
class Mailgun
|
class Mailgun
|
||||||
{
|
{
|
||||||
const BASE_URL = 'https://api.mailgun.net/v3';
|
const BASE_URL = 'https://api.mailgun.net/v3';
|
||||||
|
|
||||||
const TOP_DOMAIN = 'lbry.io';
|
const TOP_DOMAIN = 'lbry.io';
|
||||||
const MAIL_DOMAIN = 'mail.lbry.io';
|
const MAIL_DOMAIN = 'mail.lbry.io';
|
||||||
|
|
||||||
const LIST_GENERAL = 'lbryians@lbry.io';
|
const LIST_GENERAL = 'lbryians@lbry.io';
|
||||||
|
|
||||||
public static function sendDmcaReport($data)
|
public static function sendDmcaReport($data)
|
||||||
{
|
{
|
||||||
list($status, $headers, $body) = static::post('/' . static::MAIL_DOMAIN . '/messages', [
|
list($status, $headers, $body) = static::post('/' . static::MAIL_DOMAIN . '/messages', [
|
||||||
'from' => 'LBRY <mail@' . static::MAIL_DOMAIN . '>',
|
'from' => 'LBRY <mail@' . static::MAIL_DOMAIN . '>',
|
||||||
'to' => 'help@lbry.io',
|
'to' => 'help@lbry.io',
|
||||||
'subject' => 'DMCA Report #' . $data['report_id'],
|
'subject' => 'DMCA Report #' . $data['report_id'],
|
||||||
|
@ -20,12 +20,12 @@ class Mailgun
|
||||||
'o:tracking-opens' => 'no'
|
'o:tracking-opens' => 'no'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $status == 200;
|
return $status == 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function sendYouTubeWarmLead($data)
|
public static function sendYouTubeWarmLead($data)
|
||||||
{
|
{
|
||||||
list($status, $headers, $body) = static::post('/' . static::MAIL_DOMAIN . '/messages', [
|
list($status, $headers, $body) = static::post('/' . static::MAIL_DOMAIN . '/messages', [
|
||||||
'from' => 'LBRY <mail@' . static::MAIL_DOMAIN . '>',
|
'from' => 'LBRY <mail@' . static::MAIL_DOMAIN . '>',
|
||||||
'to' => 'reilly@lbry.io',
|
'to' => 'reilly@lbry.io',
|
||||||
'subject' => 'Interested YouTuber',
|
'subject' => 'Interested YouTuber',
|
||||||
|
@ -34,32 +34,32 @@ class Mailgun
|
||||||
'o:tracking-opens' => 'no'
|
'o:tracking-opens' => 'no'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $status == 200;
|
return $status == 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function post($endpoint, $data)
|
protected static function post($endpoint, $data)
|
||||||
{
|
{
|
||||||
return static::request(Curl::POST, $endpoint, $data);
|
return static::request(Curl::POST, $endpoint, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function put($endpoint, $data)
|
protected static function put($endpoint, $data)
|
||||||
{
|
{
|
||||||
return static::request(Curl::PUT, $endpoint, $data);
|
return static::request(Curl::PUT, $endpoint, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function request($method, $endpoint, $data)
|
protected static function request($method, $endpoint, $data)
|
||||||
{
|
{
|
||||||
return Curl::doCurl($method, self::BASE_URL . $endpoint, $data, [
|
return Curl::doCurl($method, self::BASE_URL . $endpoint, $data, [
|
||||||
'headers' => [
|
'headers' => [
|
||||||
'Authorization: Basic ' . base64_encode('api:' . Config::get(Config::MAILGUN_API_KEY))
|
'Authorization: Basic ' . base64_encode('api:' . Config::get(Config::MAILGUN_API_KEY))
|
||||||
],
|
],
|
||||||
'retry' => 3,
|
'retry' => 3,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function inlineCss($html, $css = '')
|
protected static function inlineCss($html, $css = '')
|
||||||
{
|
{
|
||||||
$e = new \Pelago\Emogrifier($html, $css);
|
$e = new \Pelago\Emogrifier($html, $css);
|
||||||
return trim($e->emogrify());
|
return trim($e->emogrify());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
64
lib/thirdparty/Salesforce.class.php
vendored
64
lib/thirdparty/Salesforce.class.php
vendored
|
@ -2,21 +2,20 @@
|
||||||
|
|
||||||
class Salesforce
|
class Salesforce
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
API_URL = 'https://api.salesforceiq.com/v2/',
|
API_URL = 'https://api.salesforceiq.com/v2/',
|
||||||
DEFAULT_LIST_ID = '58387a94e4b0a1fea2c76f4a';
|
DEFAULT_LIST_ID = '58387a94e4b0a1fea2c76f4a';
|
||||||
|
|
||||||
protected static
|
protected static $curlOptions = [
|
||||||
$curlOptions = [
|
|
||||||
'headers' => ['Accept: application/json', 'Content-type: application/json'],
|
'headers' => ['Accept: application/json', 'Content-type: application/json'],
|
||||||
'json_response' => true,
|
'json_response' => true,
|
||||||
'json_data' => true,
|
'json_data' => true,
|
||||||
'timeout' => 10
|
'timeout' => 10
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function createContact(string $email, string $initialListId = null, string $acquisitionChannel = null)
|
public static function createContact(string $email, string $initialListId = null, string $acquisitionChannel = null)
|
||||||
{
|
{
|
||||||
$contactData = [
|
$contactData = [
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'email' => [[
|
'email' => [[
|
||||||
'value' => $email,
|
'value' => $email,
|
||||||
|
@ -25,54 +24,51 @@ class Salesforce
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$contactId = static::post('contacts?_upsert=email', $contactData)['id'] ?? null;
|
$contactId = static::post('contacts?_upsert=email', $contactData)['id'] ?? null;
|
||||||
|
|
||||||
if ($initialListId)
|
if ($initialListId) {
|
||||||
{
|
if (!$contactId) {
|
||||||
if (!$contactId)
|
throw new SalesforceException('Failed to generate or update contact');
|
||||||
{
|
}
|
||||||
throw new SalesforceException('Failed to generate or update contact');
|
|
||||||
}
|
|
||||||
|
|
||||||
static::post('lists/' . $initialListId . '/listitems?_upsert=contactIds', [
|
static::post('lists/' . $initialListId . '/listitems?_upsert=contactIds', [
|
||||||
'contactIds' => [$contactId],
|
'contactIds' => [$contactId],
|
||||||
'fieldValues' => (object)[
|
'fieldValues' => (object)[
|
||||||
'2' => [['raw' => $acquisitionChannel]]
|
'2' => [['raw' => $acquisitionChannel]]
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getApiUserPassword()
|
protected static function getApiUserPassword()
|
||||||
{
|
|
||||||
$userpw = Config::get(Config::SALESFORCE_KEY) . ':' . Config::get(Config::SALESFORCE_SECRET);
|
|
||||||
if ($userpw[0] === ':' || substr($userpw, -1) === ':')
|
|
||||||
{
|
{
|
||||||
throw new SalesforceException('Salesforce key and/or secret not configured correctly');
|
$userpw = Config::get(Config::SALESFORCE_KEY) . ':' . Config::get(Config::SALESFORCE_SECRET);
|
||||||
|
if ($userpw[0] === ':' || substr($userpw, -1) === ':') {
|
||||||
|
throw new SalesforceException('Salesforce key and/or secret not configured correctly');
|
||||||
|
}
|
||||||
|
return $userpw;
|
||||||
}
|
}
|
||||||
return $userpw;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function get($endpoint, array $data = [])
|
public static function get($endpoint, array $data = [])
|
||||||
{
|
{
|
||||||
$options = [
|
$options = [
|
||||||
'password' => static::getApiUserPassword(),
|
'password' => static::getApiUserPassword(),
|
||||||
] + static::$curlOptions;
|
] + static::$curlOptions;
|
||||||
|
|
||||||
$responseData = Curl::get(static::API_URL . $endpoint, $data, $options);
|
$responseData = Curl::get(static::API_URL . $endpoint, $data, $options);
|
||||||
|
|
||||||
return $responseData ?? [];
|
return $responseData ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function post($endpoint, array $data = [], array $options = [])
|
public static function post($endpoint, array $data = [], array $options = [])
|
||||||
{
|
{
|
||||||
$options += [
|
$options += [
|
||||||
'password' => static::getApiUserPassword(),
|
'password' => static::getApiUserPassword(),
|
||||||
] + static::$curlOptions;
|
] + static::$curlOptions;
|
||||||
|
|
||||||
$responseData = Curl::post(static::API_URL . $endpoint, $data, $options);
|
$responseData = Curl::post(static::API_URL . $endpoint, $data, $options);
|
||||||
return $responseData ?? [];
|
return $responseData ?? [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SalesforceException extends Exception
|
class SalesforceException extends Exception
|
||||||
|
|
19
lib/thirdparty/Slack.class.php
vendored
19
lib/thirdparty/Slack.class.php
vendored
|
@ -2,18 +2,15 @@
|
||||||
|
|
||||||
class Slack
|
class Slack
|
||||||
{
|
{
|
||||||
|
public static function sendErrorIfProd($e, $alert = true)
|
||||||
public static function sendErrorIfProd($e, $alert = true)
|
|
||||||
{
|
|
||||||
if ($e instanceof Throwable)
|
|
||||||
{
|
{
|
||||||
$e = Debug::exceptionToString($e);
|
if ($e instanceof Throwable) {
|
||||||
}
|
$e = Debug::exceptionToString($e);
|
||||||
|
}
|
||||||
|
|
||||||
$slackErrorNotificationUrl = Config::get(Config::SLACK_ERROR_NOTIFICATION_URL);
|
$slackErrorNotificationUrl = Config::get(Config::SLACK_ERROR_NOTIFICATION_URL);
|
||||||
if ($slackErrorNotificationUrl)
|
if ($slackErrorNotificationUrl) {
|
||||||
{
|
Curl::post($slackErrorNotificationUrl, ['text' => ($alert ? '<!channel> ' : '') . Request::getRelativeUri() . "\n" . $e], ['json_data' => true]);
|
||||||
Curl::post($slackErrorNotificationUrl, ['text' => ($alert ? '<!channel> ' : '') . Request::getRelativeUri() . "\n" . $e], ['json_data' => true]);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,45 +2,43 @@
|
||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
const HELP_CONTACT_EMAIL = 'josh@lbry.io';
|
const HELP_CONTACT_EMAIL = 'josh@lbry.io';
|
||||||
|
|
||||||
//Constant to help with managing strings
|
//Constant to help with managing strings
|
||||||
const IS_PROD = "is_prod";
|
const IS_PROD = "is_prod";
|
||||||
const GITHUB_KEY = "github_key";
|
const GITHUB_KEY = "github_key";
|
||||||
const GITHUB_DEVELOPER_CREDITS_CLIENT_ID = "github_developer_credits_client_id";
|
const GITHUB_DEVELOPER_CREDITS_CLIENT_ID = "github_developer_credits_client_id";
|
||||||
const GITHUB_DEVELOPER_CREDITS_CLIENT_SECRET = "github_developer_credits_client_secret";
|
const GITHUB_DEVELOPER_CREDITS_CLIENT_SECRET = "github_developer_credits_client_secret";
|
||||||
const LBRY_API_SERVER = "lbry_api_server";
|
const LBRY_API_SERVER = "lbry_api_server";
|
||||||
const MAILCHIMP_KEY = "mailchimp_key";
|
const MAILCHIMP_KEY = "mailchimp_key";
|
||||||
const ASANA_KEY = "asana_key";
|
const ASANA_KEY = "asana_key";
|
||||||
const AWS_LOG_ACCESS_KEY = "aws_log_access_key";
|
const AWS_LOG_ACCESS_KEY = "aws_log_access_key";
|
||||||
const AWS_LOG_SECRET_KEY = "aws_log_secret_key";
|
const AWS_LOG_SECRET_KEY = "aws_log_secret_key";
|
||||||
const MAILGUN_API_KEY = "mailgun_api_key";
|
const MAILGUN_API_KEY = "mailgun_api_key";
|
||||||
const SALESFORCE_KEY = "salesforce_key";
|
const SALESFORCE_KEY = "salesforce_key";
|
||||||
const SALESFORCE_SECRET = "salesforce_secret";
|
const SALESFORCE_SECRET = "salesforce_secret";
|
||||||
const SLACK_ERROR_NOTIFICATION_URL = "slack_error_notification_url";
|
const SLACK_ERROR_NOTIFICATION_URL = "slack_error_notification_url";
|
||||||
|
|
||||||
|
|
||||||
protected static $loaded = false;
|
protected static $loaded = false;
|
||||||
protected static $data = [];
|
protected static $data = [];
|
||||||
|
|
||||||
public static function get($name, $default = null)
|
public static function get($name, $default = null)
|
||||||
{
|
|
||||||
static::load();
|
|
||||||
return array_key_exists($name, static::$data) ? static::$data[$name] : $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected static function load()
|
|
||||||
{
|
|
||||||
if (!static::$loaded)
|
|
||||||
{
|
{
|
||||||
$dataFile = ROOT_DIR.'/data/config.php';
|
static::load();
|
||||||
if (!is_readable($dataFile))
|
return array_key_exists($name, static::$data) ? static::$data[$name] : $default;
|
||||||
{
|
}
|
||||||
throw new RuntimeException('config file is missing or not readable');
|
|
||||||
}
|
|
||||||
static::$data = require $dataFile;
|
protected static function load()
|
||||||
static::$loaded = true;
|
{
|
||||||
|
if (!static::$loaded) {
|
||||||
|
$dataFile = ROOT_DIR.'/data/config.php';
|
||||||
|
if (!is_readable($dataFile)) {
|
||||||
|
throw new RuntimeException('config file is missing or not readable');
|
||||||
|
}
|
||||||
|
static::$data = require $dataFile;
|
||||||
|
static::$loaded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,40 +2,40 @@
|
||||||
|
|
||||||
class Curl
|
class Curl
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
GET = 'GET',
|
GET = 'GET',
|
||||||
POST = 'POST',
|
POST = 'POST',
|
||||||
PUT = 'PUT',
|
PUT = 'PUT',
|
||||||
DELETE = 'DELETE';
|
DELETE = 'DELETE';
|
||||||
|
|
||||||
|
|
||||||
public static function get($url, $params = [], $options = [])
|
public static function get($url, $params = [], $options = [])
|
||||||
{
|
{
|
||||||
list ($status, $headers, $body) = static::doCurl(static::GET, $url, $params, $options);
|
list($status, $headers, $body) = static::doCurl(static::GET, $url, $params, $options);
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function post($url, $params = [], $options = [])
|
public static function post($url, $params = [], $options = [])
|
||||||
{
|
{
|
||||||
list ($status, $headers, $body) = static::doCurl(static::POST, $url, $params, $options);
|
list($status, $headers, $body) = static::doCurl(static::POST, $url, $params, $options);
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function put($url, $params = [], $options = [])
|
public static function put($url, $params = [], $options = [])
|
||||||
{
|
{
|
||||||
list ($status, $headers, $body) = static::doCurl(static::PUT, $url, $params, $options);
|
list($status, $headers, $body) = static::doCurl(static::PUT, $url, $params, $options);
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($url, $params = [], $options = [])
|
public static function delete($url, $params = [], $options = [])
|
||||||
{
|
{
|
||||||
list ($status, $headers, $body) = static::doCurl(static::DELETE, $url, $params, $options);
|
list($status, $headers, $body) = static::doCurl(static::DELETE, $url, $params, $options);
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function doCurl($method, $url, $params = [], $options = [])
|
public static function doCurl($method, $url, $params = [], $options = [])
|
||||||
{
|
{
|
||||||
$defaults = [
|
$defaults = [
|
||||||
'headers' => [],
|
'headers' => [],
|
||||||
'verify' => true,
|
'verify' => true,
|
||||||
'timeout' => 5,
|
'timeout' => 5,
|
||||||
|
@ -49,41 +49,36 @@ class Curl
|
||||||
'retry' => false,
|
'retry' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
$invalid = array_diff_key($options, $defaults);
|
$invalid = array_diff_key($options, $defaults);
|
||||||
if ($invalid)
|
if ($invalid) {
|
||||||
{
|
throw new DomainException('Invalid curl options: ' . join(', ', array_keys($invalid)));
|
||||||
throw new DomainException('Invalid curl options: ' . join(', ', array_keys($invalid)));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($method, [static::GET, static::POST, static::PUT]))
|
if (!in_array($method, [static::GET, static::POST, static::PUT])) {
|
||||||
{
|
throw new DomainException('Invalid method: ' . $method);
|
||||||
throw new DomainException('Invalid method: ' . $method);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$options = array_merge($defaults, $options);
|
$options = array_merge($defaults, $options);
|
||||||
|
|
||||||
if ($options['headers'] && $options['headers'] !== array_values($options['headers'])) // associative array
|
if ($options['headers'] && $options['headers'] !== array_values($options['headers'])) { // associative array
|
||||||
{
|
throw new DomainException('Headers must not be an associative array. Its a simple array with values of the form "Header: value"');
|
||||||
throw new DomainException('Headers must not be an associative array. Its a simple array with values of the form "Header: value"');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
|
curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
|
||||||
|
|
||||||
if ($ch === false || $ch === null)
|
if ($ch === false || $ch === null) {
|
||||||
{
|
throw new LogicException('Unable to initialize cURL');
|
||||||
throw new LogicException('Unable to initialize cURL');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$urlWithParams = $url;
|
$urlWithParams = $url;
|
||||||
if ($method == static::GET && $params)
|
if ($method == static::GET && $params) {
|
||||||
{
|
$urlWithParams .= (strpos($urlWithParams, '?') === false ? '?' : '&') . http_build_query($params);
|
||||||
$urlWithParams .= (strpos($urlWithParams, '?') === false ? '?' : '&') . http_build_query($params);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_URL => $urlWithParams,
|
CURLOPT_URL => $urlWithParams,
|
||||||
CURLOPT_HTTPHEADER => $options['headers'],
|
CURLOPT_HTTPHEADER => $options['headers'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
@ -96,97 +91,82 @@ class Curl
|
||||||
CURLOPT_USERAGENT => $options['user_agent'],
|
CURLOPT_USERAGENT => $options['user_agent'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($method == static::POST)
|
if ($method == static::POST) {
|
||||||
{
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
} elseif ($method == static::PUT) {
|
||||||
}
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||||
elseif ($method == static::PUT)
|
}
|
||||||
{
|
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($method, [static::PUT, static::POST]))
|
if (in_array($method, [static::PUT, static::POST])) {
|
||||||
{
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $options['json_data'] ? json_encode($params) : http_build_query($params));
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $options['json_data'] ? json_encode($params) : http_build_query($params));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($options['proxy'])
|
if ($options['proxy']) {
|
||||||
{
|
curl_setopt($ch, CURLOPT_PROXY, $options['proxy']);
|
||||||
curl_setopt($ch, CURLOPT_PROXY, $options['proxy']);
|
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
||||||
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($options['password'])
|
if ($options['password']) {
|
||||||
{
|
curl_setopt($ch, CURLOPT_USERPWD, $options['password']);
|
||||||
curl_setopt($ch, CURLOPT_USERPWD, $options['password']);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($options['cookie'])
|
if ($options['cookie']) {
|
||||||
{
|
curl_setopt($ch, CURLOPT_COOKIE, $options['cookie']);
|
||||||
curl_setopt($ch, CURLOPT_COOKIE, $options['cookie']);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$startingResponse = false;
|
|
||||||
$headers = [];
|
|
||||||
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $h) use (&$headers, &$startingResponse)
|
|
||||||
{
|
|
||||||
$value = trim($h);
|
|
||||||
if ($value === '')
|
|
||||||
{
|
|
||||||
$startingResponse = true;
|
|
||||||
}
|
|
||||||
elseif ($startingResponse)
|
|
||||||
{
|
|
||||||
$startingResponse = false;
|
$startingResponse = false;
|
||||||
$headers = [$value];
|
$headers = [];
|
||||||
}
|
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $h) use (&$headers, &$startingResponse) {
|
||||||
else
|
$value = trim($h);
|
||||||
{
|
if ($value === '') {
|
||||||
$headers[] = $value;
|
$startingResponse = true;
|
||||||
}
|
} elseif ($startingResponse) {
|
||||||
return strlen($h);
|
$startingResponse = false;
|
||||||
});
|
$headers = [$value];
|
||||||
|
} else {
|
||||||
|
$headers[] = $value;
|
||||||
|
}
|
||||||
|
return strlen($h);
|
||||||
|
});
|
||||||
|
|
||||||
$rawResponse = curl_exec($ch);
|
$rawResponse = curl_exec($ch);
|
||||||
|
|
||||||
if ($options['json_response'])
|
if ($options['json_response']) {
|
||||||
{
|
$responseContent = $rawResponse ? json_decode($rawResponse, true) : [];
|
||||||
$responseContent = $rawResponse ? json_decode($rawResponse, true) : [];
|
} else {
|
||||||
|
$responseContent = $rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
if ($options['retry'] && is_numeric($options['retry']) && $options['retry'] > 0) {
|
||||||
|
$options['retry'] -= 1;
|
||||||
|
return static::doCurl($method, $url, $params, $options);
|
||||||
|
}
|
||||||
|
throw new CurlException($ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
return [$statusCode, $headers, $responseContent];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
$responseContent = $rawResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
$statusCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
|
|
||||||
if (curl_errno($ch))
|
|
||||||
{
|
|
||||||
if ($options['retry'] && is_numeric($options['retry']) && $options['retry'] > 0)
|
|
||||||
{
|
|
||||||
$options['retry'] -= 1;
|
|
||||||
return static::doCurl($method, $url, $params, $options);
|
|
||||||
}
|
|
||||||
throw new CurlException($ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
return [$statusCode, $headers, $responseContent];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CurlException extends Exception
|
class CurlException extends Exception
|
||||||
{
|
{
|
||||||
protected $errno, $error, $info, $handle;
|
protected $errno;
|
||||||
|
protected $error;
|
||||||
|
protected $info;
|
||||||
|
protected $handle;
|
||||||
|
|
||||||
public function __construct($curlHandle, Exception $previous = null)
|
public function __construct($curlHandle, Exception $previous = null)
|
||||||
{
|
{
|
||||||
$this->handle = $curlHandle;
|
$this->handle = $curlHandle;
|
||||||
$this->errno = curl_errno($curlHandle);
|
$this->errno = curl_errno($curlHandle);
|
||||||
$this->error = curl_error($curlHandle);
|
$this->error = curl_error($curlHandle);
|
||||||
$this->info = curl_getinfo($curlHandle);
|
$this->info = curl_getinfo($curlHandle);
|
||||||
|
|
||||||
parent::__construct($this->error, $this->errno, $previous);
|
parent::__construct($this->error, $this->errno, $previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,40 +2,34 @@
|
||||||
|
|
||||||
class CurlWithCache extends Curl
|
class CurlWithCache extends Curl
|
||||||
{
|
{
|
||||||
const DEFAULT_CACHE = 600000;
|
const DEFAULT_CACHE = 600000;
|
||||||
|
|
||||||
public static function doCurl($method, $url, $params = [], $options = [])
|
public static function doCurl($method, $url, $params = [], $options = [])
|
||||||
{
|
|
||||||
$cacheAllowed = $options['cache'] ?? true;
|
|
||||||
$cacheEnabled = Apc::isEnabled();
|
|
||||||
|
|
||||||
$cacheTimeout = is_numeric($options['cache'] ?? null) ? $options['cache'] : static::DEFAULT_CACHE;
|
|
||||||
unset($options['cache']);
|
|
||||||
|
|
||||||
$cacheKey = $cacheEnabled ? md5($url . $method . serialize($options) . serialize($params)) : null;
|
|
||||||
if ($cacheAllowed && $cacheKey)
|
|
||||||
{
|
{
|
||||||
$cachedData = apc_fetch($cacheKey);
|
$cacheAllowed = $options['cache'] ?? true;
|
||||||
if ($cachedData)
|
$cacheEnabled = Apc::isEnabled();
|
||||||
{
|
|
||||||
return $cachedData;
|
$cacheTimeout = is_numeric($options['cache'] ?? null) ? $options['cache'] : static::DEFAULT_CACHE;
|
||||||
}
|
unset($options['cache']);
|
||||||
|
|
||||||
|
$cacheKey = $cacheEnabled ? md5($url . $method . serialize($options) . serialize($params)) : null;
|
||||||
|
if ($cacheAllowed && $cacheKey) {
|
||||||
|
$cachedData = apc_fetch($cacheKey);
|
||||||
|
if ($cachedData) {
|
||||||
|
return $cachedData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = parent::doCurl($method, $url, $params, $options);
|
||||||
|
|
||||||
|
if ($cacheEnabled) {
|
||||||
|
if ($cacheAllowed) {
|
||||||
|
apc_store($cacheKey, $response, $cacheTimeout);
|
||||||
|
} else {
|
||||||
|
apc_delete($cacheKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$response = parent::doCurl($method, $url, $params, $options);
|
|
||||||
|
|
||||||
if ($cacheEnabled)
|
|
||||||
{
|
|
||||||
if ($cacheAllowed)
|
|
||||||
{
|
|
||||||
apc_store($cacheKey, $response, $cacheTimeout);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
apc_delete($cacheKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,74 +2,61 @@
|
||||||
|
|
||||||
class Debug
|
class Debug
|
||||||
{
|
{
|
||||||
public static function exceptionToString(Throwable $e)
|
public static function exceptionToString(Throwable $e)
|
||||||
{
|
|
||||||
return static::getExceptionMessageWithoutTrace($e) . "\n" . static::getFullTrace($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getExceptionMessageWithoutTrace(Throwable $e)
|
|
||||||
{
|
|
||||||
return 'exception \'' . get_class($e) . '\' with message \'' . $e->getMessage() . '\' in ' . $e->getFile() . ':' . $e->getLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as the normal getTraceAsString(), but does not truncate long lines.
|
|
||||||
* @param Throwable $exception
|
|
||||||
* @return string
|
|
||||||
* @see http://stackoverflow.com/questions/1949345/how-can-i-get-the-full-string-of-phps-gettraceasstring/6076667#6076667
|
|
||||||
* @see https://gist.github.com/1437966
|
|
||||||
*/
|
|
||||||
public static function getFullTrace(Throwable $exception)
|
|
||||||
{
|
|
||||||
$rtn = '';
|
|
||||||
foreach ($exception->getTrace() as $count => $frame)
|
|
||||||
{
|
{
|
||||||
$args = isset($frame['args']) ? static::exceptionFrameArgsToString($frame['args']) : '';
|
return static::getExceptionMessageWithoutTrace($e) . "\n" . static::getFullTrace($e);
|
||||||
|
}
|
||||||
|
|
||||||
$rtn .= sprintf("#%s %s(%s): %s(%s)\n",
|
public static function getExceptionMessageWithoutTrace(Throwable $e)
|
||||||
|
{
|
||||||
|
return 'exception \'' . get_class($e) . '\' with message \'' . $e->getMessage() . '\' in ' . $e->getFile() . ':' . $e->getLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as the normal getTraceAsString(), but does not truncate long lines.
|
||||||
|
* @param Throwable $exception
|
||||||
|
* @return string
|
||||||
|
* @see http://stackoverflow.com/questions/1949345/how-can-i-get-the-full-string-of-phps-gettraceasstring/6076667#6076667
|
||||||
|
* @see https://gist.github.com/1437966
|
||||||
|
*/
|
||||||
|
public static function getFullTrace(Throwable $exception)
|
||||||
|
{
|
||||||
|
$rtn = '';
|
||||||
|
foreach ($exception->getTrace() as $count => $frame) {
|
||||||
|
$args = isset($frame['args']) ? static::exceptionFrameArgsToString($frame['args']) : '';
|
||||||
|
|
||||||
|
$rtn .= sprintf(
|
||||||
|
"#%s %s(%s): %s(%s)\n",
|
||||||
$count,
|
$count,
|
||||||
$frame['file'] ?? 'unknown file',
|
$frame['file'] ?? 'unknown file',
|
||||||
$frame['line'] ?? 'unknown line',
|
$frame['line'] ?? 'unknown line',
|
||||||
isset($frame['class']) ? $frame['class'].$frame['type'].$frame['function'] : $frame['function'],
|
isset($frame['class']) ? $frame['class'].$frame['type'].$frame['function'] : $frame['function'],
|
||||||
$args);
|
$args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $rtn;
|
||||||
}
|
}
|
||||||
return $rtn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function exceptionFrameArgsToString(array $args)
|
public static function exceptionFrameArgsToString(array $args)
|
||||||
{
|
|
||||||
$ret = [];
|
|
||||||
foreach ($args as $arg)
|
|
||||||
{
|
{
|
||||||
if (is_string($arg))
|
$ret = [];
|
||||||
{
|
foreach ($args as $arg) {
|
||||||
$ret[] = "'" . $arg . "'";
|
if (is_string($arg)) {
|
||||||
}
|
$ret[] = "'" . $arg . "'";
|
||||||
elseif (is_array($arg))
|
} elseif (is_array($arg)) {
|
||||||
{
|
$ret[] = 'Array(' . count($arg) . ')';
|
||||||
$ret[] = 'Array(' . count($arg) . ')';
|
} elseif (is_null($arg)) {
|
||||||
}
|
$ret[] = 'NULL';
|
||||||
elseif (is_null($arg))
|
} elseif (is_bool($arg)) {
|
||||||
{
|
$ret[] = ($arg) ? 'true' : 'false';
|
||||||
$ret[] = 'NULL';
|
} elseif (is_object($arg)) {
|
||||||
}
|
$ret[] = get_class($arg) . (!($arg instanceof Closure) && isset($arg->id) ? "({$arg->id})" : '');
|
||||||
elseif (is_bool($arg))
|
} elseif (is_resource($arg)) {
|
||||||
{
|
$ret[] = get_resource_type($arg);
|
||||||
$ret[] = ($arg) ? 'true' : 'false';
|
} else {
|
||||||
}
|
$ret[] = $arg;
|
||||||
elseif (is_object($arg))
|
}
|
||||||
{
|
}
|
||||||
$ret[] = get_class($arg) . (!($arg instanceof Closure) && isset($arg->id) ? "({$arg->id})" : '');
|
return join(', ', $ret);
|
||||||
}
|
|
||||||
elseif (is_resource($arg))
|
|
||||||
{
|
|
||||||
$ret[] = get_resource_type($arg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$ret[] = $arg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return join(', ', $ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,63 +2,58 @@
|
||||||
|
|
||||||
class Encoding
|
class Encoding
|
||||||
{
|
{
|
||||||
public static function base64EncodeUrlsafe($data)
|
public static function base64EncodeUrlsafe($data)
|
||||||
{
|
|
||||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); // equals sign is just for padding, can be safely removed
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function base64DecodeUrlsafe($data)
|
|
||||||
{
|
|
||||||
return base64_decode(strtr($data, '-_', '+/')); // dont worry about replacing equals sign
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function base58Encode($byteString)
|
|
||||||
{
|
|
||||||
$alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
|
|
||||||
return static::convertBase($byteString, join('', array_map('chr', range(0, 255))), $alphabet);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function convertBase($numberInput, $sourceAlphabet, $targetAlphabet)
|
|
||||||
{
|
|
||||||
if ($sourceAlphabet == $targetAlphabet)
|
|
||||||
{
|
{
|
||||||
return $numberInput;
|
return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); // equals sign is just for padding, can be safely removed
|
||||||
}
|
}
|
||||||
|
|
||||||
$decimalAlphabet = '0123456789';
|
public static function base64DecodeUrlsafe($data)
|
||||||
|
|
||||||
$fromBase = str_split($sourceAlphabet);
|
|
||||||
$toBase = str_split($targetAlphabet);
|
|
||||||
$number = str_split($numberInput);
|
|
||||||
|
|
||||||
$fromLen = strlen($sourceAlphabet);
|
|
||||||
$toLen = strlen($targetAlphabet);
|
|
||||||
$numberLen = strlen($numberInput);
|
|
||||||
|
|
||||||
if ($targetAlphabet == $decimalAlphabet)
|
|
||||||
{
|
{
|
||||||
$decimal = 0;
|
return base64_decode(strtr($data, '-_', '+/')); // dont worry about replacing equals sign
|
||||||
for ($i = 1; $i <= $numberLen; $i++)
|
|
||||||
{
|
|
||||||
$decimal = bcadd($decimal, bcmul(array_search($number[$i - 1], $fromBase), bcpow($fromLen, $numberLen - $i)));
|
|
||||||
}
|
|
||||||
return $decimal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$base10 = $sourceAlphabet == $decimalAlphabet ? $numberInput : static::convertBase($numberInput, $sourceAlphabet, $decimalAlphabet);
|
public static function base58Encode($byteString)
|
||||||
|
|
||||||
if ($base10 < strlen($targetAlphabet))
|
|
||||||
{
|
{
|
||||||
return $toBase[$base10];
|
$alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
|
||||||
|
return static::convertBase($byteString, join('', array_map('chr', range(0, 255))), $alphabet);
|
||||||
}
|
}
|
||||||
|
|
||||||
$retval = '';
|
protected static function convertBase($numberInput, $sourceAlphabet, $targetAlphabet)
|
||||||
while ($base10 != '0')
|
|
||||||
{
|
{
|
||||||
$retval = $toBase[bcmod($base10, $toLen)] . $retval;
|
if ($sourceAlphabet == $targetAlphabet) {
|
||||||
$base10 = bcdiv($base10, $toLen, 0);
|
return $numberInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $retval;
|
$decimalAlphabet = '0123456789';
|
||||||
}
|
|
||||||
}
|
$fromBase = str_split($sourceAlphabet);
|
||||||
|
$toBase = str_split($targetAlphabet);
|
||||||
|
$number = str_split($numberInput);
|
||||||
|
|
||||||
|
$fromLen = strlen($sourceAlphabet);
|
||||||
|
$toLen = strlen($targetAlphabet);
|
||||||
|
$numberLen = strlen($numberInput);
|
||||||
|
|
||||||
|
if ($targetAlphabet == $decimalAlphabet) {
|
||||||
|
$decimal = 0;
|
||||||
|
for ($i = 1; $i <= $numberLen; $i++) {
|
||||||
|
$decimal = bcadd($decimal, bcmul(array_search($number[$i - 1], $fromBase), bcpow($fromLen, $numberLen - $i)));
|
||||||
|
}
|
||||||
|
return $decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base10 = $sourceAlphabet == $decimalAlphabet ? $numberInput : static::convertBase($numberInput, $sourceAlphabet, $decimalAlphabet);
|
||||||
|
|
||||||
|
if ($base10 < strlen($targetAlphabet)) {
|
||||||
|
return $toBase[$base10];
|
||||||
|
}
|
||||||
|
|
||||||
|
$retval = '';
|
||||||
|
while ($base10 != '0') {
|
||||||
|
$retval = $toBase[bcmod($base10, $toLen)] . $retval;
|
||||||
|
$base10 = bcdiv($base10, $toLen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,34 +2,29 @@
|
||||||
|
|
||||||
class Gzip
|
class Gzip
|
||||||
{
|
{
|
||||||
public static function compressFile($source, $level = 1)
|
public static function compressFile($source, $level = 1)
|
||||||
{
|
|
||||||
$compressedPath = $source . '.gz';
|
|
||||||
$mode = 'wb' . $level;
|
|
||||||
|
|
||||||
$fpOut = gzopen($compressedPath, $mode);
|
|
||||||
if (!$fpOut)
|
|
||||||
{
|
{
|
||||||
return false;
|
$compressedPath = $source . '.gz';
|
||||||
}
|
$mode = 'wb' . $level;
|
||||||
|
|
||||||
$fpIn = fopen($source, 'rb');
|
$fpOut = gzopen($compressedPath, $mode);
|
||||||
$error = false;
|
if (!$fpOut) {
|
||||||
if ($fpIn)
|
return false;
|
||||||
{
|
}
|
||||||
while (!feof($fpIn))
|
|
||||||
{
|
|
||||||
gzwrite($fpOut, fread($fpIn, 1024 * 512));
|
|
||||||
}
|
|
||||||
fclose($fpIn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
gzclose($fpOut);
|
$fpIn = fopen($source, 'rb');
|
||||||
|
$error = false;
|
||||||
|
if ($fpIn) {
|
||||||
|
while (!feof($fpIn)) {
|
||||||
|
gzwrite($fpOut, fread($fpIn, 1024 * 512));
|
||||||
|
}
|
||||||
|
fclose($fpIn);
|
||||||
|
} else {
|
||||||
|
$error = true;
|
||||||
|
}
|
||||||
|
|
||||||
return $error ? false : $compressedPath;
|
gzclose($fpOut);
|
||||||
}
|
|
||||||
}
|
return $error ? false : $compressedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,55 +16,50 @@ else {
|
||||||
|
|
||||||
class Lock
|
class Lock
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Creates a lockfile and acquires an exclusive lock on it.
|
* Creates a lockfile and acquires an exclusive lock on it.
|
||||||
*
|
*
|
||||||
* @param string $name The name of the lockfile.
|
* @param string $name The name of the lockfile.
|
||||||
* @param boolean $blocking Block until lock becomes available (default: don't block, just fail)
|
* @param boolean $blocking Block until lock becomes available (default: don't block, just fail)
|
||||||
* @return mixed Returns the lockfile, or FALSE if a lock could not be acquired.
|
* @return mixed Returns the lockfile, or FALSE if a lock could not be acquired.
|
||||||
*/
|
*/
|
||||||
public static function getLock($name, $blocking = false)
|
public static function getLock($name, $blocking = false)
|
||||||
{
|
|
||||||
if (!preg_match('/^[A-Za-z0-9\.\-_]+$/', $name))
|
|
||||||
{
|
{
|
||||||
throw new InvalidArgumentException('Invalid lock name: "' . $name . '"');
|
if (!preg_match('/^[A-Za-z0-9\.\-_]+$/', $name)) {
|
||||||
|
throw new InvalidArgumentException('Invalid lock name: "' . $name . '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = static::getLockDir() . '/' . $name;
|
||||||
|
if (!preg_match('/\.lo?ck$/', $filename)) {
|
||||||
|
$filename .= '.lck';
|
||||||
|
}
|
||||||
|
if (!file_exists($filename)) {
|
||||||
|
file_put_contents($filename, '');
|
||||||
|
chmod($filename, 0666); // if the file cant be opened for writing later, getting the lock will fail
|
||||||
|
}
|
||||||
|
$lockFile = fopen($filename, 'w+');
|
||||||
|
if (!flock($lockFile, $blocking ? LOCK_EX : LOCK_EX|LOCK_NB)) {
|
||||||
|
fclose($lockFile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $lockFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = static::getLockDir() . '/' . $name;
|
/**
|
||||||
if (!preg_match('/\.lo?ck$/', $filename))
|
* Free a lock.
|
||||||
|
*
|
||||||
|
* @param resource $lockFile
|
||||||
|
*/
|
||||||
|
public static function freeLock($lockFile)
|
||||||
{
|
{
|
||||||
$filename .= '.lck';
|
if ($lockFile) {
|
||||||
|
flock($lockFile, LOCK_UN);
|
||||||
|
fclose($lockFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!file_exists($filename))
|
|
||||||
{
|
|
||||||
file_put_contents($filename, '');
|
|
||||||
chmod($filename, 0666); // if the file cant be opened for writing later, getting the lock will fail
|
|
||||||
}
|
|
||||||
$lockFile = fopen($filename, 'w+');
|
|
||||||
if (!flock($lockFile, $blocking ? LOCK_EX : LOCK_EX|LOCK_NB))
|
|
||||||
{
|
|
||||||
fclose($lockFile);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return $lockFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static function getLockDir()
|
||||||
* Free a lock.
|
|
||||||
*
|
|
||||||
* @param resource $lockFile
|
|
||||||
*/
|
|
||||||
public static function freeLock($lockFile)
|
|
||||||
{
|
|
||||||
if ($lockFile)
|
|
||||||
{
|
{
|
||||||
flock($lockFile, LOCK_UN);
|
return sys_get_temp_dir();
|
||||||
fclose($lockFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getLockDir()
|
|
||||||
{
|
|
||||||
return sys_get_temp_dir();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,32 +2,31 @@
|
||||||
|
|
||||||
class OS
|
class OS
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* if changing below constants, you should add permanent redirects for old OS names used in URLs
|
* if changing below constants, you should add permanent redirects for old OS names used in URLs
|
||||||
*/
|
*/
|
||||||
const OS_ANDROID = 'android',
|
const OS_ANDROID = 'android',
|
||||||
OS_IOS = 'ios',
|
OS_IOS = 'ios',
|
||||||
OS_LINUX = 'linux',
|
OS_LINUX = 'linux',
|
||||||
OS_OSX = 'osx',
|
OS_OSX = 'osx',
|
||||||
OS_WINDOWS = 'windows';
|
OS_WINDOWS = 'windows';
|
||||||
|
|
||||||
public static function getAll()
|
public static function getAll()
|
||||||
{
|
{
|
||||||
//url, English name, icon class, partial name
|
//url, English name, icon class, partial name
|
||||||
//yes, this is probably a bad pattern
|
//yes, this is probably a bad pattern
|
||||||
return [
|
return [
|
||||||
OS::OS_WINDOWS => ['/windows', 'Windows', 'icon-windows', __("Download for Windows"), "Windows"],
|
OS::OS_WINDOWS => ['/windows', 'Windows', 'icon-windows', __("Download for Windows"), "Windows"],
|
||||||
OS::OS_OSX => ['/osx', 'macOS', 'icon-apple', __("Download for macOS"), "OSX"],
|
OS::OS_OSX => ['/osx', 'macOS', 'icon-apple', __("Download for macOS"), "OSX"],
|
||||||
OS::OS_LINUX => ['/linux', 'Linux', 'icon-linux', __("Download .deb"), "Linux"],
|
OS::OS_LINUX => ['/linux', 'Linux', 'icon-linux', __("Download .deb"), "Linux"],
|
||||||
OS::OS_ANDROID => ['/android', 'Android', 'icon-android', false, false],
|
OS::OS_ANDROID => ['/android', 'Android', 'icon-android', false, false],
|
||||||
OS::OS_IOS => ['/ios', 'iOS', 'icon-mobile', false, false]
|
OS::OS_IOS => ['/ios', 'iOS', 'icon-mobile', false, false]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getOsForExtension($ext)
|
public static function getOsForExtension($ext)
|
||||||
{
|
|
||||||
switch ($ext)
|
|
||||||
{
|
{
|
||||||
|
switch ($ext) {
|
||||||
case 'deb':
|
case 'deb':
|
||||||
return OS::OS_LINUX;
|
return OS::OS_LINUX;
|
||||||
|
|
||||||
|
@ -42,5 +41,5 @@ class OS
|
||||||
default:
|
default:
|
||||||
throw new LogicException("Unknown ext $ext");
|
throw new LogicException("Unknown ext $ext");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,140 +14,121 @@
|
||||||
*/
|
*/
|
||||||
class Shell
|
class Shell
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Execute a command. Returns the command's exit code, output, and error output.
|
* Execute a command. Returns the command's exit code, output, and error output.
|
||||||
*
|
*
|
||||||
* @param string $cmd The command to execute
|
* @param string $cmd The command to execute
|
||||||
* @param array $options Available options:
|
* @param array $options Available options:
|
||||||
* - echo (bool) - If true, print the command's output/error to stdout/stderr of this process
|
* - echo (bool) - If true, print the command's output/error to stdout/stderr of this process
|
||||||
* - echo_errors (bool) - If you want to control printing to stderr separately, use this. If not provided, will
|
* - echo_errors (bool) - If you want to control printing to stderr separately, use this. If not provided, will
|
||||||
* default to the value of 'echo'
|
* default to the value of 'echo'
|
||||||
* - live_callback (callable) - Will be called as soon as data is read. Use this for custom handling
|
* - live_callback (callable) - Will be called as soon as data is read. Use this for custom handling
|
||||||
* of live output. Callable signature: fn(string $text, bool $isError)
|
* of live output. Callable signature: fn(string $text, bool $isError)
|
||||||
*
|
*
|
||||||
* @return array [exit code, output, errorOutput]
|
* @return array [exit code, output, errorOutput]
|
||||||
*/
|
*/
|
||||||
public static function exec($cmd, array $options = [])
|
public static function exec($cmd, array $options = [])
|
||||||
{
|
{
|
||||||
$options = array_merge([
|
$options = array_merge([
|
||||||
'echo' => false,
|
'echo' => false,
|
||||||
'echo_errors' => null,
|
'echo_errors' => null,
|
||||||
'live_callback' => null,
|
'live_callback' => null,
|
||||||
], $options);
|
], $options);
|
||||||
|
|
||||||
if ($options['echo_errors'] === null)
|
if ($options['echo_errors'] === null) {
|
||||||
{
|
$options['echo_errors'] = $options['echo'];
|
||||||
$options['echo_errors'] = $options['echo'];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($options['live_callback'] && !is_callable($options['live_callback']))
|
if ($options['live_callback'] && !is_callable($options['live_callback'])) {
|
||||||
{
|
throw new InvalidArgumentException('live_callback option must be a valid callback');
|
||||||
throw new InvalidArgumentException('live_callback option must be a valid callback');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$descriptorSpec = [
|
$descriptorSpec = [
|
||||||
1 => ['pipe', 'w'], // stdout
|
1 => ['pipe', 'w'], // stdout
|
||||||
2 => ['pipe', 'w'], // stderr
|
2 => ['pipe', 'w'], // stderr
|
||||||
];
|
];
|
||||||
|
|
||||||
$process = proc_open($cmd, $descriptorSpec, $pipes);
|
$process = proc_open($cmd, $descriptorSpec, $pipes);
|
||||||
if (!is_resource($process))
|
if (!is_resource($process)) {
|
||||||
{
|
throw new RuntimeException('proc_open failed');
|
||||||
throw new RuntimeException('proc_open failed');
|
}
|
||||||
|
|
||||||
|
stream_set_blocking($pipes[1], false);
|
||||||
|
stream_set_blocking($pipes[2], false);
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
$err = '';
|
||||||
|
|
||||||
|
while (!feof($pipes[1]) || !feof($pipes[2])) {
|
||||||
|
foreach ($pipes as $key => $pipe) {
|
||||||
|
$data = fread($pipe, 1024);
|
||||||
|
if (!$data) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == $key) {
|
||||||
|
$output .= $data;
|
||||||
|
if ($options['echo']) {
|
||||||
|
fprintf(STDOUT, "%s", $data);
|
||||||
|
}
|
||||||
|
if ($options['live_callback']) {
|
||||||
|
call_user_func($options['live_callback'], $data, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err .= $data;
|
||||||
|
if ($options['echo_errors']) {
|
||||||
|
fprintf(STDERR, "%s", $data);
|
||||||
|
}
|
||||||
|
if ($options['live_callback']) {
|
||||||
|
call_user_func($options['live_callback'], $data, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($pipes[1]);
|
||||||
|
fclose($pipes[2]);
|
||||||
|
|
||||||
|
$exitCode = proc_close($process);
|
||||||
|
|
||||||
|
return [$exitCode, $output, $err];
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_set_blocking($pipes[1], false);
|
/**
|
||||||
stream_set_blocking($pipes[2], false);
|
* Convenience method to build a command to execute. Will escape everything as necessary.
|
||||||
|
*
|
||||||
$output = '';
|
* @param string $executable The path to the executable
|
||||||
$err = '';
|
* @param array $arguments An array of arguments
|
||||||
|
* @param array $options An associative array of flags in the form flagName => flagValue.
|
||||||
while (!feof($pipes[1]) || !feof($pipes[2]))
|
* Short and long flags are supported.
|
||||||
|
* If flagValue === true, the flag have no value.
|
||||||
|
* If flagValue === false, the flag will be skipped.
|
||||||
|
*
|
||||||
|
* @return string An executable command
|
||||||
|
*/
|
||||||
|
public static function buildCmd($executable, array $arguments = [], array $options = [])
|
||||||
{
|
{
|
||||||
foreach ($pipes as $key => $pipe)
|
$shellArgs = [];
|
||||||
{
|
|
||||||
$data = fread($pipe, 1024);
|
foreach ($options as $key => $value) {
|
||||||
if (!$data)
|
if ($value === false) {
|
||||||
{
|
continue;
|
||||||
continue;
|
}
|
||||||
|
|
||||||
|
if (strlen($key) === 1) {
|
||||||
|
$shellArgs[] = '-'.$key;
|
||||||
|
if ($value !== true) {
|
||||||
|
$shellArgs[] = $value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$shellArgs[] = '--' . $key . ($value !== true ? '=' . $value : '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1 == $key)
|
$shellArgs = array_merge($shellArgs, array_values($arguments));
|
||||||
{
|
|
||||||
$output .= $data;
|
|
||||||
if ($options['echo'])
|
|
||||||
{
|
|
||||||
fprintf(STDOUT, "%s", $data);
|
|
||||||
}
|
|
||||||
if ($options['live_callback'])
|
|
||||||
{
|
|
||||||
call_user_func($options['live_callback'], $data, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$err .= $data;
|
|
||||||
if ($options['echo_errors'])
|
|
||||||
{
|
|
||||||
fprintf(STDERR, "%s", $data);
|
|
||||||
}
|
|
||||||
if ($options['live_callback'])
|
|
||||||
{
|
|
||||||
call_user_func($options['live_callback'], $data, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(100000);
|
return $executable . ' ' . join(' ', array_map('escapeshellarg', $shellArgs));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fclose($pipes[1]);
|
|
||||||
fclose($pipes[2]);
|
|
||||||
|
|
||||||
$exitCode = proc_close($process);
|
|
||||||
|
|
||||||
return [$exitCode, $output, $err];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to build a command to execute. Will escape everything as necessary.
|
|
||||||
*
|
|
||||||
* @param string $executable The path to the executable
|
|
||||||
* @param array $arguments An array of arguments
|
|
||||||
* @param array $options An associative array of flags in the form flagName => flagValue.
|
|
||||||
* Short and long flags are supported.
|
|
||||||
* If flagValue === true, the flag have no value.
|
|
||||||
* If flagValue === false, the flag will be skipped.
|
|
||||||
*
|
|
||||||
* @return string An executable command
|
|
||||||
*/
|
|
||||||
public static function buildCmd($executable, array $arguments = [], array $options = [])
|
|
||||||
{
|
|
||||||
$shellArgs = [];
|
|
||||||
|
|
||||||
foreach ($options as $key => $value)
|
|
||||||
{
|
|
||||||
if ($value === false)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($key) === 1)
|
|
||||||
{
|
|
||||||
$shellArgs[] = '-'.$key;
|
|
||||||
if ($value !== true)
|
|
||||||
{
|
|
||||||
$shellArgs[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$shellArgs[] = '--' . $key . ($value !== true ? '=' . $value : '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$shellArgs = array_merge($shellArgs, array_values($arguments));
|
|
||||||
|
|
||||||
return $executable . ' ' . join(' ', array_map('escapeshellarg', $shellArgs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
*/
|
*/
|
||||||
class Smaz
|
class Smaz
|
||||||
{
|
{
|
||||||
const CODEBOOK_DEFAULT = 'default';
|
const CODEBOOK_DEFAULT = 'default';
|
||||||
const CODEBOOK_EMAIL = 'email';
|
const CODEBOOK_EMAIL = 'email';
|
||||||
|
|
||||||
const VERBATIM_CHAR = 254;
|
const VERBATIM_CHAR = 254;
|
||||||
const VERBATIM_STR = 255;
|
const VERBATIM_STR = 255;
|
||||||
|
|
||||||
protected static $encodeBooks = [];
|
protected static $encodeBooks = [];
|
||||||
protected static $decodeBooks = [
|
protected static $decodeBooks = [
|
||||||
self::CODEBOOK_DEFAULT => [
|
self::CODEBOOK_DEFAULT => [
|
||||||
" ", "the", "e", "t", "a", "of", "o", "and", "i", "n", "s", "e ", "r", " th",
|
" ", "the", "e", "t", "a", "of", "o", "and", "i", "n", "s", "e ", "r", " th",
|
||||||
" t", "in", "he", "th", "h", "he ", "to", "\r\n", "l", "s ", "d", " a", "an",
|
" t", "in", "he", "th", "h", "he ", "to", "\r\n", "l", "s ", "d", " a", "an",
|
||||||
|
@ -67,145 +67,123 @@ class Smaz
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
protected static function getEncodeBook($codebook)
|
protected static function getEncodeBook($codebook)
|
||||||
{
|
|
||||||
if (!isset(static::$encodeBooks[$codebook]))
|
|
||||||
{
|
{
|
||||||
static::$encodeBooks[$codebook] = array_flip(static::getDecodeBook($codebook));
|
if (!isset(static::$encodeBooks[$codebook])) {
|
||||||
|
static::$encodeBooks[$codebook] = array_flip(static::getDecodeBook($codebook));
|
||||||
|
}
|
||||||
|
return static::$encodeBooks[$codebook];
|
||||||
}
|
}
|
||||||
return static::$encodeBooks[$codebook];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getDecodeBook($codebook)
|
protected static function getDecodeBook($codebook)
|
||||||
{
|
|
||||||
if (!static::$decodeBooks[$codebook])
|
|
||||||
{
|
{
|
||||||
throw new Exception('decodebook ' . $codebook . ' does not exist');
|
if (!static::$decodeBooks[$codebook]) {
|
||||||
|
throw new Exception('decodebook ' . $codebook . ' does not exist');
|
||||||
|
}
|
||||||
|
if (count(static::$decodeBooks[$codebook]) > static::VERBATIM_CHAR) {
|
||||||
|
throw new Exception('decodebook ' . $codebook . ' must be at most ' . static::VERBATIM_CHAR . 'entries');
|
||||||
|
}
|
||||||
|
return static::$decodeBooks[$codebook];
|
||||||
}
|
}
|
||||||
if (count(static::$decodeBooks[$codebook]) > static::VERBATIM_CHAR)
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $str
|
||||||
|
* @param string $codebook
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function encode($str, $codebook = self::CODEBOOK_DEFAULT)
|
||||||
{
|
{
|
||||||
throw new Exception('decodebook ' . $codebook . ' must be at most ' . static::VERBATIM_CHAR . 'entries');
|
$encodeBook = static::getEncodeBook($codebook);
|
||||||
}
|
|
||||||
return static::$decodeBooks[$codebook];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$inLen = strlen($str);
|
||||||
|
$inIdx = 0;
|
||||||
|
$output = '';
|
||||||
|
$verbatim = '';
|
||||||
|
$maxItemLen = max(array_map('strlen', array_keys($encodeBook)));
|
||||||
|
|
||||||
/**
|
while ($inIdx < $inLen) {
|
||||||
* @param string $str
|
$encode = false;
|
||||||
* @param string $codebook
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function encode($str, $codebook = self::CODEBOOK_DEFAULT)
|
|
||||||
{
|
|
||||||
$encodeBook = static::getEncodeBook($codebook);
|
|
||||||
|
|
||||||
$inLen = strlen($str);
|
for ($j = min($maxItemLen, $inLen - $inIdx); $j > 0; $j--) {
|
||||||
$inIdx = 0;
|
$code = isset($encodeBook[substr($str, $inIdx, $j)]) ? $encodeBook[substr($str, $inIdx, $j)] : null;
|
||||||
$output = '';
|
if ($code !== null) {
|
||||||
$verbatim = '';
|
|
||||||
$maxItemLen = max(array_map('strlen', array_keys($encodeBook)));
|
|
||||||
|
|
||||||
while ($inIdx < $inLen)
|
|
||||||
{
|
|
||||||
$encode = false;
|
|
||||||
|
|
||||||
for ($j = min($maxItemLen, $inLen - $inIdx); $j > 0; $j--)
|
|
||||||
{
|
|
||||||
$code = isset($encodeBook[substr($str, $inIdx, $j)]) ? $encodeBook[substr($str, $inIdx, $j)] : null;
|
|
||||||
if ($code !== null)
|
|
||||||
{
|
|
||||||
// echo substr($str, $inIdx, $j) . " = $code\n";
|
// echo substr($str, $inIdx, $j) . " = $code\n";
|
||||||
if (strlen($verbatim))
|
if (strlen($verbatim)) {
|
||||||
{
|
$output .= static::flushVerbatim($verbatim);
|
||||||
$output .= static::flushVerbatim($verbatim);
|
$verbatim = '';
|
||||||
$verbatim = '';
|
}
|
||||||
}
|
$output .= chr($code);
|
||||||
$output .= chr($code);
|
$inIdx += $j;
|
||||||
$inIdx += $j;
|
$encode = true;
|
||||||
$encode = true;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!$encode)
|
if (!$encode) {
|
||||||
{
|
|
||||||
// echo "VERBATIM\n";
|
// echo "VERBATIM\n";
|
||||||
$verbatim .= $str[$inIdx];
|
$verbatim .= $str[$inIdx];
|
||||||
$inIdx++;
|
$inIdx++;
|
||||||
if (strlen($verbatim) == 255) // any longer, and we can't represent the length as a single char
|
if (strlen($verbatim) == 255) { // any longer, and we can't represent the length as a single char
|
||||||
{
|
$output .= static::flushVerbatim($verbatim);
|
||||||
$output .= static::flushVerbatim($verbatim);
|
$verbatim = '';
|
||||||
$verbatim = '';
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (strlen($verbatim)) {
|
||||||
|
$output .= static::flushVerbatim($verbatim);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($verbatim))
|
/**
|
||||||
|
* @param string $str
|
||||||
|
* @param string $codebook
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function decode($str, $codebook = self::CODEBOOK_DEFAULT)
|
||||||
{
|
{
|
||||||
$output .= static::flushVerbatim($verbatim);
|
$decodeBook = static::getDecodeBook($codebook);
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
while ($i < strlen($str)) {
|
||||||
|
$code = ord($str[$i]);
|
||||||
|
if ($code == static::VERBATIM_CHAR) {
|
||||||
|
$output .= $str[$i + 1];
|
||||||
|
$i += 2;
|
||||||
|
} elseif ($code == static::VERBATIM_STR) {
|
||||||
|
$len = ord($str[$i + 1]);
|
||||||
|
$output .= substr($str, $i + 2, $len);
|
||||||
|
$i += 2 + $len;
|
||||||
|
} elseif (!isset($decodeBook[$code])) {
|
||||||
|
return null; // decode error. throw exception?
|
||||||
|
} else {
|
||||||
|
$output .= $decodeBook[$code];
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
protected static function flushVerbatim($verbatim)
|
||||||
* @param string $str
|
|
||||||
* @param string $codebook
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function decode($str, $codebook = self::CODEBOOK_DEFAULT)
|
|
||||||
{
|
|
||||||
$decodeBook = static::getDecodeBook($codebook);
|
|
||||||
|
|
||||||
$output = '';
|
|
||||||
$i = 0;
|
|
||||||
|
|
||||||
while ($i < strlen($str))
|
|
||||||
{
|
{
|
||||||
$code = ord($str[$i]);
|
$output = '';
|
||||||
if ($code == static::VERBATIM_CHAR)
|
if (!strlen($verbatim)) {
|
||||||
{
|
return $output;
|
||||||
$output .= $str[$i + 1];
|
}
|
||||||
$i += 2;
|
|
||||||
}
|
|
||||||
elseif ($code == static::VERBATIM_STR)
|
|
||||||
{
|
|
||||||
$len = ord($str[$i + 1]);
|
|
||||||
$output .= substr($str, $i + 2, $len);
|
|
||||||
$i += 2 + $len;
|
|
||||||
}
|
|
||||||
elseif (!isset($decodeBook[$code]))
|
|
||||||
{
|
|
||||||
return null; // decode error. throw exception?
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$output .= $decodeBook[$code];
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function flushVerbatim($verbatim)
|
if (strlen($verbatim) > 1) {
|
||||||
{
|
$output .= chr(static::VERBATIM_STR);
|
||||||
$output = '';
|
$output .= chr(strlen($verbatim));
|
||||||
if (!strlen($verbatim))
|
} else {
|
||||||
{
|
$output .= chr(static::VERBATIM_CHAR);
|
||||||
return $output;
|
}
|
||||||
|
$output .= $verbatim;
|
||||||
|
return $output;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (strlen($verbatim) > 1)
|
|
||||||
{
|
|
||||||
$output .= chr(static::VERBATIM_STR);
|
|
||||||
$output .= chr(strlen($verbatim));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$output .= chr(static::VERBATIM_CHAR);
|
|
||||||
}
|
|
||||||
$output .= $verbatim;
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,312 +1,310 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class PostNotFoundException extends Exception {}
|
class PostNotFoundException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
class PostMalformedException extends Exception {}
|
class PostMalformedException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
class Post
|
class Post
|
||||||
{
|
{
|
||||||
const SORT_DATE_DESC = 'sort_date_desc',
|
const SORT_DATE_DESC = 'sort_date_desc',
|
||||||
SORT_ORD_ASC = 'sort_ord_asc';
|
SORT_ORD_ASC = 'sort_ord_asc';
|
||||||
|
|
||||||
protected static $slugMap = [];
|
protected static $slugMap = [];
|
||||||
protected $path, $slug, $title, $metadata, $author, $date, $markdown, $contentText, $contentHtml, $cover, $postType, $category;
|
protected $path;
|
||||||
protected $isCoverLight = false;
|
protected $slug;
|
||||||
|
protected $title;
|
||||||
|
protected $metadata;
|
||||||
|
protected $author;
|
||||||
|
protected $date;
|
||||||
|
protected $markdown;
|
||||||
|
protected $contentText;
|
||||||
|
protected $contentHtml;
|
||||||
|
protected $cover;
|
||||||
|
protected $postType;
|
||||||
|
protected $category;
|
||||||
|
protected $isCoverLight = false;
|
||||||
|
|
||||||
public static function load($relativeOrAbsolutePath)
|
public static function load($relativeOrAbsolutePath)
|
||||||
{
|
|
||||||
$pathTokens = explode('/', $relativeOrAbsolutePath);
|
|
||||||
if (count($pathTokens) <= 1)
|
|
||||||
{
|
{
|
||||||
throw new LogicException('Cannot load a post without a path.');
|
$pathTokens = explode('/', $relativeOrAbsolutePath);
|
||||||
}
|
if (count($pathTokens) <= 1) {
|
||||||
|
throw new LogicException('Cannot load a post without a path.');
|
||||||
|
}
|
||||||
|
|
||||||
$postType = $pathTokens[count($pathTokens) - 2];
|
$postType = $pathTokens[count($pathTokens) - 2];
|
||||||
$filename = $pathTokens[count($pathTokens) - 1];
|
$filename = $pathTokens[count($pathTokens) - 1];
|
||||||
$isRelative = $relativeOrAbsolutePath[0] != '/';
|
$isRelative = $relativeOrAbsolutePath[0] != '/';
|
||||||
$slug = strpos($filename, '.md') !== false ? static::getSlugFromFilename($filename) : $filename;
|
$slug = strpos($filename, '.md') !== false ? static::getSlugFromFilename($filename) : $filename;
|
||||||
$path = ($isRelative ? ContentActions::CONTENT_DIR . '/' : '') .
|
$path = ($isRelative ? ContentActions::CONTENT_DIR . '/' : '') .
|
||||||
$relativeOrAbsolutePath .
|
$relativeOrAbsolutePath .
|
||||||
(substr($filename, -3) !== '.md' ? '.md' : '');
|
(substr($filename, -3) !== '.md' ? '.md' : '');
|
||||||
|
|
||||||
if (!file_exists($path) && $isRelative) //may have come in without a post number
|
if (!file_exists($path) && $isRelative) { //may have come in without a post number
|
||||||
{
|
if ($isRelative) {
|
||||||
if ($isRelative)
|
$slugMap = static::getSlugMap($postType);
|
||||||
{
|
if (isset($slugMap[$slug])) {
|
||||||
$slugMap = static::getSlugMap($postType);
|
return static::load($slugMap[$slug]);
|
||||||
if (isset($slugMap[$slug]))
|
}
|
||||||
{
|
}
|
||||||
return static::load($slugMap[$slug]);
|
throw new PostNotFoundException('No post found for path: ' . $relativeOrAbsolutePath);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
throw new PostNotFoundException('No post found for path: ' . $relativeOrAbsolutePath);
|
list($ignored, $frontMatter, $content) = explode('---', file_get_contents($path), 3) + ['','',''];
|
||||||
|
if (!$frontMatter || !$content) {
|
||||||
|
throw new PostMalformedException('Post "' . basename($path) . '" is missing front matter or content');
|
||||||
|
}
|
||||||
|
return new static($path, $postType, $slug, Spyc::YAMLLoadString(trim($frontMatter)), trim($content));
|
||||||
}
|
}
|
||||||
|
|
||||||
list($ignored, $frontMatter, $content) = explode('---', file_get_contents($path), 3) + ['','',''];
|
public function __construct($path, $postType, $slug, $frontMatter, $markdown)
|
||||||
if (!$frontMatter || !$content)
|
|
||||||
{
|
{
|
||||||
throw new PostMalformedException('Post "' . basename($path) . '" is missing front matter or content');
|
$this->path = $path;
|
||||||
}
|
$this->postType = $postType;
|
||||||
return new static($path, $postType, $slug, Spyc::YAMLLoadString(trim($frontMatter)), trim($content));
|
$this->slug = $slug;
|
||||||
}
|
$this->markdown = $markdown;
|
||||||
|
$this->metadata = $frontMatter;
|
||||||
public function __construct($path, $postType, $slug, $frontMatter, $markdown)
|
$this->title = $frontMatter['title'] ?? null;
|
||||||
{
|
$this->author = $frontMatter['author'] ?? null;
|
||||||
$this->path = $path;
|
$this->date = isset($frontMatter['date']) ? new DateTime($frontMatter['date']) : null;
|
||||||
$this->postType = $postType;
|
$this->cover = $frontMatter['cover'] ?? null;
|
||||||
$this->slug = $slug;
|
$this->isCoverLight = isset($frontMatter['cover-light']) && $frontMatter['cover-light'] == 'true';
|
||||||
$this->markdown = $markdown;
|
$this->category = $frontMatter['category'] ?? null;
|
||||||
$this->metadata = $frontMatter;
|
|
||||||
$this->title = $frontMatter['title'] ?? null;
|
|
||||||
$this->author = $frontMatter['author'] ?? null;
|
|
||||||
$this->date = isset($frontMatter['date']) ? new DateTime($frontMatter['date']) : null;
|
|
||||||
$this->cover = $frontMatter['cover'] ?? null;
|
|
||||||
$this->isCoverLight = isset($frontMatter['cover-light']) && $frontMatter['cover-light'] == 'true';
|
|
||||||
$this->category = $frontMatter['category'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function find($folder, $sort = null)
|
|
||||||
{
|
|
||||||
$posts = [];
|
|
||||||
foreach(glob(rtrim($folder, '/') . '/*.md') as $file)
|
|
||||||
{
|
|
||||||
$posts[] = static::load($file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sort)
|
public static function find($folder, $sort = null)
|
||||||
{
|
{
|
||||||
switch ($sort)
|
$posts = [];
|
||||||
{
|
foreach (glob(rtrim($folder, '/') . '/*.md') as $file) {
|
||||||
|
$posts[] = static::load($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sort) {
|
||||||
|
switch ($sort) {
|
||||||
case static::SORT_DATE_DESC:
|
case static::SORT_DATE_DESC:
|
||||||
usort($posts, function(Post $a, Post $b) {
|
usort($posts, function (Post $a, Post $b) {
|
||||||
return strcasecmp($b->getDate()->format('Y-m-d'), $a->getDate()->format('Y-m-d'));
|
return strcasecmp($b->getDate()->format('Y-m-d'), $a->getDate()->format('Y-m-d'));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case static::SORT_ORD_ASC:
|
case static::SORT_ORD_ASC:
|
||||||
usort($posts, function(Post $a, Post $b) {
|
usort($posts, function (Post $a, Post $b) {
|
||||||
$aMeta = $a->getMetadata();
|
$aMeta = $a->getMetadata();
|
||||||
$bMeta = $b->getMetadata();
|
$bMeta = $b->getMetadata();
|
||||||
if (!isset($aMeta['order']) && !isset($bMeta['order']))
|
if (!isset($aMeta['order']) && !isset($bMeta['order'])) {
|
||||||
{
|
return $a->getTitle() < $b->getTitle() ? -1 : 1;
|
||||||
return $a->getTitle() < $b->getTitle() ? -1 : 1;
|
}
|
||||||
}
|
if (isset($aMeta['order']) && isset($bMeta['order'])) {
|
||||||
if (isset($aMeta['order']) && isset($bMeta['order']))
|
return $aMeta['order'] < $bMeta['order'] ? -1 : 1;
|
||||||
{
|
}
|
||||||
return $aMeta['order'] < $bMeta['order'] ? -1 : 1;
|
return isset($aMeta['order']) ? -1 : 1;
|
||||||
}
|
|
||||||
return isset($aMeta['order']) ? -1 : 1;
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return $posts;
|
||||||
}
|
}
|
||||||
return $posts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function filter(array $posts, array $filters)
|
public static function filter(array $posts, array $filters)
|
||||||
{
|
{
|
||||||
return array_filter($posts, function(Post $post) use($filters) {
|
return array_filter($posts, function (Post $post) use ($filters) {
|
||||||
$metadata = $post->getMetadata();
|
$metadata = $post->getMetadata();
|
||||||
foreach($filters as $filterAttr => $filterValue)
|
foreach ($filters as $filterAttr => $filterValue) {
|
||||||
{
|
if (!isset($metadata[$filterAttr]) || (
|
||||||
if (!isset($metadata[$filterAttr]) || (
|
|
||||||
($metadata[$filterAttr] != $filterValue) &&
|
($metadata[$filterAttr] != $filterValue) &&
|
||||||
(!is_array($metadata[$filterAttr]) || !in_array($filterValue, $metadata[$filterAttr]))
|
(!is_array($metadata[$filterAttr]) || !in_array($filterValue, $metadata[$filterAttr]))
|
||||||
))
|
)) {
|
||||||
{
|
return false;
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadata()
|
||||||
|
{
|
||||||
|
return $this->metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataItem($key, $default = null)
|
||||||
|
{
|
||||||
|
return $this->metadata[$key] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMetadataItem($key, $value)
|
||||||
|
{
|
||||||
|
$this->metadata[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelativeUrl()
|
||||||
|
{
|
||||||
|
return '/' . $this->postType . '/' . $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthor()
|
||||||
|
{
|
||||||
|
return $this->author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorGithubID()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
if (array_key_exists("github", $post)) {
|
||||||
|
return $post["github"];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMetadata()
|
|
||||||
{
|
|
||||||
return $this->metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMetadataItem($key, $default = null)
|
|
||||||
{
|
|
||||||
return $this->metadata[$key] ?? $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setMetadataItem($key, $value)
|
|
||||||
{
|
|
||||||
$this->metadata[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRelativeUrl()
|
|
||||||
{
|
|
||||||
return '/' . $this->postType . '/' . $this->slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSlug()
|
|
||||||
{
|
|
||||||
return $this->slug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return $this->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthor()
|
|
||||||
{
|
|
||||||
return $this->author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorGithubID()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
if(array_key_exists("github", $post)){
|
|
||||||
return $post["github"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorTwitterID()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
if(array_key_exists("twitter", $post)){
|
|
||||||
return $post["twitter"];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorEmail()
|
public function getAuthorTwitterID()
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
if(array_key_exists("email", $post)){
|
|
||||||
return $post["email"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDate()
|
|
||||||
{
|
|
||||||
return $this->date;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCover()
|
|
||||||
{
|
|
||||||
return $this->cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIsCoverLight()
|
|
||||||
{
|
|
||||||
return $this->isCoverLight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCategory()
|
|
||||||
{
|
|
||||||
return $this->category;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContentText($wordLimit = null, $appendEllipsis = false)
|
|
||||||
{
|
|
||||||
if ($this->markdown && !$this->contentText)
|
|
||||||
{
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
if (array_key_exists("twitter", $post)) {
|
||||||
|
return $post["twitter"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorEmail()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
if (array_key_exists("email", $post)) {
|
||||||
|
return $post["email"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDate()
|
||||||
|
{
|
||||||
|
return $this->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCover()
|
||||||
|
{
|
||||||
|
return $this->cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsCoverLight()
|
||||||
|
{
|
||||||
|
return $this->isCoverLight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCategory()
|
||||||
|
{
|
||||||
|
return $this->category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContentText($wordLimit = null, $appendEllipsis = false)
|
||||||
|
{
|
||||||
|
if ($this->markdown && !$this->contentText) {
|
||||||
// $this->contentText = $this->markdownToText(trim($this->markdown));
|
// $this->contentText = $this->markdownToText(trim($this->markdown));
|
||||||
$this->contentText = html_entity_decode(str_replace(' ', ' ', strip_tags($this->getContentHtml())), ENT_COMPAT, 'utf-8');
|
$this->contentText = html_entity_decode(str_replace(' ', ' ', strip_tags($this->getContentHtml())), ENT_COMPAT, 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $wordLimit === null ? $this->contentText : $this->limitWords($this->contentText, $wordLimit, $appendEllipsis);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $wordLimit === null ? $this->contentText : $this->limitWords($this->contentText, $wordLimit, $appendEllipsis);
|
public function getContentHtml()
|
||||||
}
|
|
||||||
|
|
||||||
public function getContentHtml()
|
|
||||||
{
|
|
||||||
if ($this->markdown && !$this->contentHtml)
|
|
||||||
{
|
{
|
||||||
$this->contentHtml = ParsedownExtra::instance()->text(trim($this->markdown));
|
if ($this->markdown && !$this->contentHtml) {
|
||||||
|
$this->contentHtml = ParsedownExtra::instance()->text(trim($this->markdown));
|
||||||
|
}
|
||||||
|
return $this->contentHtml;
|
||||||
}
|
}
|
||||||
return $this->contentHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPostNum()
|
public function getPostNum()
|
||||||
{
|
|
||||||
return array_search($this->getSlug(), array_keys(static::getSlugMap($this->postType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPrevPost()
|
|
||||||
{
|
|
||||||
$slugs = array_keys(Post::getSlugMap($this->postType));
|
|
||||||
$postNum = $this->getPostNum();
|
|
||||||
return $postNum === false || $postNum === 0 ? null : Post::load($this->postType . '/' . $slugs[$postNum-1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNextPost()
|
|
||||||
{
|
|
||||||
$slugs = array_keys(Post::getSlugMap($this->postType));
|
|
||||||
$postNum = $this->getPostNum();
|
|
||||||
return $postNum === false || $postNum >= count($slugs)-1 ? null : Post::load($this->postType . '/' . $slugs[$postNum+1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasAuthor()
|
|
||||||
{
|
|
||||||
return $this->author !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasDate()
|
|
||||||
{
|
|
||||||
return $this->date !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorName()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
|
|
||||||
return $post["name"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorPostEmail()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
|
|
||||||
return $post["email"];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorPhoto()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
|
|
||||||
return $post['imgSrc'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthorBioHtml()
|
|
||||||
{
|
|
||||||
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
|
||||||
|
|
||||||
return $post["bioHtml"];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCoverBackgroundStyle($maxStyles)
|
|
||||||
{
|
|
||||||
return $this->getPostNum() % $maxStyles + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getImageUrls()
|
|
||||||
{
|
|
||||||
$urls = [];
|
|
||||||
|
|
||||||
$cover = $this->getCover();
|
|
||||||
if ($cover)
|
|
||||||
{
|
{
|
||||||
$urls[] = 'https://' . Request::getHost() . '/img/blog-covers/' . $cover;
|
return array_search($this->getSlug(), array_keys(static::getSlugMap($this->postType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$matches = [];
|
public function getPrevPost()
|
||||||
preg_match_all('/!\[.*?\]\((.*?)\)/', $this->markdown, $matches);
|
|
||||||
|
|
||||||
if ($matches)
|
|
||||||
{
|
{
|
||||||
$urls = array_merge($urls, $matches[1]);
|
$slugs = array_keys(Post::getSlugMap($this->postType));
|
||||||
|
$postNum = $this->getPostNum();
|
||||||
|
return $postNum === false || $postNum === 0 ? null : Post::load($this->postType . '/' . $slugs[$postNum-1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $urls;
|
public function getNextPost()
|
||||||
}
|
{
|
||||||
|
$slugs = array_keys(Post::getSlugMap($this->postType));
|
||||||
|
$postNum = $this->getPostNum();
|
||||||
|
return $postNum === false || $postNum >= count($slugs)-1 ? null : Post::load($this->postType . '/' . $slugs[$postNum+1]);
|
||||||
|
}
|
||||||
|
|
||||||
protected function markdownToText($markdown)
|
public function hasAuthor()
|
||||||
{
|
{
|
||||||
$replacements = [
|
return $this->author !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasDate()
|
||||||
|
{
|
||||||
|
return $this->date !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorName()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
|
||||||
|
return $post["name"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorPostEmail()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
|
||||||
|
return $post["email"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorPhoto()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
|
||||||
|
return $post['imgSrc'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthorBioHtml()
|
||||||
|
{
|
||||||
|
$post = ContentActions::prepareBioPartial(['person' =>$this->author]);
|
||||||
|
|
||||||
|
return $post["bioHtml"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCoverBackgroundStyle($maxStyles)
|
||||||
|
{
|
||||||
|
return $this->getPostNum() % $maxStyles + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageUrls()
|
||||||
|
{
|
||||||
|
$urls = [];
|
||||||
|
|
||||||
|
$cover = $this->getCover();
|
||||||
|
if ($cover) {
|
||||||
|
$urls[] = 'https://' . Request::getHost() . '/img/blog-covers/' . $cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
$matches = [];
|
||||||
|
preg_match_all('/!\[.*?\]\((.*?)\)/', $this->markdown, $matches);
|
||||||
|
|
||||||
|
if ($matches) {
|
||||||
|
$urls = array_merge($urls, $matches[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function markdownToText($markdown)
|
||||||
|
{
|
||||||
|
$replacements = [
|
||||||
// '/<(.*?)>/' => '$1', // HTML tags
|
// '/<(.*?)>/' => '$1', // HTML tags
|
||||||
'/^[=\-]{2,}\s*$/' => '', // setext-style headers
|
'/^[=\-]{2,}\s*$/' => '', // setext-style headers
|
||||||
'/\[\^.+?\](\: .*?$)?/' => '', // footnotes
|
'/\[\^.+?\](\: .*?$)?/' => '', // footnotes
|
||||||
|
@ -327,65 +325,61 @@ public function getAuthorEmail()
|
||||||
'/\n{2,}/' => '\n\n', // multiple newlines
|
'/\n{2,}/' => '\n\n', // multiple newlines
|
||||||
];
|
];
|
||||||
|
|
||||||
return preg_replace(array_keys($replacements), array_values($replacements), strip_tags($markdown));
|
return preg_replace(array_keys($replacements), array_values($replacements), strip_tags($markdown));
|
||||||
}
|
|
||||||
|
|
||||||
protected function limitWords($string, $wordLimit, $appendEllipsis = false)
|
|
||||||
{
|
|
||||||
$regexp = '/\s+/u';
|
|
||||||
$words = preg_split($regexp, $string, $wordLimit + 1);
|
|
||||||
$numWords = count($words);
|
|
||||||
|
|
||||||
# TBB: if there are $wordLimit words or less, this check is necessary
|
|
||||||
# to prevent the last word from being lost.
|
|
||||||
if ($numWords > $wordLimit)
|
|
||||||
{
|
|
||||||
array_pop($words);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$string = implode(' ', $words);
|
protected function limitWords($string, $wordLimit, $appendEllipsis = false)
|
||||||
|
|
||||||
if ($appendEllipsis && $numWords > $wordLimit)
|
|
||||||
{
|
{
|
||||||
$ellipsis = '…';
|
$regexp = '/\s+/u';
|
||||||
$string .= $ellipsis;
|
$words = preg_split($regexp, $string, $wordLimit + 1);
|
||||||
|
$numWords = count($words);
|
||||||
|
|
||||||
|
# TBB: if there are $wordLimit words or less, this check is necessary
|
||||||
|
# to prevent the last word from being lost.
|
||||||
|
if ($numWords > $wordLimit) {
|
||||||
|
array_pop($words);
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = implode(' ', $words);
|
||||||
|
|
||||||
|
if ($appendEllipsis && $numWords > $wordLimit) {
|
||||||
|
$ellipsis = '…';
|
||||||
|
$string .= $ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $string;
|
public static function getSlugFromFilename($filename)
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSlugFromFilename($filename)
|
|
||||||
{
|
|
||||||
return strtolower(preg_replace('#^\d{1,3}\-#', '', basename(trim($filename), '.md')));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function collectMetadata(array $posts, $field)
|
|
||||||
{
|
|
||||||
$values = array_unique(array_map(function(Post $post) use($field) {
|
|
||||||
$metadata = $post->getMetadata();
|
|
||||||
return $metadata[$field] ?? null;
|
|
||||||
}, $posts));
|
|
||||||
sort($values);
|
|
||||||
return array_combine($values, $values);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSlugMap($postType)
|
|
||||||
{
|
|
||||||
if (!isset(static::$slugMap[$postType]))
|
|
||||||
{
|
{
|
||||||
static::$slugMap[$postType] = [];
|
return strtolower(preg_replace('#^\d{1,3}\-#', '', basename(trim($filename), '.md')));
|
||||||
$files = glob(ContentActions::CONTENT_DIR . '/' . $postType . '/*.md');
|
|
||||||
usort($files, 'strnatcasecmp');
|
|
||||||
foreach($files as $file)
|
|
||||||
{
|
|
||||||
static::$slugMap[$postType][static::getSlugFromFilename($file)] = $file;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return static::$slugMap[$postType];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getGithubEditUrl()
|
public static function collectMetadata(array $posts, $field)
|
||||||
{
|
{
|
||||||
return 'https://github.com/lbryio/lbry.io/tree/master' . str_replace(ROOT_DIR, '', $this->path);
|
$values = array_unique(array_map(function (Post $post) use ($field) {
|
||||||
}
|
$metadata = $post->getMetadata();
|
||||||
|
return $metadata[$field] ?? null;
|
||||||
|
}, $posts));
|
||||||
|
sort($values);
|
||||||
|
return array_combine($values, $values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSlugMap($postType)
|
||||||
|
{
|
||||||
|
if (!isset(static::$slugMap[$postType])) {
|
||||||
|
static::$slugMap[$postType] = [];
|
||||||
|
$files = glob(ContentActions::CONTENT_DIR . '/' . $postType . '/*.md');
|
||||||
|
usort($files, 'strnatcasecmp');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
static::$slugMap[$postType][static::getSlugFromFilename($file)] = $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return static::$slugMap[$postType];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGithubEditUrl()
|
||||||
|
{
|
||||||
|
return 'https://github.com/lbryio/lbry.io/tree/master' . str_replace(ROOT_DIR, '', $this->path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,9 @@ $options = getopt('f');
|
||||||
$force = isset($options['f']); // update even if no NEEDS_UPDATE file exists
|
$force = isset($options['f']); // update even if no NEEDS_UPDATE file exists
|
||||||
|
|
||||||
$needsUpdateFile = ROOT_DIR . '/data/writeable/NEEDS_UPDATE';
|
$needsUpdateFile = ROOT_DIR . '/data/writeable/NEEDS_UPDATE';
|
||||||
if (!$force && !file_exists($needsUpdateFile))
|
if (!$force && !file_exists($needsUpdateFile)) {
|
||||||
{
|
echo "No update necessary\n";
|
||||||
echo "No update necessary\n";
|
return;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@unlink($needsUpdateFile);
|
@unlink($needsUpdateFile);
|
||||||
|
|
|
@ -2,321 +2,302 @@
|
||||||
|
|
||||||
class Response
|
class Response
|
||||||
{
|
{
|
||||||
const HEADER_STATUS = 'Status';
|
const HEADER_STATUS = 'Status';
|
||||||
const HEADER_LOCATION = 'Location';
|
const HEADER_LOCATION = 'Location';
|
||||||
|
|
||||||
const HEADER_CACHE_CONTROL = 'Cache-Control';
|
const HEADER_CACHE_CONTROL = 'Cache-Control';
|
||||||
const HEADER_LAST_MODIFIED = 'Last-Modified';
|
const HEADER_LAST_MODIFIED = 'Last-Modified';
|
||||||
const HEADER_ETAG = 'Etag';
|
const HEADER_ETAG = 'Etag';
|
||||||
|
|
||||||
const HEADER_CONTENT_TYPE = 'Content-Type';
|
const HEADER_CONTENT_TYPE = 'Content-Type';
|
||||||
const HEADER_CONTENT_LENGTH = 'Content-Length';
|
const HEADER_CONTENT_LENGTH = 'Content-Length';
|
||||||
const HEADER_CONTENT_DISPOSITION = 'Content-Disposition';
|
const HEADER_CONTENT_DISPOSITION = 'Content-Disposition';
|
||||||
const HEADER_CONTENT_TYPE_OPTIONS = 'X-Content-Type-Options';
|
const HEADER_CONTENT_TYPE_OPTIONS = 'X-Content-Type-Options';
|
||||||
const HEADER_CONTENT_ENCODING = 'Content-Encoding';
|
const HEADER_CONTENT_ENCODING = 'Content-Encoding';
|
||||||
const HEADER_CROSS_ORIGIN = 'Access-Control-Allow-Origin';
|
const HEADER_CROSS_ORIGIN = 'Access-Control-Allow-Origin';
|
||||||
|
|
||||||
protected static
|
protected static $metaDescription = '';
|
||||||
$metaDescription = '',
|
protected static $metaTitle = '';
|
||||||
$metaTitle = '',
|
protected static $jsCalls = [];
|
||||||
$jsCalls = [],
|
protected static $assets = [
|
||||||
$assets = [
|
|
||||||
'js' => [
|
'js' => [
|
||||||
'/js/jquery-3.3.1.min.js',
|
'/js/jquery-3.3.1.min.js',
|
||||||
'/js/global.js'
|
'/js/global.js'
|
||||||
],
|
],
|
||||||
'css' => ['/css/all.css']
|
'css' => ['/css/all.css']
|
||||||
],
|
];
|
||||||
$headers = [],
|
protected static $headers = [];
|
||||||
$headersSent = false,
|
protected static $headersSent = false;
|
||||||
$content = '',
|
protected static $content = '';
|
||||||
$contentSent = false,
|
protected static $contentSent = false;
|
||||||
$isHeadersOnly = false,
|
protected static $isHeadersOnly = false;
|
||||||
$gzipResponseContent = true,
|
protected static $gzipResponseContent = true;
|
||||||
$metaImages = [],
|
protected static $metaImages = [];
|
||||||
$facebookAnalyticsType = "PageView";
|
protected static $facebookAnalyticsType = "PageView";
|
||||||
|
|
||||||
public static function setMetaDescription($description)
|
public static function setMetaDescription($description)
|
||||||
{
|
|
||||||
static::$metaDescription = $description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addMetaImage($url)
|
|
||||||
{
|
|
||||||
static::$metaImages[] = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addMetaImages(array $urls)
|
|
||||||
{
|
|
||||||
foreach ($urls as $url)
|
|
||||||
{
|
{
|
||||||
static::addMetaImage($url);
|
static::$metaDescription = $description;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function getMetaDescription()
|
public static function addMetaImage($url)
|
||||||
{
|
|
||||||
return static::$metaDescription ?: 'A Content Revolution';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getMetaImages()
|
|
||||||
{
|
|
||||||
return static::$metaImages ?: [Request::getHostAndProto() . '/img/lbry-green-meta-1200x900.png'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setMetaTitle($title)
|
|
||||||
{
|
|
||||||
static::$metaTitle = $title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getMetaTitle()
|
|
||||||
{
|
|
||||||
return static::$metaTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function guessMetaTitle($content)
|
|
||||||
{
|
|
||||||
$title = '';
|
|
||||||
preg_match_all('/<h(1|2)[^>]*>([^<]+)</', $content, $titleMatches);
|
|
||||||
foreach ($titleMatches[1] as $matchIndex => $headerValue)
|
|
||||||
{
|
{
|
||||||
if ($headerValue == '1' || !$title)
|
static::$metaImages[] = $url;
|
||||||
{
|
}
|
||||||
$title = $titleMatches[2][$matchIndex];
|
|
||||||
if ($headerValue == '1')
|
public static function addMetaImages(array $urls)
|
||||||
{
|
{
|
||||||
return $title;
|
foreach ($urls as $url) {
|
||||||
|
static::addMetaImage($url);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getJsCalls()
|
public static function getMetaDescription()
|
||||||
{
|
|
||||||
return static::$jsCalls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function jsOutputCallback($js)
|
|
||||||
{
|
|
||||||
static::$jsCalls[] = $js;
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addJsAsset($src)
|
|
||||||
{
|
|
||||||
static::$assets['js'][$src] = $src;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addCssAsset($src)
|
|
||||||
{
|
|
||||||
static::$assets['css'][$src] = $src;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getJsAssets()
|
|
||||||
{
|
|
||||||
return static::$assets['js'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getCssAssets()
|
|
||||||
{
|
|
||||||
return static::$assets['css'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setCssAssets(array $assets = []){
|
|
||||||
static::$assets['css'] = $assets;
|
|
||||||
}
|
|
||||||
public static function setGzipResponseContent($gzip = true)
|
|
||||||
{
|
|
||||||
static::$gzipResponseContent = $gzip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function gzipContentIfNotDisabled()
|
|
||||||
{
|
|
||||||
if (static::$gzipResponseContent)
|
|
||||||
{
|
{
|
||||||
$content = static::getContent();
|
return static::$metaDescription ?: 'A Content Revolution';
|
||||||
if (strlen($content) > 256) // not worth it for really short content
|
|
||||||
{
|
|
||||||
$compressed = gzencode($content, 1);
|
|
||||||
static::setContent($compressed);
|
|
||||||
static::setHeader(static::HEADER_CONTENT_LENGTH, strlen($compressed));
|
|
||||||
static::setHeader(static::HEADER_CONTENT_ENCODING, 'gzip');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function send()
|
public static function getMetaImages()
|
||||||
{
|
|
||||||
static::sendHeaders();
|
|
||||||
static::sendContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setContent(string $content)
|
|
||||||
{
|
|
||||||
static::$content = $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getContent(): string
|
|
||||||
{
|
|
||||||
return static::$content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function sendContent()
|
|
||||||
{
|
|
||||||
if (static::$contentSent)
|
|
||||||
{
|
{
|
||||||
throw new LogicException('Content has already been sent. It cannot be sent twice');
|
return static::$metaImages ?: [Request::getHostAndProto() . '/img/lbry-green-meta-1200x900.png'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!static::$isHeadersOnly)
|
public static function setMetaTitle($title)
|
||||||
{
|
{
|
||||||
echo static::$content;
|
static::$metaTitle = $title;
|
||||||
}
|
}
|
||||||
|
|
||||||
static::$contentSent = true;
|
public static function getMetaTitle()
|
||||||
}
|
{
|
||||||
|
return static::$metaTitle;
|
||||||
|
}
|
||||||
|
|
||||||
public static function setIsHeadersOnly(bool $isHeadersOnly = true)
|
public static function guessMetaTitle($content)
|
||||||
{
|
{
|
||||||
static::$isHeadersOnly = $isHeadersOnly;
|
$title = '';
|
||||||
}
|
preg_match_all('/<h(1|2)[^>]*>([^<]+)</', $content, $titleMatches);
|
||||||
|
foreach ($titleMatches[1] as $matchIndex => $headerValue) {
|
||||||
|
if ($headerValue == '1' || !$title) {
|
||||||
|
$title = $titleMatches[2][$matchIndex];
|
||||||
|
if ($headerValue == '1') {
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
|
||||||
public static function setDownloadHttpHeaders($name, $type = null, $size = null, $noSniff = true)
|
public static function getJsCalls()
|
||||||
{
|
{
|
||||||
static::setBinaryHttpHeaders($type, $size, $noSniff);
|
return static::$jsCalls;
|
||||||
static::setHeader('Content-Disposition', 'attachment;filename=' . $name);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function setBinaryHttpHeaders($type, $size = null, $noSniff = true)
|
public static function jsOutputCallback($js)
|
||||||
{
|
{
|
||||||
static::setGzipResponseContent(false); // in case its already compressed
|
static::$jsCalls[] = $js;
|
||||||
static::setHeaders(array_filter([
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function addJsAsset($src)
|
||||||
|
{
|
||||||
|
static::$assets['js'][$src] = $src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function addCssAsset($src)
|
||||||
|
{
|
||||||
|
static::$assets['css'][$src] = $src;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getJsAssets()
|
||||||
|
{
|
||||||
|
return static::$assets['js'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCssAssets()
|
||||||
|
{
|
||||||
|
return static::$assets['css'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setCssAssets(array $assets = [])
|
||||||
|
{
|
||||||
|
static::$assets['css'] = $assets;
|
||||||
|
}
|
||||||
|
public static function setGzipResponseContent($gzip = true)
|
||||||
|
{
|
||||||
|
static::$gzipResponseContent = $gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function gzipContentIfNotDisabled()
|
||||||
|
{
|
||||||
|
if (static::$gzipResponseContent) {
|
||||||
|
$content = static::getContent();
|
||||||
|
if (strlen($content) > 256) { // not worth it for really short content
|
||||||
|
$compressed = gzencode($content, 1);
|
||||||
|
static::setContent($compressed);
|
||||||
|
static::setHeader(static::HEADER_CONTENT_LENGTH, strlen($compressed));
|
||||||
|
static::setHeader(static::HEADER_CONTENT_ENCODING, 'gzip');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function send()
|
||||||
|
{
|
||||||
|
static::sendHeaders();
|
||||||
|
static::sendContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setContent(string $content)
|
||||||
|
{
|
||||||
|
static::$content = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getContent(): string
|
||||||
|
{
|
||||||
|
return static::$content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sendContent()
|
||||||
|
{
|
||||||
|
if (static::$contentSent) {
|
||||||
|
throw new LogicException('Content has already been sent. It cannot be sent twice');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!static::$isHeadersOnly) {
|
||||||
|
echo static::$content;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$contentSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setIsHeadersOnly(bool $isHeadersOnly = true)
|
||||||
|
{
|
||||||
|
static::$isHeadersOnly = $isHeadersOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setDownloadHttpHeaders($name, $type = null, $size = null, $noSniff = true)
|
||||||
|
{
|
||||||
|
static::setBinaryHttpHeaders($type, $size, $noSniff);
|
||||||
|
static::setHeader('Content-Disposition', 'attachment;filename=' . $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setBinaryHttpHeaders($type, $size = null, $noSniff = true)
|
||||||
|
{
|
||||||
|
static::setGzipResponseContent(false); // in case its already compressed
|
||||||
|
static::setHeaders(array_filter([
|
||||||
static::HEADER_CONTENT_TYPE => $type,
|
static::HEADER_CONTENT_TYPE => $type,
|
||||||
static::HEADER_CONTENT_LENGTH => $size ?: null,
|
static::HEADER_CONTENT_LENGTH => $size ?: null,
|
||||||
static::HEADER_CONTENT_TYPE_OPTIONS => $noSniff ? 'nosniff' : null,
|
static::HEADER_CONTENT_TYPE_OPTIONS => $noSniff ? 'nosniff' : null,
|
||||||
]));
|
]));
|
||||||
}
|
|
||||||
|
|
||||||
public static function setContentEtag()
|
|
||||||
{
|
|
||||||
static::setHeader(static::HEADER_ETAG, md5(static::getContent()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function enableHttpCache(int $seconds = 300)
|
|
||||||
{
|
|
||||||
static::addCacheControlHeader('max-age', $seconds);
|
|
||||||
static::setHeader('Pragma', 'public');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addCacheControlHeader(string $name, $value = null)
|
|
||||||
{
|
|
||||||
$cacheControl = static::getHeader(static::HEADER_CACHE_CONTROL);
|
|
||||||
$currentHeaders = [];
|
|
||||||
if ($cacheControl)
|
|
||||||
{
|
|
||||||
foreach (preg_split('/\s*,\s*/', $cacheControl) as $tmp)
|
|
||||||
{
|
|
||||||
$tmp = explode('=', $tmp);
|
|
||||||
$currentHeaders[$tmp[0]] = $tmp[1] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$currentHeaders[strtr(strtolower($name), '_', '-')] = $value;
|
|
||||||
|
|
||||||
$headers = [];
|
|
||||||
foreach ($currentHeaders as $key => $currentVal)
|
|
||||||
{
|
|
||||||
$headers[] = $key . ($currentVal !== null ? '=' . $currentVal : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static::setHeader(static::HEADER_CACHE_CONTROL, implode(', ', $headers));
|
public static function setContentEtag()
|
||||||
}
|
|
||||||
|
|
||||||
public static function setHeader($name, $value)
|
|
||||||
{
|
|
||||||
static::$headers[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setHeaders($headers, $overwrite = true)
|
|
||||||
{
|
|
||||||
foreach ($headers as $name => $value)
|
|
||||||
{
|
{
|
||||||
if ($overwrite || !static::getHeader($name))
|
static::setHeader(static::HEADER_ETAG, md5(static::getContent()));
|
||||||
{
|
|
||||||
static::setHeader($name, $value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static function getHeader($name, $default = null)
|
public static function enableHttpCache(int $seconds = 300)
|
||||||
{
|
{
|
||||||
return static::$headers[$name] ?? $default;
|
static::addCacheControlHeader('max-age', $seconds);
|
||||||
}
|
static::setHeader('Pragma', 'public');
|
||||||
|
}
|
||||||
|
|
||||||
public static function getHeaders(): array
|
public static function addCacheControlHeader(string $name, $value = null)
|
||||||
{
|
{
|
||||||
return static::$headers;
|
$cacheControl = static::getHeader(static::HEADER_CACHE_CONTROL);
|
||||||
}
|
$currentHeaders = [];
|
||||||
|
if ($cacheControl) {
|
||||||
|
foreach (preg_split('/\s*,\s*/', $cacheControl) as $tmp) {
|
||||||
|
$tmp = explode('=', $tmp);
|
||||||
|
$currentHeaders[$tmp[0]] = $tmp[1] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$currentHeaders[strtr(strtolower($name), '_', '-')] = $value;
|
||||||
|
|
||||||
public static function setStatus($status)
|
$headers = [];
|
||||||
{
|
foreach ($currentHeaders as $key => $currentVal) {
|
||||||
static::setHeader(static::HEADER_STATUS, $status);
|
$headers[] = $key . ($currentVal !== null ? '=' . $currentVal : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setDefaultSecurityHeaders()
|
static::setHeader(static::HEADER_CACHE_CONTROL, implode(', ', $headers));
|
||||||
{
|
}
|
||||||
$defaultHeaders = [
|
|
||||||
|
public static function setHeader($name, $value)
|
||||||
|
{
|
||||||
|
static::$headers[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setHeaders($headers, $overwrite = true)
|
||||||
|
{
|
||||||
|
foreach ($headers as $name => $value) {
|
||||||
|
if ($overwrite || !static::getHeader($name)) {
|
||||||
|
static::setHeader($name, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getHeader($name, $default = null)
|
||||||
|
{
|
||||||
|
return static::$headers[$name] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getHeaders(): array
|
||||||
|
{
|
||||||
|
return static::$headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setStatus($status)
|
||||||
|
{
|
||||||
|
static::setHeader(static::HEADER_STATUS, $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setDefaultSecurityHeaders()
|
||||||
|
{
|
||||||
|
$defaultHeaders = [
|
||||||
'Content-Security-Policy' => "frame-ancestors 'none'",
|
'Content-Security-Policy' => "frame-ancestors 'none'",
|
||||||
'X-Frame-Options' => 'DENY',
|
'X-Frame-Options' => 'DENY',
|
||||||
'X-XSS-Protection' => '1',
|
'X-XSS-Protection' => '1',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (IS_PRODUCTION)
|
if (IS_PRODUCTION) {
|
||||||
{
|
$defaultHeaders['Strict-Transport-Security'] = 'max-age=31536000';
|
||||||
$defaultHeaders['Strict-Transport-Security'] = 'max-age=31536000';
|
}
|
||||||
|
|
||||||
|
static::setHeaders($defaultHeaders, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static::setHeaders($defaultHeaders, false);
|
public static function sendHeaders()
|
||||||
}
|
|
||||||
|
|
||||||
public static function sendHeaders()
|
|
||||||
{
|
|
||||||
if (static::$headersSent)
|
|
||||||
{
|
{
|
||||||
throw new LogicException('Headers have already been sent. They cannot be sent twice');
|
if (static::$headersSent) {
|
||||||
|
throw new LogicException('Headers have already been sent. They cannot be sent twice');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!static::getHeader(static::HEADER_CONTENT_TYPE)) {
|
||||||
|
static::setHeader(static::HEADER_CONTENT_TYPE, 'text/html');
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = static::getHeaders();
|
||||||
|
|
||||||
|
if (isset($headers[static::HEADER_STATUS])) {
|
||||||
|
$status = 'HTTP/1.0 ' . $headers[static::HEADER_STATUS] . ' ' . static::getStatusTextForCode($headers[static::HEADER_STATUS]);
|
||||||
|
header($status);
|
||||||
|
|
||||||
|
if (substr(php_sapi_name(), 0, 3) == 'cgi') {
|
||||||
|
// fastcgi servers cannot send this status information because it was sent by them already due to the HTT/1.0 line
|
||||||
|
// so we can safely unset them. see ticket #3191
|
||||||
|
unset($headers[static::HEADER_STATUS]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($headers as $name => $value) {
|
||||||
|
header($name . ': ' . $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static::$headersSent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!static::getHeader(static::HEADER_CONTENT_TYPE))
|
public static function getStatusTextForCode($code)
|
||||||
{
|
{
|
||||||
static::setHeader(static::HEADER_CONTENT_TYPE, 'text/html');
|
$statusTexts = [
|
||||||
}
|
|
||||||
|
|
||||||
$headers = static::getHeaders();
|
|
||||||
|
|
||||||
if (isset($headers[static::HEADER_STATUS]))
|
|
||||||
{
|
|
||||||
$status = 'HTTP/1.0 ' . $headers[static::HEADER_STATUS] . ' ' . static::getStatusTextForCode($headers[static::HEADER_STATUS]);
|
|
||||||
header($status);
|
|
||||||
|
|
||||||
if (substr(php_sapi_name(), 0, 3) == 'cgi')
|
|
||||||
{
|
|
||||||
// fastcgi servers cannot send this status information because it was sent by them already due to the HTT/1.0 line
|
|
||||||
// so we can safely unset them. see ticket #3191
|
|
||||||
unset($headers[static::HEADER_STATUS]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($headers as $name => $value)
|
|
||||||
{
|
|
||||||
header($name . ': ' . $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static::$headersSent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getStatusTextForCode($code)
|
|
||||||
{
|
|
||||||
$statusTexts = [
|
|
||||||
'100' => 'Continue',
|
'100' => 'Continue',
|
||||||
'101' => 'Switching Protocols',
|
'101' => 'Switching Protocols',
|
||||||
'200' => 'OK',
|
'200' => 'OK',
|
||||||
|
@ -364,28 +345,32 @@ class Response
|
||||||
'505' => 'HTTP Version Not Supported',
|
'505' => 'HTTP Version Not Supported',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $statusTexts[$code] ?? null;
|
return $statusTexts[$code] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setFacebookPixelAnalyticsType($type){
|
public static function setFacebookPixelAnalyticsType($type)
|
||||||
static::$facebookAnalyticsType = $type;
|
{
|
||||||
}
|
static::$facebookAnalyticsType = $type;
|
||||||
|
}
|
||||||
|
|
||||||
public static function getFacebookPixelAnalyticsType(){
|
public static function getFacebookPixelAnalyticsType()
|
||||||
return static::$facebookAnalyticsType;
|
{
|
||||||
}
|
return static::$facebookAnalyticsType;
|
||||||
|
}
|
||||||
|
|
||||||
protected static function normalizeHeaderName($name): string
|
protected static function normalizeHeaderName($name): string
|
||||||
{
|
{
|
||||||
return preg_replace_callback(
|
return preg_replace_callback(
|
||||||
'/\-(.)/',
|
'/\-(.)/',
|
||||||
function ($matches) { return '-' . strtoupper($matches[1]); },
|
function ($matches) {
|
||||||
|
return '-' . strtoupper($matches[1]);
|
||||||
|
},
|
||||||
strtr(ucfirst(strtolower($name)), '_', '-')
|
strtr(ucfirst(strtolower($name)), '_', '-')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public static function addBodyCssClass($classOrClasses)
|
// public static function addBodyCssClass($classOrClasses)
|
||||||
// {
|
// {
|
||||||
// static::$bodyCssClasses = array_unique(array_merge(static::$bodyCssClasses, (array)$classOrClasses));
|
// static::$bodyCssClasses = array_unique(array_merge(static::$bodyCssClasses, (array)$classOrClasses));
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -2,195 +2,179 @@
|
||||||
|
|
||||||
function js_start()
|
function js_start()
|
||||||
{
|
{
|
||||||
ob_start('Response::jsOutputCallback');
|
ob_start('Response::jsOutputCallback');
|
||||||
}
|
}
|
||||||
|
|
||||||
function js_end()
|
function js_end()
|
||||||
{
|
{
|
||||||
ob_end_flush();
|
ob_end_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
class View
|
class View
|
||||||
{
|
{
|
||||||
const LAYOUT_PARAMS = '_layout_params';
|
const LAYOUT_PARAMS = '_layout_params';
|
||||||
|
|
||||||
const WEB_DIR = ROOT_DIR . '/web';
|
const WEB_DIR = ROOT_DIR . '/web';
|
||||||
const SCSS_DIR = self::WEB_DIR . '/scss';
|
const SCSS_DIR = self::WEB_DIR . '/scss';
|
||||||
const CSS_DIR = self::WEB_DIR . '/css';
|
const CSS_DIR = self::WEB_DIR . '/css';
|
||||||
const JS_DIR = self::WEB_DIR . '/js';
|
const JS_DIR = self::WEB_DIR . '/js';
|
||||||
|
|
||||||
public static function render($template, array $vars = []): string
|
public static function render($template, array $vars = []): string
|
||||||
{
|
|
||||||
if (static::isMarkdown($template))
|
|
||||||
{
|
{
|
||||||
return static::markdownToHtml(static::getFullPath($template));
|
if (static::isMarkdown($template)) {
|
||||||
|
return static::markdownToHtml(static::getFullPath($template));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!static::exists($template) || substr_count($template, '/') !== 1) {
|
||||||
|
throw new InvalidArgumentException(sprintf('The template "%s" does not exist or is unreadable.', $template));
|
||||||
|
}
|
||||||
|
|
||||||
|
list($module, $view) = explode('/', $template);
|
||||||
|
|
||||||
|
$isPartial = $view[0] === '_';
|
||||||
|
$actionClass = ucfirst($module) . 'Actions';
|
||||||
|
$method = 'prepare' . ucfirst(ltrim($view, '_')) . ($isPartial ? 'Partial' : '');
|
||||||
|
|
||||||
|
if (method_exists($actionClass, $method)) {
|
||||||
|
$vars = $actionClass::$method($vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($vars === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::interpolateTokens(static::getTemplateSafely($template, $vars));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!static::exists($template) || substr_count($template, '/') !== 1)
|
/**
|
||||||
|
* This is its own function because we don't want in-scope variables to leak into the template
|
||||||
|
*
|
||||||
|
* @param string $___template
|
||||||
|
* @param array $___vars
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
protected static function getTemplateSafely(string $___template, array $___vars): string
|
||||||
{
|
{
|
||||||
throw new InvalidArgumentException(sprintf('The template "%s" does not exist or is unreadable.', $template));
|
extract($___vars);
|
||||||
|
ob_start();
|
||||||
|
ob_implicit_flush(0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
require(static::getFullPath($___template));
|
||||||
|
return ob_get_clean();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
// need to end output buffering before throwing the exception
|
||||||
|
ob_end_clean();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list($module, $view) = explode('/', $template);
|
public static function markdownToHtml($path): string
|
||||||
|
|
||||||
$isPartial = $view[0] === '_';
|
|
||||||
$actionClass = ucfirst($module) . 'Actions';
|
|
||||||
$method = 'prepare' . ucfirst(ltrim($view, '_')) . ($isPartial ? 'Partial' : '');
|
|
||||||
|
|
||||||
if (method_exists($actionClass, $method))
|
|
||||||
{
|
{
|
||||||
$vars = $actionClass::$method($vars);
|
return ParsedownExtra::instance()->text(trim(file_get_contents($path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($vars === null)
|
public static function exists($template): bool
|
||||||
{
|
{
|
||||||
return [];
|
return is_readable(static::getFullPath($template));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::interpolateTokens(static::getTemplateSafely($template, $vars));
|
protected static function isMarkdown($nameOrPath): bool
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is its own function because we don't want in-scope variables to leak into the template
|
|
||||||
*
|
|
||||||
* @param string $___template
|
|
||||||
* @param array $___vars
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
protected static function getTemplateSafely(string $___template, array $___vars): string
|
|
||||||
{
|
|
||||||
extract($___vars);
|
|
||||||
ob_start();
|
|
||||||
ob_implicit_flush(0);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
require(static::getFullPath($___template));
|
return strlen($nameOrPath) > 3 && substr($nameOrPath, -3) == '.md';
|
||||||
return ob_get_clean();
|
|
||||||
}
|
|
||||||
catch (Throwable $e)
|
|
||||||
{
|
|
||||||
// need to end output buffering before throwing the exception
|
|
||||||
ob_end_clean();
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function markdownToHtml($path): string
|
|
||||||
{
|
|
||||||
return ParsedownExtra::instance()->text(trim(file_get_contents($path)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function exists($template): bool
|
|
||||||
{
|
|
||||||
return is_readable(static::getFullPath($template));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function isMarkdown($nameOrPath): bool
|
|
||||||
{
|
|
||||||
return strlen($nameOrPath) > 3 && substr($nameOrPath, -3) == '.md';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function getFullPath($template): string
|
|
||||||
{
|
|
||||||
if ($template && $template[0] == '/')
|
|
||||||
{
|
|
||||||
return $template;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static::isMarkdown($template))
|
protected static function getFullPath($template): string
|
||||||
{
|
{
|
||||||
return ContentActions::CONTENT_DIR . '/' . $template;
|
if ($template && $template[0] == '/') {
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::isMarkdown($template)) {
|
||||||
|
return ContentActions::CONTENT_DIR . '/' . $template;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROOT_DIR . '/view/template/' . $template . '.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
return ROOT_DIR . '/view/template/' . $template . '.php';
|
public static function imagePath($image): string
|
||||||
}
|
|
||||||
|
|
||||||
public static function imagePath($image): string
|
|
||||||
{
|
|
||||||
return '/img/' . $image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function parseMarkdown($template): array
|
|
||||||
{
|
|
||||||
$path = static::getFullPath($template);
|
|
||||||
list($ignored, $frontMatter, $markdown) = explode('---', file_get_contents($path), 3);
|
|
||||||
$metadata = Spyc::YAMLLoadString(trim($frontMatter));
|
|
||||||
$html = ParsedownExtra::instance()->text(trim($markdown));
|
|
||||||
return [$metadata, $html];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function compileCss()
|
|
||||||
{
|
|
||||||
$scssCompiler = new \Leafo\ScssPhp\Compiler();
|
|
||||||
|
|
||||||
$scssCompiler->setImportPaths([self::SCSS_DIR]);
|
|
||||||
|
|
||||||
$compress = true;
|
|
||||||
if ($compress)
|
|
||||||
{
|
{
|
||||||
$scssCompiler->setFormatter('Leafo\ScssPhp\Formatter\Crunched');
|
return '/img/' . $image;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$scssCompiler->setFormatter('Leafo\ScssPhp\Formatter\Expanded');
|
|
||||||
$scssCompiler->setLineNumberStyle(Leafo\ScssPhp\Compiler::LINE_COMMENTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$all_css = $scssCompiler->compile(file_get_contents(self::SCSS_DIR . '/all.scss'));
|
public static function parseMarkdown($template): array
|
||||||
file_put_contents(self::CSS_DIR . '/all.css', $all_css);
|
|
||||||
|
|
||||||
$youtube_css = $scssCompiler->compile(file_get_contents(self::SCSS_DIR . '/youtube.scss'));
|
|
||||||
file_put_contents(self::CSS_DIR . '/youtube.css', $youtube_css);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function gzipAssets()
|
|
||||||
{
|
|
||||||
foreach ([self::CSS_DIR => 'css', self::JS_DIR => 'js'] as $dir => $ext)
|
|
||||||
{
|
{
|
||||||
foreach (glob("$dir/*.$ext") as $file)
|
$path = static::getFullPath($template);
|
||||||
{
|
list($ignored, $frontMatter, $markdown) = explode('---', file_get_contents($path), 3);
|
||||||
Gzip::compressFile($file);
|
$metadata = Spyc::YAMLLoadString(trim($frontMatter));
|
||||||
}
|
$html = ParsedownExtra::instance()->text(trim($markdown));
|
||||||
|
return [$metadata, $html];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected static function interpolateTokens($html): string
|
public static function compileCss()
|
||||||
{
|
|
||||||
return preg_replace_callback('/{{[\w\.]+}}/is', function ($m)
|
|
||||||
{
|
{
|
||||||
return i18n::translate(trim($m[0], '}{'));
|
$scssCompiler = new \Leafo\ScssPhp\Compiler();
|
||||||
}, $html);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function escapeOnce($value): string
|
$scssCompiler->setImportPaths([self::SCSS_DIR]);
|
||||||
{
|
|
||||||
return preg_replace('/&([a-z]+|(#\d+)|(#x[\da-f]+));/i', '&$1;', htmlspecialchars((string)$value, ENT_QUOTES, 'utf-8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function attributesToHtml($attributes): string
|
$compress = true;
|
||||||
{
|
if ($compress) {
|
||||||
return implode('', array_map(function ($k, $v)
|
$scssCompiler->setFormatter('Leafo\ScssPhp\Formatter\Crunched');
|
||||||
|
} else {
|
||||||
|
$scssCompiler->setFormatter('Leafo\ScssPhp\Formatter\Expanded');
|
||||||
|
$scssCompiler->setLineNumberStyle(Leafo\ScssPhp\Compiler::LINE_COMMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
$all_css = $scssCompiler->compile(file_get_contents(self::SCSS_DIR . '/all.scss'));
|
||||||
|
file_put_contents(self::CSS_DIR . '/all.css', $all_css);
|
||||||
|
|
||||||
|
$youtube_css = $scssCompiler->compile(file_get_contents(self::SCSS_DIR . '/youtube.scss'));
|
||||||
|
file_put_contents(self::CSS_DIR . '/youtube.css', $youtube_css);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function gzipAssets()
|
||||||
{
|
{
|
||||||
return $v === true ? " $k" : ($v === false || $v === null || ($v === '' && $k != 'value') ? '' : sprintf(' %s="%s"', $k, static::escapeOnce($v)));
|
foreach ([self::CSS_DIR => 'css', self::JS_DIR => 'js'] as $dir => $ext) {
|
||||||
}, array_keys($attributes), array_values($attributes)));
|
foreach (glob("$dir/*.$ext") as $file) {
|
||||||
}
|
Gzip::compressFile($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function renderTag($tag, $attributes = []): string
|
protected static function interpolateTokens($html): string
|
||||||
{
|
{
|
||||||
return $tag ? sprintf('<%s%s />', $tag, static::attributesToHtml($attributes)) : '';
|
return preg_replace_callback('/{{[\w\.]+}}/is', function ($m) {
|
||||||
}
|
return i18n::translate(trim($m[0], '}{'));
|
||||||
|
}, $html);
|
||||||
|
}
|
||||||
|
|
||||||
public static function renderContentTag($tag, $content = null, $attributes = []): string
|
protected static function escapeOnce($value): string
|
||||||
{
|
{
|
||||||
return $tag ? sprintf('<%s%s>%s</%s>', $tag, static::attributesToHtml($attributes), $content, $tag) : '';
|
return preg_replace('/&([a-z]+|(#\d+)|(#x[\da-f]+));/i', '&$1;', htmlspecialchars((string)$value, ENT_QUOTES, 'utf-8'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function renderJson($data): array
|
protected static function attributesToHtml($attributes): string
|
||||||
{
|
{
|
||||||
Response::setHeader(Response::HEADER_CONTENT_TYPE, 'application/json');
|
return implode('', array_map(function ($k, $v) {
|
||||||
return ['internal/json', ['json' => $data, '_no_layout' => true]];
|
return $v === true ? " $k" : ($v === false || $v === null || ($v === '' && $k != 'value') ? '' : sprintf(' %s="%s"', $k, static::escapeOnce($v)));
|
||||||
}
|
}, array_keys($attributes), array_values($attributes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function renderTag($tag, $attributes = []): string
|
||||||
|
{
|
||||||
|
return $tag ? sprintf('<%s%s />', $tag, static::attributesToHtml($attributes)) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function renderContentTag($tag, $content = null, $attributes = []): string
|
||||||
|
{
|
||||||
|
return $tag ? sprintf('<%s%s>%s</%s>', $tag, static::attributesToHtml($attributes), $content, $tag) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function renderJson($data): array
|
||||||
|
{
|
||||||
|
Response::setHeader(Response::HEADER_CONTENT_TYPE, 'application/json');
|
||||||
|
return ['internal/json', ['json' => $data, '_no_layout' => true]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ $email = Request::encodeStringFromUser($_POST['new_email']);
|
||||||
$sync_consent = isset($_POST['sync_consent']);
|
$sync_consent = isset($_POST['sync_consent']);
|
||||||
|
|
||||||
|
|
||||||
if(!preg_match("/@[A-Za-z0-9_-]+$/", $channel_name)){
|
if (!preg_match("/@[A-Za-z0-9_-]+$/", $channel_name)) {
|
||||||
$channel_name = "@" . $channel_name;
|
$channel_name = "@" . $channel_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
endif;?>
|
endif;?>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<label for="channel-name">LBRY Channel ID</label>
|
<label for="channel-name">LBRY Channel ID</label>
|
||||||
<input type="text" id="channel-name" name="new_preferred_channel" placeholder="@YourPreferredChannelName" value="<?php echo $statusData['lbry_channel_name'];?>" <?php if($statusData['status'] == 'syncing' || $statusData['status'] == 'synced'): echo "disabled"; endif; ?> >
|
<input type="text" id="channel-name" name="new_preferred_channel" placeholder="@YourPreferredChannelName" value="<?php echo $statusData['lbry_channel_name'];?>" <?php if ($statusData['status'] == 'syncing' || $statusData['status'] == 'synced'): echo "disabled"; endif; ?> >
|
||||||
<div hidden id="channel-name-error" class="error">Channel is invalid or blank</div>
|
<div hidden id="channel-name-error" class="error">Channel is invalid or blank</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
<div hidden id="email-google-plus-error" class="error">Are you sure you want to use this email</div>
|
<div hidden id="email-google-plus-error" class="error">Are you sure you want to use this email</div>
|
||||||
</div>
|
</div>
|
||||||
<label for="sync-consent" class="block full">
|
<label for="sync-consent" class="block full">
|
||||||
<input name="sync_consent" id="sync-consent" type="checkbox" <?php if($statusData['status'] == 'queued'): echo "checked"; endif;?> <?php if($statusData['status'] == 'syncing' || $statusData['status'] == 'synced'): echo "disabled "; echo "checked"; endif; ?>>I want to sync my content to the LBRY network and agree to <a href="/faq/youtube-terms">these terms</a>.
|
<input name="sync_consent" id="sync-consent" type="checkbox" <?php if ($statusData['status'] == 'queued'): echo "checked"; endif;?> <?php if ($statusData['status'] == 'syncing' || $statusData['status'] == 'synced'): echo "disabled "; echo "checked"; endif; ?>>I want to sync my content to the LBRY network and agree to <a href="/faq/youtube-terms">these terms</a>.
|
||||||
<div hidden id="sync-consent-error" class="error">In order to continue, you must agree to sync.</div>
|
<div hidden id="sync-consent-error" class="error">In order to continue, you must agree to sync.</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
$desired_lbry_channel_name = Request::encodeStringFromUser($_POST['desired_lbry_channel_name']);
|
$desired_lbry_channel_name = Request::encodeStringFromUser($_POST['desired_lbry_channel_name']);
|
||||||
|
|
||||||
if(!preg_match("/@[A-Za-z0-9_-]+$/", $desired_lbry_channel_name)){
|
if (!preg_match("/@[A-Za-z0-9_-]+$/", $desired_lbry_channel_name)) {
|
||||||
$desired_lbry_channel_name = "@" . $desired_lbry_channel_name;
|
$desired_lbry_channel_name = "@" . $desired_lbry_channel_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
AcquisitionActions::actionYoutubeToken($desired_lbry_channel_name);
|
AcquisitionActions::actionYoutubeToken($desired_lbry_channel_name);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="form-row align-left">
|
<div class="form-row align-left">
|
||||||
<label>Status</label>
|
<label>Status</label>
|
||||||
<select name="status">
|
<select name="status">
|
||||||
<?php foreach($statuses as $statusVal => $statusLabel): ?>
|
<?php foreach ($statuses as $statusVal => $statusLabel): ?>
|
||||||
<option value="<?php echo $statusVal ?>" <?php echo $selectedStatus == $statusVal ? 'selected="selected"' : '' ?>><?php echo $statusLabel ?></option>
|
<option value="<?php echo $statusVal ?>" <?php echo $selectedStatus == $statusVal ? 'selected="selected"' : '' ?>><?php echo $statusLabel ?></option>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</select>
|
</select>
|
||||||
|
@ -41,12 +41,12 @@
|
||||||
<?php if (count($bounties)): ?>
|
<?php if (count($bounties)): ?>
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<?php $index = 0 ?>
|
<?php $index = 0 ?>
|
||||||
<?php foreach($bounties as $post): ?>
|
<?php foreach ($bounties as $post): ?>
|
||||||
<?php $metadata = $post->getMetadata() ?>
|
<?php $metadata = $post->getMetadata() ?>
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<a class="bounty-tile" href="<?php echo $post->getRelativeUrl() ?>">
|
<a class="bounty-tile" href="<?php echo $post->getRelativeUrl() ?>">
|
||||||
<div class="text-center spacer-half"><span class="icon-mega
|
<div class="text-center spacer-half"><span class="icon-mega
|
||||||
<?php switch($metadata['category']) {
|
<?php switch ($metadata['category']) {
|
||||||
case 'android': echo 'icon-android'; break;
|
case 'android': echo 'icon-android'; break;
|
||||||
case 'osx':
|
case 'osx':
|
||||||
case 'ios':
|
case 'ios':
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<?php if (isset($email)): ?>
|
<?php if (isset($email)): ?>
|
||||||
<a href="mailto:<?php echo $email ?>" class="link-primary"><span class="icon icon-envelope"></span></a>
|
<a href="mailto:<?php echo $email ?>" class="link-primary"><span class="icon icon-envelope"></span></a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (isset ($github)): ?>
|
<?php if (isset($github)): ?>
|
||||||
<a href="https://github.com/<?php echo $github ?>" class="link-primary"><span class="icon icon-github"></span></a>
|
<a href="https://github.com/<?php echo $github ?>" class="link-primary"><span class="icon icon-github"></span></a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (isset($twitter)): ?>
|
<?php if (isset($twitter)): ?>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div>
|
<div>
|
||||||
<?php foreach($jobs as $job): ?>
|
<?php foreach ($jobs as $job): ?>
|
||||||
<?php echo View::render('content/_job', [
|
<?php echo View::render('content/_job', [
|
||||||
'metadata' => $job[0],
|
'metadata' => $job[0],
|
||||||
'jobHtml' => $job[1]
|
'jobHtml' => $job[1]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div>
|
<div>
|
||||||
<h3>Latest News</h3>
|
<h3>Latest News</h3>
|
||||||
<ul class="no-style">
|
<ul class="no-style">
|
||||||
<?php foreach($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<li><a href="<?php echo $post->getRelativeUrl() ?>"><?php echo $post->getTitle() ?></a></li>
|
<li><a href="<?php echo $post->getRelativeUrl() ?>"><?php echo $post->getTitle() ?></a></li>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<a href="http://www.tumblr.com/share?v=3&u=<?php echo $url ?>&t=<?php echo $title ?>&s=" target="_blank" title="Post to Tumblr">
|
<a href="http://www.tumblr.com/share?v=3&u=<?php echo $url ?>&t=<?php echo $title ?>&s=" target="_blank" title="Post to Tumblr">
|
||||||
<span class="icon-fw icon-tumblr"></span>
|
<span class="icon-fw icon-tumblr"></span>
|
||||||
</a>
|
</a>
|
||||||
<a href="mailto:?subject=<?php echo urlencode('LBRY: ') . $title ?>&body=<?php echo $url . urlencode("\n\n" . $post->getContentText(50,true)) ?>"
|
<a href="mailto:?subject=<?php echo urlencode('LBRY: ') . $title ?>&body=<?php echo $url . urlencode("\n\n" . $post->getContentText(50, true)) ?>"
|
||||||
title="Email a Friend">
|
title="Email a Friend">
|
||||||
<span class="icon-fw icon-envelope"></span>
|
<span class="icon-fw icon-envelope"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<?php foreach($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?php echo strtoupper($post->getSlug()) ?></td>
|
<td><?php echo strtoupper($post->getSlug()) ?></td>
|
||||||
<td><a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary">Report</a></td>
|
<td><a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary">Report</a></td>
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
$('#faq-filter-form').change(function() { $(this).submit(); });
|
$('#faq-filter-form').change(function() { $(this).submit(); });
|
||||||
<?php js_end() ?>
|
<?php js_end() ?>
|
||||||
|
|
||||||
<?php foreach($postGroups as $category => $posts): ?>
|
<?php foreach ($postGroups as $category => $posts): ?>
|
||||||
<?php if (count($posts)): ?>
|
<?php if (count($posts)): ?>
|
||||||
<h2><?php echo $categories[$category] ?></h2>
|
<h2><?php echo $categories[$category] ?></h2>
|
||||||
<?php foreach($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<div class="spacer1">
|
<div class="spacer1">
|
||||||
<a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary"><?php echo $post->getTitle() ?></a>
|
<a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary"><?php echo $post->getTitle() ?></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<section class="content content-readable spacer2">
|
<section class="content content-readable spacer2">
|
||||||
<?php foreach($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<div class="spacer1">
|
<div class="spacer1">
|
||||||
<h3><a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary"><?php echo $post->getTitle() ?></a></h3>
|
<h3><a href="<?php echo $post->getRelativeUrl() ?>" class="link-primary"><?php echo $post->getTitle() ?></a></h3>
|
||||||
<div class="meta clearfix" title="<?php echo $post->getDate()->format('F jS, Y') ?>">
|
<div class="meta clearfix" title="<?php echo $post->getDate()->format('F jS, Y') ?>">
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div style="max-width: 800px; margin: 0 auto">
|
<div style="max-width: 800px; margin: 0 auto">
|
||||||
<div class="roadmap-container" id="project-roadmap">
|
<div class="roadmap-container" id="project-roadmap">
|
||||||
<?php foreach($items as $group => $groupItems): ?>
|
<?php foreach ($items as $group => $groupItems): ?>
|
||||||
<?php $firstItem = reset($groupItems) ?>
|
<?php $firstItem = reset($groupItems) ?>
|
||||||
<?php $isOpen = !isset($firstItem['project']) || !isset($firstItem['sort_key']) || $firstItem['sort_key'] === $projectMaxVersions[$firstItem['project']] ?>
|
<?php $isOpen = !isset($firstItem['project']) || !isset($firstItem['sort_key']) || $firstItem['sort_key'] === $projectMaxVersions[$firstItem['project']] ?>
|
||||||
<h2 class="roadmap-group-title" <?php echo !$isOpen ? 'style="display: none"' : '' ?>">
|
<h2 class="roadmap-group-title" <?php echo !$isOpen ? 'style="display: none"' : '' ?>">
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
<?php if (count($groupItems) > $maxItems): ?>
|
<?php if (count($groupItems) > $maxItems): ?>
|
||||||
<div class="text-center spacer1"><a href="javascript:;" class="link-primary show-all-roadmap-group-items">Show All Items for <?php echo $group ?></a></div>
|
<div class="text-center spacer1"><a href="javascript:;" class="link-primary show-all-roadmap-group-items">Show All Items for <?php echo $group ?></a></div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php foreach($groupItems as $item): ?>
|
<?php foreach ($groupItems as $item): ?>
|
||||||
<?php ++$index ?>
|
<?php ++$index ?>
|
||||||
<div class="roadmap-item" <?php echo $index != 1 && isset($firstItem['sort_key']) ? 'style="display: none"' : '' ?>>
|
<div class="roadmap-item" <?php echo $index != 1 && isset($firstItem['sort_key']) ? 'style="display: none"' : '' ?>>
|
||||||
<?php if (isset($item['badge']) || isset($item['assignee'])): ?>
|
<?php if (isset($item['badge']) || isset($item['assignee'])): ?>
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
<span class="roadmap-item-assignee"><?php echo $item['assignee'] ?></span>
|
<span class="roadmap-item-assignee"><?php echo $item['assignee'] ?></span>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (isset($item['badge'])): ?>
|
<?php if (isset($item['badge'])): ?>
|
||||||
<?php switch($item['badge']): case "Complete": ?>
|
<?php switch ($item['badge']): case "Complete": ?>
|
||||||
<span class=" badge badge-primary"><?php echo $item['badge'] ?></span><br/>
|
<span class=" badge badge-primary"><?php echo $item['badge'] ?></span><br/>
|
||||||
<?php break; case "In Progress":?>
|
<?php break; case "In Progress":?>
|
||||||
<span class="badge badge-info"><?php echo $item['badge']?></span><br/>
|
<span class="badge badge-info"><?php echo $item['badge']?></span><br/>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<description>{{rss.description}}</description>
|
<description>{{rss.description}}</description>
|
||||||
<generator>https://github.com/lbryio/lbry.io</generator>
|
<generator>https://github.com/lbryio/lbry.io</generator>
|
||||||
<language>{{rss.lang}}</language>
|
<language>{{rss.lang}}</language>
|
||||||
<?php //<lastBuildDate>Sat, 07 Sep 2002 09:42:31 GMT</lastBuildDate> ?>
|
<?php //<lastBuildDate>Sat, 07 Sep 2002 09:42:31 GMT</lastBuildDate>?>
|
||||||
<atom:link href="<?php echo Request::getHostAndProto() . ContentActions::URL_NEWS . '/' . ContentActions::SLUG_RSS ?>" rel="self" type="application/rss+xml" />
|
<atom:link href="<?php echo Request::getHostAndProto() . ContentActions::URL_NEWS . '/' . ContentActions::SLUG_RSS ?>" rel="self" type="application/rss+xml" />
|
||||||
<?php foreach ($posts as $post): ?>
|
<?php foreach ($posts as $post): ?>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<div class="meta"><a href="/quickstart" class="link-primary">Quickstart Home</a></div>
|
<div class="meta"><a href="/quickstart" class="link-primary">Quickstart Home</a></div>
|
||||||
<h1>Quickstart</h1>
|
<h1>Quickstart</h1>
|
||||||
</div>
|
</div>
|
||||||
<?php foreach(array_filter(array_keys($stepLabels)) as $step): ?>
|
<?php foreach (array_filter(array_keys($stepLabels)) as $step): ?>
|
||||||
<section>
|
<section>
|
||||||
<div class="content content-dark">
|
<div class="content content-dark">
|
||||||
<?php echo View::render('developer/_quickstart' . ucfirst($step)) ?>
|
<?php echo View::render('developer/_quickstart' . ucfirst($step)) ?>
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
</div>
|
</div>
|
||||||
<ol class="quickstart__progress-bar">
|
<ol class="quickstart__progress-bar">
|
||||||
<?php $stepCounter = 0 ?>
|
<?php $stepCounter = 0 ?>
|
||||||
<?php foreach($stepLabels as $step => $stepLabel): ?>
|
<?php foreach ($stepLabels as $step => $stepLabel): ?>
|
||||||
<li class="<?php echo $currentStep == $step ? 'active' : '' ?> <?php echo ++$stepCounter <= $stepNum ? 'completed' : '' ?>">
|
<li class="<?php echo $currentStep == $step ? 'active' : '' ?> <?php echo ++$stepCounter <= $stepNum ? 'completed' : '' ?>">
|
||||||
<a href="/quickstart<?php echo $step ? '/' . $step : '' ?>"><?php echo $stepLabel ?></a>
|
<a href="/quickstart<?php echo $step ? '/' . $step : '' ?>"><?php echo $stepLabel ?></a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<?php $buckets = array_fill(0, 3, []) ?>
|
<?php $buckets = array_fill(0, 3, []) ?>
|
||||||
<?php $columns = 2 ?>
|
<?php $columns = 2 ?>
|
||||||
<?php $index = 0 ?>
|
<?php $index = 0 ?>
|
||||||
<?php foreach($osChoices as $osChoice): ?>
|
<?php foreach ($osChoices as $osChoice): ?>
|
||||||
<?php ob_start() ?>
|
<?php ob_start() ?>
|
||||||
<?php list($url, $title, $icon) = $osChoice ?>
|
<?php list($url, $title, $icon) = $osChoice ?>
|
||||||
<h4>
|
<h4>
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
</h4>
|
</h4>
|
||||||
<?php $buckets[floor($index++ / $columns)][] = ob_get_clean() ?>
|
<?php $buckets[floor($index++ / $columns)][] = ob_get_clean() ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php foreach(array_filter($buckets) as $bucketRow): ?>
|
<?php foreach (array_filter($buckets) as $bucketRow): ?>
|
||||||
<div class="row-fluid-always">
|
<div class="row-fluid-always">
|
||||||
<div class="span6"><?php echo implode('</div><div class="span6">', $bucketRow) ?></div>
|
<div class="span6"><?php echo implode('</div><div class="span6">', $bucketRow) ?></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,4 +13,4 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<?php echo View::render('email_templates/_base', ['body' => ob_get_clean()]);
|
<?php echo View::render('email_templates/_base', ['body' => ob_get_clean()]);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<select name="<?php echo $name ?>">
|
<select name="<?php echo $name ?>">
|
||||||
<?php foreach($choices as $value => $label): ?>
|
<?php foreach ($choices as $value => $label): ?>
|
||||||
<option value="<?php echo $value ?>" <?php echo $selected == $value ? 'selected="selected"' : '' ?>>
|
<option value="<?php echo $value ?>" <?php echo $selected == $value ? 'selected="selected"' : '' ?>>
|
||||||
<?php echo $label ?>
|
<?php echo $label ?>
|
||||||
</option>
|
</option>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo json_encode($json ?? [], JSON_PRETTY_PRINT) ?>
|
<?php echo json_encode($json ?? [], JSON_PRETTY_PRINT);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo file_get_contents($zipPath) ?>
|
<?php echo file_get_contents($zipPath);
|
||||||
|
|
|
@ -6,7 +6,7 @@ h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
|
||||||
})(window,document.documentElement,'async-hide','dataLayer',4000,
|
})(window,document.documentElement,'async-hide','dataLayer',4000,
|
||||||
{'GTM-NT8579P':true});</script>
|
{'GTM-NT8579P':true});</script>
|
||||||
<script>
|
<script>
|
||||||
<?php //google analytics ?>
|
<?php //google analytics?>
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<title><?php echo $title ?></title>
|
<title><?php echo $title ?></title>
|
||||||
|
|
||||||
<link href='https://fonts.googleapis.com/css?family=Raleway:500,500italic,700' rel='stylesheet' type='text/css'>
|
<link href='https://fonts.googleapis.com/css?family=Raleway:500,500italic,700' rel='stylesheet' type='text/css'>
|
||||||
<?php foreach(Response::getCssAssets() as $src): ?>
|
<?php foreach (Response::getCssAssets() as $src): ?>
|
||||||
<link rel="stylesheet" type="text/css" href="<?php echo $src?>">
|
<link rel="stylesheet" type="text/css" href="<?php echo $src?>">
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/img/fav/apple-touch-icon-60x60.png">
|
<link rel="apple-touch-icon" sizes="60x60" href="/img/fav/apple-touch-icon-60x60.png">
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<link rel="icon" type="image/png" href="/img/fav/android-chrome-192x192.png" sizes="192x192">
|
<link rel="icon" type="image/png" href="/img/fav/android-chrome-192x192.png" sizes="192x192">
|
||||||
<link rel="icon" type="image/png" href="/img/fav/favicon-16x16.png" sizes="16x16">
|
<link rel="icon" type="image/png" href="/img/fav/favicon-16x16.png" sizes="16x16">
|
||||||
<link rel="manifest" href="/img/fav/manifest.json">
|
<link rel="manifest" href="/img/fav/manifest.json">
|
||||||
<?php if(isset($showRssLink) && $showRssLink): ?>
|
<?php if (isset($showRssLink) && $showRssLink): ?>
|
||||||
<link rel="alternate" type="application/rss+xml" title="LBRY News" href="<?php echo ContentActions::URL_NEWS . '/' . ContentActions::SLUG_RSS ?>" />
|
<link rel="alternate" type="application/rss+xml" title="LBRY News" href="<?php echo ContentActions::URL_NEWS . '/' . ContentActions::SLUG_RSS ?>" />
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
<meta property="og:type" content="article" />
|
<meta property="og:type" content="article" />
|
||||||
<meta property="og:description" content="<?php echo Response::getMetaDescription() ?>"/>
|
<meta property="og:description" content="<?php echo Response::getMetaDescription() ?>"/>
|
||||||
<meta property="og:site_name" content="LBRY" />
|
<meta property="og:site_name" content="LBRY" />
|
||||||
<?php foreach(Response::getMetaImages() as $image): ?>
|
<?php foreach (Response::getMetaImages() as $image): ?>
|
||||||
<meta property="og:image" content="<?php echo $image ?>" />
|
<meta property="og:image" content="<?php echo $image ?>" />
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<script id="facebook-jssdk" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5&appId=1477813539180850"></script>
|
<script id="facebook-jssdk" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5&appId=1477813539180850"></script>
|
||||||
<script id="twitter-oct" src="https://platform.twitter.com/oct.js"></script>
|
<script id="twitter-oct" src="https://platform.twitter.com/oct.js"></script>
|
||||||
<script id="twitter-wjs" src="https://platform.twitter.com/widgets.js"></script>
|
<script id="twitter-wjs" src="https://platform.twitter.com/widgets.js"></script>
|
||||||
<?php foreach(Response::getJsAssets() as $src): ?>
|
<?php foreach (Response::getJsAssets() as $src): ?>
|
||||||
<script src="<?php echo $src ?>"></script>
|
<script src="<?php echo $src ?>"></script>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php echo View::render('layout/_analytics') ?>
|
<?php echo View::render('layout/_analytics') ?>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?php foreach([
|
<?php foreach ([
|
||||||
'/get' => __('nav.get'),
|
'/get' => __('nav.get'),
|
||||||
'/learn' => __('nav.learn'),
|
'/learn' => __('nav.learn'),
|
||||||
'/news' => __("News")
|
'/news' => __("News")
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<h3 id="images">{{press.logos}}</h3>
|
<h3 id="images">{{press.logos}}</h3>
|
||||||
<div class="column-fluid">
|
<div class="column-fluid">
|
||||||
<?php foreach(glob(ROOT_DIR . '/web/img/press/*') as $imgPath): ?>
|
<?php foreach (glob(ROOT_DIR . '/web/img/press/*') as $imgPath): ?>
|
||||||
<div class="span6">
|
<div class="span6">
|
||||||
<div style="margin: 10px">
|
<div style="margin: 10px">
|
||||||
<?php $imgUrl = str_replace(ROOT_DIR . '/web', '', $imgPath) ?>
|
<?php $imgUrl = str_replace(ROOT_DIR . '/web', '', $imgPath) ?>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>{{press.team}}</h3>
|
<h3>{{press.team}}</h3>
|
||||||
<?php foreach(['jeremy-kauffman', 'josh-finer', 'alex-grintsvayg', 'jack-robison'] as $person): ?>
|
<?php foreach (['jeremy-kauffman', 'josh-finer', 'alex-grintsvayg', 'jack-robison'] as $person): ?>
|
||||||
<?php list($metadata, $bioHtml) = View::parseMarkdown('bio/' . $person . '.md') ?>
|
<?php list($metadata, $bioHtml) = View::parseMarkdown('bio/' . $person . '.md') ?>
|
||||||
<section class="row-fluid">
|
<section class="row-fluid">
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
</section>
|
</section>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<h3>{{press.advisory}}</h3>
|
<h3>{{press.advisory}}</h3>
|
||||||
<?php foreach(['alex-tabarrok', 'ray-carballada', 'stephan-kinsella', 'michael-huemer'] as $person): ?>
|
<?php foreach (['alex-tabarrok', 'ray-carballada', 'stephan-kinsella', 'michael-huemer'] as $person): ?>
|
||||||
<?php list($metadata, $bioHtml) = View::parseMarkdown('bio/' . $person . '.md') ?>
|
<?php list($metadata, $bioHtml) = View::parseMarkdown('bio/' . $person . '.md') ?>
|
||||||
<section class="row-fluid">
|
<section class="row-fluid">
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
|
|
|
@ -17,20 +17,20 @@
|
||||||
<a href="/join-us" class="link-primary">See our hiring page</a>.
|
<a href="/join-us" class="link-primary">See our hiring page</a>.
|
||||||
</div>
|
</div>
|
||||||
<h2>Leadership</h2>
|
<h2>Leadership</h2>
|
||||||
<?php foreach(['jeremy-kauffman', 'alex-grintsvayg'] as $bioSlug): ?>
|
<?php foreach (['jeremy-kauffman', 'alex-grintsvayg'] as $bioSlug): ?>
|
||||||
<div class="spacer2">
|
<div class="spacer2">
|
||||||
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<h2>Technical</h2>
|
<h2>Technical</h2>
|
||||||
<?php foreach([ 'kay-kurokawa', 'jack-robison', 'lex-berezhny',
|
<?php foreach ([ 'kay-kurokawa', 'jack-robison', 'lex-berezhny',
|
||||||
'akinwale-ariwodola', 'sean-yesmunt', 'liam-cardenas', 'bill-bittner', 'amit-tulshyan', 'igor-gassmann'] as $bioSlug): ?>
|
'akinwale-ariwodola', 'sean-yesmunt', 'liam-cardenas', 'bill-bittner', 'amit-tulshyan', 'igor-gassmann'] as $bioSlug): ?>
|
||||||
<div class="spacer2">
|
<div class="spacer2">
|
||||||
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<h2>Business</h2>
|
<h2>Business</h2>
|
||||||
<?php foreach(['josh-finer',
|
<?php foreach (['josh-finer',
|
||||||
'natalie-mitchell',
|
'natalie-mitchell',
|
||||||
'reilly-smith',
|
'reilly-smith',
|
||||||
'tom-zarebczan',
|
'tom-zarebczan',
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<h2>{{page.team.advisory}}</h2>
|
<h2>{{page.team.advisory}}</h2>
|
||||||
<?php foreach(['alex-tabarrok', 'ray-carballada', 'stephan-kinsella', 'michael-huemer'] as $bioSlug): ?>
|
<?php foreach (['alex-tabarrok', 'ray-carballada', 'stephan-kinsella', 'michael-huemer'] as $bioSlug): ?>
|
||||||
<div class="spacer2">
|
<div class="spacer2">
|
||||||
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
<?php echo View::render('content/_bio', ['person' => $bioSlug]) ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
# Enable PHP dev cli-server
|
# Enable PHP dev cli-server
|
||||||
if (php_sapi_name() === 'cli-server' && is_file(__DIR__.preg_replace('#(\?.*)$#', '', $_SERVER['REQUEST_URI'])))
|
if (php_sapi_name() === 'cli-server' && is_file(__DIR__.preg_replace('#(\?.*)$#', '', $_SERVER['REQUEST_URI']))) {
|
||||||
{
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
include __DIR__ . '/../bootstrap.php';
|
include __DIR__ . '/../bootstrap.php';
|
||||||
|
@ -15,32 +14,26 @@ error_reporting(IS_PRODUCTION ? 0 : (E_ALL | E_STRICT));
|
||||||
|
|
||||||
register_shutdown_function('Controller::shutdown');
|
register_shutdown_function('Controller::shutdown');
|
||||||
|
|
||||||
if (!IS_PRODUCTION)
|
if (!IS_PRODUCTION) {
|
||||||
{
|
// make warnings into errors
|
||||||
// make warnings into errors
|
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
||||||
set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
|
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
|
||||||
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
|
}, E_WARNING|E_CORE_WARNING|E_COMPILE_WARNING|E_USER_WARNING);
|
||||||
}, E_WARNING|E_CORE_WARNING|E_COMPILE_WARNING|E_USER_WARNING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
Session::init();
|
||||||
Session::init();
|
i18n::register();
|
||||||
i18n::register();
|
if (!IS_PRODUCTION) {
|
||||||
if (!IS_PRODUCTION)
|
View::compileCss();
|
||||||
{
|
}
|
||||||
View::compileCss();
|
Controller::dispatch(Request::getRoutingUri());
|
||||||
}
|
} catch (Throwable $e) {
|
||||||
Controller::dispatch(Request::getRoutingUri());
|
if (IS_PRODUCTION) {
|
||||||
}
|
Slack::sendErrorIfProd($e);
|
||||||
catch(Throwable $e)
|
throw $e;
|
||||||
{
|
}
|
||||||
if (IS_PRODUCTION)
|
|
||||||
{
|
|
||||||
Slack::sendErrorIfProd($e);
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo '<pre>'.Debug::exceptionToString($e).'</pre>';
|
echo '<pre>'.Debug::exceptionToString($e).'</pre>';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue