1<?php 2/** 3 * Display Fortune cookies 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9class helper_plugin_xfortune extends DokuWiki_Plugin { 10 11 /** 12 * Get a random cookie properly escaped 13 * 14 * @param string $cookieID the media file id to the cookie file 15 * @param int $maxlines 16 * @return string 17 */ 18 static public function getCookieHTML($cookieID, $maxlines=0, $maxchars=0) { 19 if($maxlines) { 20 $cookie = self::getSmallCookie($cookieID, $maxlines, $maxchars); 21 } else { 22 $cookie = self::getCookie($cookieID); 23 } 24 25 return nl2br(hsc($cookie)); 26 } 27 28 /** 29 * Tries to find a cookie with a maximum number of lines 30 * 31 * gives up after a 100 tries 32 * 33 * @param $cookieID 34 * @param int $maxlines maximum lines to return 35 * @return string 36 */ 37 static public function getSmallCookie($cookieID, $maxlines, $maxchars){ 38 $runaway = 100; 39 $tries = 0; 40 if($maxlines < 1) $maxlines = 1; 41 if($maxchars < 1) $maxlines = 250; 42 43 do { 44 $cookie = self::getCookie($cookieID); 45 $lines = count(explode("\n", $cookie)); 46 } while( ($lines > $maxlines || strlen($cookie) > $maxchars) && $tries++ < $runaway); 47 48 return $cookie; 49 } 50 51 /** 52 * Get a file for the given ID 53 * 54 * If the ID ends with a colon a namespace is assumed and a random txt file is picked from there 55 * 56 * @param $cookieID 57 * @return string 58 * @throws Exception 59 */ 60 static public function id2file($cookieID) { 61 $file = mediaFN($cookieID); 62 $isns = is_dir($file); 63 if($isns) $cookieID .= ':dir'; 64 65 if(auth_quickaclcheck($cookieID) < AUTH_READ) throw new Exception("No read permissions for $cookieID"); 66 67 if($isns) { 68 $dir = $file; 69 $files = glob("$dir/*.txt"); 70 if(!count($files)) throw new Exception("Could not find fortune files in $cookieID"); 71 $file = $files[array_rand($files)]; 72 } 73 74 // we now should have a valid file 75 if(!file_exists($file)) throw new Exception("No fortune file at $cookieID"); 76 77 return $file; 78 } 79 80 /** 81 * Returns one random cookie 82 * 83 * @param string $cookieID the media file id to the cookie file 84 * @return string 85 */ 86 static public function getCookie($cookieID) { 87 try { 88 $file = self::id2file($cookieID); 89 } catch(Exception $e) { 90 return 'ERROR: '.$e->getMessage(); 91 } 92 93 $dim = filesize($file); 94 if($dim < 2) return "ERROR: invalid cookie file $file"; 95 mt_srand((double) microtime() * 1000000); 96 $rnd = mt_rand(0, $dim); 97 98 $fd = fopen($file, 'r'); 99 if(!$fd) return "ERROR: reading cookie file $file failed"; 100 101 // jump to random place in file 102 fseek($fd, $rnd); 103 104 $text = ''; 105 $cookie = false; 106 while(true) { 107 $seek = ftell($fd); 108 $line = fgets($fd, 1024); 109 110 if($seek == 0) { 111 // start of file always starts a cookie 112 $cookie = true; 113 if($line == "%\n") { 114 // ignore delimiter if exists 115 continue; 116 } else { 117 // part of the cookie 118 $text .= $line; 119 continue; 120 } 121 } 122 123 if(feof($fd)) { 124 if($cookie) { 125 // we had a cookie already, stop here 126 break; 127 } else { 128 // no cookie yet, wrap around 129 fseek($fd, 0); 130 continue; 131 } 132 } 133 134 if($line == "%\n") { 135 if($cookie) { 136 // we had a cookie already, stop here 137 break; 138 } elseif($seek == $dim - 2) { 139 // it's the end of file delimiter, wrap around 140 fseek($fd, 0); 141 continue; 142 } else { 143 // start of the cookie 144 $cookie = true; 145 continue; 146 } 147 } 148 149 // part of the cookie? 150 if($cookie) { 151 $text .= $line; 152 } 153 } 154 fclose($fd); 155 156 $text = trim($text); 157 158 // if it is not valid UTF-8 assume it's latin1 159 if(!utf8_check($text)) return utf8_encode($text); 160 161 return $text; 162 } 163 164} 165