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