1<?php 2/** 3 * This file is part of RSS-Bridge, a PHP project capable of generating RSS and 4 * Atom feeds for websites that don't have one. 5 * 6 * For the full license information, please view the UNLICENSE file distributed 7 * with this source code. 8 * 9 * @package Core 10 * @license http://unlicense.org/ UNLICENSE 11 * @link https://github.com/rss-bridge/rss-bridge 12 */ 13 14/** 15 * A generator class for a single bridge card on the home page of RSS-Bridge. 16 * 17 * This class generates the HTML content for a single bridge card for the home 18 * page of RSS-Bridge. 19 * 20 * @todo Return error if a caller creates an object of this class. 21 */ 22final class BridgeCard { 23 /** 24 * Build a HTML document string of buttons for each of the provided formats 25 * 26 * @param array $formats A list of format names 27 * @return string The document string 28 */ 29 private static function buildFormatButtons($formats) { 30 $buttons = ''; 31 32 foreach($formats as $name) { 33 $buttons .= '<button type="submit" name="format" value="' 34 . $name 35 . '">' 36 . $name 37 . '</button>' 38 . PHP_EOL; 39 } 40 41 return $buttons; 42 } 43 44 /** 45 * Get the form header for a bridge card 46 * 47 * @param string $bridgeName The bridge name 48 * @param bool $isHttps If disabled, adds a warning to the form 49 * @return string The form header 50 */ 51 private static function getFormHeader($bridgeName, $isHttps = false, $parameterName = '') { 52 $form = <<<EOD 53 <form method="GET" action="?"> 54 <input type="hidden" name="action" value="display" /> 55 <input type="hidden" name="bridge" value="{$bridgeName}" /> 56EOD; 57 58 if(!empty($parameterName)) { 59 $form .= <<<EOD 60 <input type="hidden" name="context" value="{$parameterName}" /> 61EOD; 62 } 63 64 if(!$isHttps) { 65 $form .= '<div class="secure-warning">Warning : 66This bridge is not fetching its content through a secure connection</div>'; 67 } 68 69 return $form; 70 } 71 72 /** 73 * Get the form body for a bridge 74 * 75 * @param string $bridgeName The bridge name 76 * @param array $formats A list of supported formats 77 * @param bool $isActive Indicates if a bridge is enabled or not 78 * @param bool $isHttps Indicates if a bridge uses HTTPS or not 79 * @param string $parameterName Sets the bridge context for the current form 80 * @param array $parameters The bridge parameters 81 * @return string The form body 82 */ 83 private static function getForm($bridgeName, 84 $formats, 85 $isActive = false, 86 $isHttps = false, 87 $parameterName = '', 88 $parameters = array()) { 89 $form = self::getFormHeader($bridgeName, $isHttps, $parameterName); 90 91 if(count($parameters) > 0) { 92 93 $form .= '<div class="parameters">'; 94 95 foreach($parameters as $id => $inputEntry) { 96 if(!isset($inputEntry['exampleValue'])) 97 $inputEntry['exampleValue'] = ''; 98 99 if(!isset($inputEntry['defaultValue'])) 100 $inputEntry['defaultValue'] = ''; 101 102 $idArg = 'arg-' 103 . urlencode($bridgeName) 104 . '-' 105 . urlencode($parameterName) 106 . '-' 107 . urlencode($id); 108 109 $form .= '<label for="' 110 . $idArg 111 . '">' 112 . filter_var($inputEntry['name'], FILTER_SANITIZE_STRING) 113 . '</label>' 114 . PHP_EOL; 115 116 if(!isset($inputEntry['type']) || $inputEntry['type'] === 'text') { 117 $form .= self::getTextInput($inputEntry, $idArg, $id); 118 } elseif($inputEntry['type'] === 'number') { 119 $form .= self::getNumberInput($inputEntry, $idArg, $id); 120 } else if($inputEntry['type'] === 'list') { 121 $form .= self::getListInput($inputEntry, $idArg, $id); 122 } elseif($inputEntry['type'] === 'checkbox') { 123 $form .= self::getCheckboxInput($inputEntry, $idArg, $id); 124 } 125 126 if(isset($inputEntry['title'])) 127 $form .= '<i class="info" title="' . filter_var($inputEntry['title'], FILTER_SANITIZE_STRING) . '">i</i>'; 128 else 129 $form .= '<i class="no-info"></i>'; 130 } 131 132 $form .= '</div>'; 133 134 } 135 136 if($isActive) { 137 $form .= self::buildFormatButtons($formats); 138 } else { 139 $form .= '<span style="font-weight: bold;">Inactive</span>'; 140 } 141 142 return $form . '</form>' . PHP_EOL; 143 } 144 145 /** 146 * Get input field attributes 147 * 148 * @param array $entry The current entry 149 * @return string The input field attributes 150 */ 151 private static function getInputAttributes($entry) { 152 $retVal = ''; 153 154 if(isset($entry['required']) && $entry['required'] === true) 155 $retVal .= ' required'; 156 157 if(isset($entry['pattern'])) 158 $retVal .= ' pattern="' . $entry['pattern'] . '"'; 159 160 return $retVal; 161 } 162 163 /** 164 * Get text input 165 * 166 * @param array $entry The current entry 167 * @param string $id The field ID 168 * @param string $name The field name 169 * @return string The text input field 170 */ 171 private static function getTextInput($entry, $id, $name) { 172 return '<input ' 173 . self::getInputAttributes($entry) 174 . ' id="' 175 . $id 176 . '" type="text" value="' 177 . filter_var($entry['defaultValue'], FILTER_SANITIZE_STRING) 178 . '" placeholder="' 179 . filter_var($entry['exampleValue'], FILTER_SANITIZE_STRING) 180 . '" name="' 181 . $name 182 . '" />' 183 . PHP_EOL; 184 } 185 186 /** 187 * Get number input 188 * 189 * @param array $entry The current entry 190 * @param string $id The field ID 191 * @param string $name The field name 192 * @return string The number input field 193 */ 194 private static function getNumberInput($entry, $id, $name) { 195 return '<input ' 196 . self::getInputAttributes($entry) 197 . ' id="' 198 . $id 199 . '" type="number" value="' 200 . filter_var($entry['defaultValue'], FILTER_SANITIZE_NUMBER_INT) 201 . '" placeholder="' 202 . filter_var($entry['exampleValue'], FILTER_SANITIZE_NUMBER_INT) 203 . '" name="' 204 . $name 205 . '" />' 206 . PHP_EOL; 207 } 208 209 /** 210 * Get list input 211 * 212 * @param array $entry The current entry 213 * @param string $id The field ID 214 * @param string $name The field name 215 * @return string The list input field 216 */ 217 private static function getListInput($entry, $id, $name) { 218 if(isset($entry['required']) && $entry['required'] === true) { 219 Debug::log('The "required" attribute is not supported for lists.'); 220 unset($entry['required']); 221 } 222 223 $list = '<select ' 224 . self::getInputAttributes($entry) 225 . ' id="' 226 . $id 227 . '" name="' 228 . $name 229 . '" >'; 230 231 foreach($entry['values'] as $name => $value) { 232 if(is_array($value)) { 233 $list .= '<optgroup label="' . htmlentities($name) . '">'; 234 foreach($value as $subname => $subvalue) { 235 if($entry['defaultValue'] === $subname 236 || $entry['defaultValue'] === $subvalue) { 237 $list .= '<option value="' 238 . $subvalue 239 . '" selected>' 240 . $subname 241 . '</option>'; 242 } else { 243 $list .= '<option value="' 244 . $subvalue 245 . '">' 246 . $subname 247 . '</option>'; 248 } 249 } 250 $list .= '</optgroup>'; 251 } else { 252 if($entry['defaultValue'] === $name 253 || $entry['defaultValue'] === $value) { 254 $list .= '<option value="' 255 . $value 256 . '" selected>' 257 . $name 258 . '</option>'; 259 } else { 260 $list .= '<option value="' 261 . $value 262 . '">' 263 . $name 264 . '</option>'; 265 } 266 } 267 } 268 269 $list .= '</select>'; 270 271 return $list; 272 } 273 274 /** 275 * Get checkbox input 276 * 277 * @param array $entry The current entry 278 * @param string $id The field ID 279 * @param string $name The field name 280 * @return string The checkbox input field 281 */ 282 private static function getCheckboxInput($entry, $id, $name) { 283 if(isset($entry['required']) && $entry['required'] === true) { 284 Debug::log('The "required" attribute is not supported for checkboxes.'); 285 unset($entry['required']); 286 } 287 288 return '<input ' 289 . self::getInputAttributes($entry) 290 . ' id="' 291 . $id 292 . '" type="checkbox" name="' 293 . $name 294 . '" ' 295 . ($entry['defaultValue'] === 'checked' ? 'checked' : '') 296 . ' />' 297 . PHP_EOL; 298 } 299 300 /** 301 * Gets a single bridge card 302 * 303 * @param string $bridgeName The bridge name 304 * @param array $formats A list of formats 305 * @param bool $isActive Indicates if the bridge is active or not 306 * @return string The bridge card 307 */ 308 static function displayBridgeCard($bridgeName, $formats, $isActive = true){ 309 310 $bridgeFac = new \BridgeFactory(); 311 $bridgeFac->setWorkingDir(PATH_LIB_BRIDGES); 312 313 $bridge = $bridgeFac->create($bridgeName); 314 315 if($bridge == false) 316 return ''; 317 318 $isHttps = strpos($bridge->getURI(), 'https') === 0; 319 320 $uri = $bridge->getURI(); 321 $name = $bridge->getName(); 322 $icon = $bridge->getIcon(); 323 $description = $bridge->getDescription(); 324 $parameters = $bridge->getParameters(); 325 326 if(defined('PROXY_URL') && PROXY_BYBRIDGE) { 327 $parameters['global']['_noproxy'] = array( 328 'name' => 'Disable proxy (' . ((defined('PROXY_NAME') && PROXY_NAME) ? PROXY_NAME : PROXY_URL) . ')', 329 'type' => 'checkbox' 330 ); 331 } 332 333 if(CUSTOM_CACHE_TIMEOUT) { 334 $parameters['global']['_cache_timeout'] = array( 335 'name' => 'Cache timeout in seconds', 336 'type' => 'number', 337 'defaultValue' => $bridge->getCacheTimeout() 338 ); 339 } 340 341 $card = <<<CARD 342 <section id="bridge-{$bridgeName}" data-ref="{$bridgeName}"> 343 <h2><a href="{$uri}">{$name}</a></h2> 344 <p class="description">{$description}</p> 345 <input type="checkbox" class="showmore-box" id="showmore-{$bridgeName}" /> 346 <label class="showmore" for="showmore-{$bridgeName}">Show more</label> 347CARD; 348 349 // If we don't have any parameter for the bridge, we print a generic form to load it. 350 if (count($parameters) === 0) { 351 $card .= self::getForm($bridgeName, $formats, $isActive, $isHttps); 352 353 // Display form with cache timeout and/or noproxy options (if enabled) when bridge has no parameters 354 } else if (count($parameters) === 1 && array_key_exists('global', $parameters)) { 355 $card .= self::getForm($bridgeName, $formats, $isActive, $isHttps, '', $parameters['global']); 356 357 } else { 358 359 foreach($parameters as $parameterName => $parameter) { 360 if(!is_numeric($parameterName) && $parameterName === 'global') 361 continue; 362 363 if(array_key_exists('global', $parameters)) 364 $parameter = array_merge($parameter, $parameters['global']); 365 366 if(!is_numeric($parameterName)) 367 $card .= '<h5>' . $parameterName . '</h5>' . PHP_EOL; 368 369 $card .= self::getForm($bridgeName, $formats, $isActive, $isHttps, $parameterName, $parameter); 370 } 371 372 } 373 374 $card .= '<label class="showless" for="showmore-' . $bridgeName . '">Show less</label>'; 375 $card .= '<p class="maintainer">' . $bridge->getMaintainer() . '</p>'; 376 $card .= '</section>'; 377 378 return $card; 379 } 380} 381