007ee4d858
Commit e26d61e
introduced a bug that causes the error message "The
bridge you [sic!] looking for does not exist." if the bridge name
specified in the query ends on "Bridge"
(i.e. '&bridge=SoundcloudBridge'), while other queries work fine
(i.e. '&bridge=Soundcloud').
This commit fixes that issue by sanitizing the bridge name before
creating the class.
References #922
167 lines
4.1 KiB
PHP
167 lines
4.1 KiB
PHP
<?php
|
|
|
|
class Bridge {
|
|
|
|
static protected $dirBridge;
|
|
|
|
/**
|
|
* Holds the active whitelist.
|
|
* Use Bridge::getWhitelist() instead of accessing this parameter directly!
|
|
*/
|
|
private static $whitelist = array();
|
|
|
|
public function __construct(){
|
|
throw new \LogicException('Please use ' . __CLASS__ . '::create for new object.');
|
|
}
|
|
|
|
/**
|
|
* Create a new bridge object
|
|
* @param string $nameBridge Defined bridge name you want use
|
|
* @return Bridge object dedicated
|
|
*/
|
|
static public function create($nameBridge){
|
|
if(!preg_match('@^[A-Z][a-zA-Z0-9-]*$@', $nameBridge)) {
|
|
$message = <<<EOD
|
|
'nameBridge' must start with one uppercase character followed or not by
|
|
alphanumeric or dash characters!
|
|
EOD;
|
|
throw new \InvalidArgumentException($message);
|
|
}
|
|
|
|
$nameBridge = Bridge::sanitizeBridgeName($nameBridge) . 'Bridge';
|
|
$pathBridge = self::getDir() . $nameBridge . '.php';
|
|
|
|
if(!file_exists($pathBridge)) {
|
|
throw new \Exception('The bridge you are looking for does not exist. It should be at path '
|
|
. $pathBridge);
|
|
}
|
|
|
|
require_once $pathBridge;
|
|
|
|
if((new ReflectionClass($nameBridge))->isInstantiable()) {
|
|
return new $nameBridge();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static public function setDir($dirBridge){
|
|
if(!is_string($dirBridge)) {
|
|
throw new \InvalidArgumentException('Dir bridge must be a string.');
|
|
}
|
|
|
|
if(!file_exists($dirBridge)) {
|
|
throw new \Exception('Dir bridge does not exist.');
|
|
}
|
|
|
|
self::$dirBridge = $dirBridge;
|
|
}
|
|
|
|
static public function getDir(){
|
|
if(is_null(self::$dirBridge)) {
|
|
throw new \LogicException(__CLASS__ . ' class need to know bridge path !');
|
|
}
|
|
|
|
return self::$dirBridge;
|
|
}
|
|
|
|
/**
|
|
* Lists the available bridges.
|
|
* @return array List of the bridges
|
|
*/
|
|
static public function listBridges(){
|
|
|
|
static $listBridge = array(); // Initialized on first call
|
|
|
|
if(empty($listBridge)) {
|
|
$dirFiles = scandir(self::getDir());
|
|
|
|
if($dirFiles !== false) {
|
|
foreach($dirFiles as $fileName) {
|
|
if(preg_match('@^([^.]+)Bridge\.php$@U', $fileName, $out)) {
|
|
$listBridge[] = $out[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $listBridge;
|
|
}
|
|
|
|
/**
|
|
* @return bool Returns true if the given bridge is whitelisted.
|
|
*/
|
|
static public function isWhitelisted($name){
|
|
return in_array(Bridge::sanitizeBridgeName($name), Bridge::getWhitelist());
|
|
}
|
|
|
|
/**
|
|
* On first call reads the whitelist from WHITELIST. Each line in the file
|
|
* specifies one bridge that will be placed on the whitelist. An empty file
|
|
* disables all bridges. '*' enables all bridges.
|
|
*
|
|
* @return array Returns a list of whitelisted bridges
|
|
*/
|
|
public static function getWhitelist() {
|
|
|
|
static $firstCall = true; // Initialized on first call
|
|
|
|
if($firstCall) {
|
|
|
|
// Create initial whitelist or load from disk
|
|
if (!file_exists(WHITELIST) && !empty(Bridge::$whitelist)) {
|
|
file_put_contents(WHITELIST, implode("\n", Bridge::$whitelist));
|
|
} else {
|
|
|
|
$contents = trim(file_get_contents(WHITELIST));
|
|
|
|
if($contents === '*') { // Whitelist all bridges
|
|
Bridge::$whitelist = Bridge::listBridges();
|
|
} else {
|
|
Bridge::$whitelist = array_map('Bridge::sanitizeBridgeName', explode("\n", $contents));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Bridge::$whitelist;
|
|
|
|
}
|
|
|
|
public static function setWhitelist($default = array()) {
|
|
Bridge::$whitelist = array_map('Bridge::sanitizeBridgeName', $default);
|
|
}
|
|
|
|
/**
|
|
* @return string Returns a sanitized bridge name if the given name has been
|
|
* found valid, null otherwise.
|
|
*/
|
|
private static function sanitizeBridgeName($name) {
|
|
|
|
if(is_string($name)) {
|
|
|
|
// Trim trailing '.php' if exists
|
|
if(preg_match('/(.+)(?:\.php)/', $name, $matches)) {
|
|
$name = $matches[1];
|
|
}
|
|
|
|
// Trim trailing 'Bridge' if exists
|
|
if(preg_match('/(.+)(?:Bridge)/i', $name, $matches)) {
|
|
$name = $matches[1];
|
|
}
|
|
|
|
// The name is valid if a corresponding bridge file is found on disk
|
|
if(in_array(strtolower($name), array_map('strtolower', Bridge::listBridges()))) {
|
|
$index = array_search(strtolower($name), array_map('strtolower', Bridge::listBridges()));
|
|
return Bridge::listBridges()[$index];
|
|
}
|
|
|
|
Debug::log('Invalid bridge name specified: "' . $name . '"!');
|
|
|
|
}
|
|
|
|
return null; // Bad parameter
|
|
|
|
}
|
|
}
|