PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/server/update-bridge.php

https://gitlab.com/daniel.ritz/update-bridge
PHP | 398 lines | 218 code | 57 blank | 123 comment | 40 complexity | af38746fc7f0eaf3bccd34a72487ff24 MD5 | raw file
  1. <?php
  2. ini_set("output_buffering", "Off");
  3. /**
  4. * Update-Bridge
  5. * @author darita
  6. * @version 0.2 Direwolf
  7. *
  8. * This script is used to push HotFixes and Daily Updates of files to an webpage
  9. */
  10. /**
  11. * Update-Bridge class
  12. *
  13. * Base class for Update-Bridge
  14. */
  15. class UpdateBridge{
  16. /** @var Array Contains the credentials for a logon */
  17. private $credentials;
  18. /** @var Array Contains all rewrite rules */
  19. private $rewriteRules;
  20. /** @var Bool Are the credentials OK? */
  21. private $credentialsOK;
  22. /** @var String Contains the error code */
  23. public $errorCode;
  24. /** @var bool Must the file be extraced before flash? */
  25. public $extractFile;
  26. /**
  27. * Init the object
  28. *
  29. * Call loading functions
  30. */
  31. function __construct(){
  32. $this -> errorCode = "";
  33. $this -> extractFile = false;
  34. $this -> credentialsOK = false;
  35. $this -> credentials = Array();
  36. $this -> rewriteRules = Array();
  37. $this -> loadCredentials();
  38. $this -> loadRewriteRules();
  39. }
  40. /**
  41. * Throw an error
  42. *
  43. * @param string $code Errorcode for further review
  44. * @return void
  45. */
  46. function throwError($code){
  47. $this -> errorCode .= $code . "\n";
  48. }
  49. /**
  50. * Set the User/Password credentials for those who will get access
  51. *
  52. * Add User and Password pairs to the credentials element
  53. * Every User/PW pair will get access to modify things
  54. *
  55. * @example $this -> credentials[] = Array('user' => 'USERNAME', 'pw' => 'PASSWORD');
  56. *
  57. * @return void
  58. */
  59. function loadCredentials(){
  60. $this -> credentials[] = Array('user' => 'sample', 'pw' => 'xxx');
  61. }
  62. /**
  63. * Set the Rewrite Rules
  64. *
  65. * Add Searchpattern and Replacepattern to the rewriteRules element
  66. * Search/Replacepatterns will be parsed with regex (preg_replace)
  67. *
  68. * @example $this -> rewriteRules[] = Array('search' => 'SEARCHPATTERN', 'replace' => 'REPLACEPATTERN');
  69. *
  70. * @return void
  71. */
  72. function loadRewriteRules(){
  73. // $this -> rewriteRules[] = Array('search' => '/^@vpl$/', 'replace' => '/content/vpl.php');
  74. }
  75. /**
  76. * Check the given credentials
  77. *
  78. * Check if the given credentials compare to the stored ones
  79. *
  80. * @return bool true if credentials are correct, false if credentials are wrong
  81. */
  82. function checkCredentials($user, $pw){
  83. $access = false;
  84. foreach($this -> credentials as $credential){
  85. if(($credential['user'] == $user)&&($credential['pw'] == $pw)){
  86. $access = true;
  87. }
  88. }
  89. if($access){
  90. $this -> credentialsOK = true; // The Credentials are OK
  91. }else{
  92. $this -> credentialsOK = false;
  93. }
  94. return $access;
  95. }
  96. /**
  97. * Rewrites a given path based on rewriteRules
  98. *
  99. * Rewrites the given path with preg_replace and the rewriteRules
  100. *
  101. * @param string $path The given path
  102. * @return string The rewritten path
  103. */
  104. function rewritePath($path){
  105. $retpath = $path;
  106. foreach ($this -> rewriteRules as $rewriteRule) {
  107. if(preg_match($rewriteRule['search'], $retpath)){
  108. $retpath = preg_replace($rewriteRule['search'], $rewriteRule['replace'], $retpath);
  109. }
  110. }
  111. return $retpath;
  112. }
  113. /**
  114. * Flash the new update
  115. *
  116. * Flash the uploaded files to their destination
  117. *
  118. * @param string $path Path to flash the file in
  119. *
  120. * @return bool true if the file could be flashed, file if not
  121. */
  122. function flash($path){
  123. if(!$this -> credentialsOK){
  124. $this -> throwError("0x1 Credentials were wrong");
  125. return false;
  126. }
  127. $path = getcwd() . '/' . $this -> rewritePath($path);
  128. if(count($_FILES) == 1){
  129. // There is only one file, let's use the $path var as the whole filename
  130. foreach($_FILES as $file){
  131. if($this -> extractFile){
  132. $this -> flashExtract($path, $file);
  133. }else{
  134. // Don't Extract the file
  135. $flashScript = $this -> loadFlashScript($path);
  136. if($flashScript != null){
  137. if($flashScript -> preFlash($path) == false){ // Start preFlash
  138. // Returned false: Quit flashing
  139. continue;
  140. }
  141. }
  142. if(($flashScript != null)&&($flashScript -> overrideFlash)){
  143. // Override flash function
  144. $flashScript -> flash($file['tmp_name'], $path);
  145. }else{
  146. move_uploaded_file($file['tmp_name'], $path);
  147. }
  148. if($flashScript != null){
  149. $flashScript -> postFlash($path); // Start postFlash
  150. }
  151. }
  152. }
  153. }else{
  154. // There is more than one file, let's use the $path as root path and use the given filenames
  155. foreach($_FILES as $file){
  156. if($this -> extractFile){
  157. $this -> flashExtract($path . '/' . $file['name'], $file);
  158. }else{
  159. move_uploaded_file($file['tmp_name'], $path . '/' . $file['name']);
  160. }
  161. }
  162. }
  163. }
  164. /**
  165. * Extract an flash file
  166. *
  167. * Extracts an archived file
  168. *
  169. * @param String $path Path to which the flashfile should be extracted
  170. * @param FILE $file Uploaded file to extract (from $_FILES[] arry)
  171. * @return bool true if everything went well, false if not
  172. */
  173. function flashExtract($path, $file){
  174. $tmppath = tempnam(sys_get_temp_dir(), 'ota_flash_');
  175. if($tmppath == false){
  176. $this -> throwError('0x2 Could not create temporary path');
  177. $this -> throwError('0x3 Could not extract file');
  178. return false;
  179. }
  180. move_uploaded_file($file['tmp_name'], $tmppath);
  181. $unzippath = sys_get_temp_dir() . '/ota_flash_' . md5(time());
  182. mkdir($unzippath);
  183. if($unzippath == false){
  184. $this -> throwError('0x2 Could not create temporary path');
  185. $this -> throwError('0x3 Could not extract file');
  186. return false;
  187. }
  188. exec("tar -zxvf $tmppath -C $unzippath");
  189. $this -> recurse_copy($unzippath, $path . '/');
  190. unlink($tmppath);
  191. $this -> rrmdir($unzippath);
  192. return true;
  193. }
  194. /**
  195. * Loads the flash script for the specified file
  196. *
  197. * @param String $path Path to the file, into which the file should be flashed
  198. * @return Object null if no flash script exists, otherwise the script object
  199. */
  200. function loadFlashScript($path){
  201. $dir = dirname($path);
  202. $flashfilename = '_' . basename($path) . '.ota.php';
  203. if(file_exists($dir . '/' . $flashfilename)){
  204. include($dir . '/' . $flashfilename);
  205. $objectname = str_replace('.', '_', '_' . basename($path) . '_ota');
  206. $object = new $objectname();
  207. return $object;
  208. }
  209. return null;
  210. }
  211. /**
  212. * Copy files/folders recoursiveley
  213. *
  214. * @param string $src Source directory
  215. * @param string $dst Destination directory
  216. * @return void
  217. */
  218. function recurse_copy($src, $dst) {
  219. $dir = opendir($src);
  220. @mkdir($dst);
  221. while(false !== ( $file = readdir($dir)) ) {
  222. if (( $file != '.' ) && ( $file != '..' )) {
  223. if ( is_dir($src . '/' . $file) ) {
  224. $this -> recurse_copy($src . '/' . $file,$dst . '/' . $file);
  225. }
  226. else {
  227. copy($src . '/' . $file,$dst . '/' . $file);
  228. }
  229. }
  230. }
  231. closedir($dir);
  232. }
  233. /**
  234. * Remove dir recursive
  235. *
  236. * @param string $dir Directory to remove
  237. * @return bool true if dir could be removed, false if not
  238. */
  239. function rrmdir($dir) {
  240. $files = array_diff(scandir($dir), array('.','..'));
  241. foreach ($files as $file) {
  242. (is_dir("$dir/$file")) ? $this -> rrmdir("$dir/$file") : unlink("$dir/$file");
  243. }
  244. return rmdir($dir);
  245. }
  246. /**
  247. * Close the Connection
  248. *
  249. * We need this to return immediately to the user
  250. * @param string $message the Message we should send
  251. */
  252. function closeConnection($message){
  253. ob_start();
  254. echo $message;
  255. echo "closed at " . microtime(true) . "\n";
  256. echo(str_repeat(' ', 65537)); // We fill the buffer
  257. session_write_close();
  258. header("Content-Encoding: none");//send header to avoid the browser side to take content as gzip format
  259. header("Content-Length: " . ob_get_length());//send length header
  260. header("Connection: close");//or redirect to some url: header('Location: http://www.google.com');
  261. ob_end_flush();flush();//really send content, can't change the order:1.ob buffer to normal buffer, 2.normal buffer to output
  262. }
  263. }
  264. // Check if we are on the update-bridge.php
  265. if($_SERVER['REQUEST_URI'] == '/update-bridge.php'){
  266. // We are on update-bridge.php
  267. // so let's invoke the update-bridge class
  268. $path = isset($_POST['path']) ? $_POST['path'] : '';
  269. $user = isset($_POST['user']) ? $_POST['user'] : '';
  270. $pw = isset($_POST['pw']) ? $_POST['pw'] : '';
  271. $__log = "received at " . microtime(true) . "\n";
  272. if(($user != '')&&($pw != '')){
  273. $_UB = new UpdateBridge();
  274. // We check if we should extract the file
  275. if(isset($_POST['extract'])){
  276. $_UB -> extractFile = true;
  277. }
  278. // Push the credentials to the UpdateBridge
  279. $credOK = $_UB -> checkCredentials($user, $pw);
  280. if(!$credOK){ // and exit if they were wrong
  281. echo $_UB -> errorCode;
  282. exit;
  283. }
  284. // We close the connection to the client
  285. // so we could do time-critical jobs
  286. $_UB -> closeConnection($__log . ': OK');
  287. ob_start(); // we buffer the output
  288. sleep(5); // sleep 5 seconds - time for the client to quit the connection
  289. echo "continued at " . microtime(true) . "\n";
  290. // Now - lastly - we'll flash the file
  291. $ret = $_UB -> flash($path);
  292. if($ret == false){
  293. echo $_UB -> errorCode;
  294. }else{
  295. echo ": OK";
  296. }
  297. echo "finished at " . microtime(true) . "\n";
  298. $logfile = '/tmp/update-bridge.log';
  299. $logcontent = file_get_contents($logfile);
  300. file_put_contents($logfile, $logcontent . "\n" . ob_get_contents()); // Write into the log
  301. ob_end_clean(); // Clean up
  302. }
  303. }else{
  304. // We are not on update-bridge.php - maybe we are included by another script?
  305. // so let's invoke nothing
  306. }
  307. // If requested with /update-bridge.php?ui we display a simple ui
  308. if($_SERVER['REQUEST_URI'] == '/update-bridge.php?ui'){
  309. ?>
  310. <!DOCTYPE html>
  311. <html>
  312. <head>
  313. <title>Update-Bridge</title>
  314. <style type="text/css">
  315. input{
  316. display: block;
  317. float: left;
  318. }
  319. label{
  320. display: block;
  321. float: left;
  322. clear: both;
  323. width: 200px;
  324. }
  325. </style>
  326. </head>
  327. <body>
  328. <form action='/update-bridge.php' method='POST' enctype='multipart/form-data'>
  329. <h1>Flash a file with the Update-Bridge</h1>
  330. <label>Path</label><input type='text' name='path' />
  331. <label>User</label><input type='text' name='user' />
  332. <label>Password</label><input type='password' name='pw' />
  333. <label>Extract</label><input type='checkbox' name='extract' />
  334. <label>File</label><input type='file' name='file' />
  335. <label>&nbsp;</label><input type='submit' value='Flash' />
  336. </form>
  337. </body>
  338. </html>
  339. <?php
  340. }
  341. ?>