1<?php 2/** 3 * Prolog plug-in : Rule-based System for Groupware. 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Paweł Kupka <pawel.kupka@gmail.com> 7 */ 8 9// must be run within Dokuwiki 10$webroot = reset(split('lib',dirname(__FILE__))); 11if(!defined('DOKU_INC')) define('DOKU_INC', $webroot); 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins'); 13if(!defined('DOKU_PAGES')) define('DOKU_PAGES',DOKU_INC.'data/pages'); 14if(!defined('DOKU_TMP')) define('DOKU_TMP',DOKU_INC.'data/tmp'); 15//require_once (DOKU_INC.'inc/pageutils.php'); 16//require_once (DOKU_INC.'inc/utf8.php'); 17require_once('prolog_tag.php'); 18 19class AttributeInclude extends PrologTag { 20 21 var $name = 'include'; 22 23 /** 24 * Constructor 25 */ 26 function AttributeInclude() 27 { 28 $this->setAttributePattern($this->name); 29 } 30 31 /** 32 * Gets the list of files to be included 33 * @param string $includeValue the attribute include value 34 * @param string $fileID the file ID in the DokuWiki notation 35 * @param array $filesList list of files 36 * @return array $filesList list of files 37 */ 38 function getFilesList($includeValue = null, $fileID = null, &$filesList = array()) 39 { 40 if(empty($fileID)) 41 $fileID = getID(); 42 43 $includedIDs = $this->sliceIncludeValue($includeValue); 44 $joinedIDs = array(); 45 foreach($includedIDs as $includeID) 46 array_push($joinedIDs, $this->joinID($fileID,$includeID)); 47 48 foreach($joinedIDs as $ID) 49 { 50 $files = $this->scan($ID); 51 foreach($files as $file) 52 { 53 if(in_array($file, $filesList) || $file == wikiFN(getID())) 54 continue; 55 else 56 { 57 array_push($filesList, $file); 58 $tags = $this->getEntryTags($file); 59 foreach($tags as $tag) 60 $this->getFilesList($this->getAttributeValue($tag), $this->abs2ID($file), $filesList); 61 } 62 } 63 } 64 return $filesList; 65 } 66 67 /** 68 * Gets the files paths from the place designated by the ID 69 * @param string $ID ID of the page or namespace 70 * @return array $foundFiles list of files paths 71 */ 72 function scan($ID = null) 73 { 74 $path = $this->ID2abs($ID); 75 76 if(!$this->isReadable($path)) 77 return array(); 78 79 if($this->getScanType($ID) == 'SINGLE_PAGE') 80 return array($path); 81 elseif($this->getScanType($ID) == 'RECURSIVE_DIRECTORY') 82 return $this->scanDirectory($path, true); 83 elseif($this->getScanType($ID) == 'SINGLE_DIRECTORY') 84 return $this->scanDirectory($path); 85 else 86 return array(); 87 } 88 89 /** 90 * cuts the include attribute value 91 * @param string $value attribute include value 92 * @return array $exValues array of ID values from the include attribute 93 */ 94 function sliceIncludeValue($value = null) 95 { 96 $parts = array(); 97 $exValues = explode(',', $value); 98 foreach($exValues as $part) { 99 $part = trim($part); 100 if(!empty($part)) 101 array_push($parts, $part); 102 } 103 return $parts; 104 } 105 106 /** 107 * Checks if the file/directory exists and is readable 108 * @param $file file path 109 * @return bool 110 */ 111 function isReadable($file = null) 112 { 113 if((is_file($file) || is_dir($file)) && file_exists($file) && is_readable($file)) 114 return true; 115 else 116 return false; 117 } 118 119 /** 120 * Returns the scan type based on the given ID 121 * @param string $ID 122 * @return string scan type 123 */ 124 function getScanType($ID = null) 125 { 126 $IDparts = explode(':', $ID); 127 if(preg_match('/[\w]+/', end($IDparts))) 128 return 'SINGLE_PAGE'; 129 elseif(preg_match('/\*\*/', end($IDparts))) 130 return 'RECURSIVE_DIRECTORY'; 131 elseif(preg_match('/\*/', end($IDparts))) 132 return 'SINGLE_DIRECTORY'; 133 else 134 return 'NONE'; 135 } 136 137 /** 138 * Reads the code from all Prolog tags in the given text files 139 * @param array $files list of files path 140 * @return string $readCode prolog source code read from the prolog tags 141 */ 142 function readCode($files = array()) 143 { 144 $readCode = ''; 145 foreach($files as $file) 146 { 147 $fileContent = file_get_contents($file); 148 $splitedByEntry = preg_split($this->entryTagPattern,$fileContent); 149 array_shift($splitedByEntry); 150 foreach($splitedByEntry as $splited) 151 { 152 if(!preg_match($this->exitTagPattern,$splited)) 153 continue; 154 $splitedByExit = preg_split($this->exitTagPattern, $splited,-1,PREG_SPLIT_NO_EMPTY); 155 $readCode .= $splitedByExit[0]; 156 } 157 } 158 return $readCode; 159 } 160 161 /** 162 * Joins two IDs into one 163 * @param string $headID base namespace 164 * @param string $tailID additional namespace 165 * @return string $joinedID 166 */ 167 function joinID($headID = null, $tailID = null) { 168 $headNS = getNS($headID); 169 $tailIDParts = explode(':',$tailID); 170 $joinedIDParts = explode(':',$headNS); 171 172 if(empty($headNS)) 173 return $tailID; 174 175 foreach($tailIDParts as $tailIDPart) 176 { 177 if(empty($tailIDPart)) 178 return implode(':',$tailIDParts); 179 180 if($tailIDPart == '.') 181 { 182 array_shift($tailIDParts); 183 $joinedIDParts = $tailIDParts; 184 break; 185 } 186 elseif($tailIDPart == '..') 187 array_pop($joinedIDParts); 188 else 189 array_push($joinedIDParts, $tailIDPart); 190 } 191 $joinedID = implode(':',$joinedIDParts); 192 193 return $joinedID; 194 } 195 196 /** 197 * Converts ID into the absolute path to the file/directory 198 * @param string $ID page/namespace ID 199 * @return string $abs absolute path to file/directory 200 */ 201 function ID2abs($ID = null) { 202 if(noNS($ID) == '*' || noNS($ID) == '**') 203 $abs = DOKU_PAGES.'/'.str_replace(':','/',getNS($ID)); 204 else 205 $abs = DOKU_PAGES.'/'.str_replace(':','/',$ID.'.txt'); 206 207 return str_replace('\\', '/', $abs); 208 } 209 210 /** 211 * Converts the file/directory absolute path into ID 212 * @param string $abs absolute path to file/directory 213 * @return string $ID page/namespace ID 214 */ 215 function abs2ID($abs = null) { 216 $abs = str_replace(realpath(DOKU_PAGES), '', realpath($abs)); 217 218 if(substr($abs,-4) == '.txt') 219 $abs = substr($abs, 0, -4); 220 else 221 $abs .= '/*'; 222 223 $ID = preg_replace('/[\/\\\]/',':',$abs); 224 225 if(substr($ID,0,1) == ':') 226 $ID = substr($ID,1); 227 228 return $ID; 229 } 230 231 /** 232 * Scans the given directory in search of text files 233 * @param string $directory path to the directory 234 * @param bool $recursive if set to "true", it also scans all sub-directories, if set to "false", only the main directory (parameter value) 235 * @param array $file_list list of found text files 236 * @return array $file_list list of found text files 237 */ 238 function scanDirectory($directory = null, $recursive = false, &$file_list = array()) 239 { 240 if(substr($directory,-1) == '/' || substr($directory,-1) == '\\') 241 $directory = substr($directory,0,-1); 242 243 $directory_list = opendir($directory); 244 245 while (false !== ($file = readdir($directory_list))) 246 { 247 if($file != '.' && $file != '..') 248 { 249 $path = $directory.'/'.$file; 250 if(is_readable($path)) 251 { 252 $subdirectories = explode('/',$path); 253 if(is_dir($path) && $recursive) 254 $this->scanDirectory($path, $recursive, $file_list); 255 elseif(is_file($path)) 256 { 257 $extension = end(explode('.',end($subdirectories))); 258 if($extension == 'txt') 259 array_push($file_list,$path); 260 } 261 } 262 } 263 } 264 closedir($directory_list); 265 return $file_list; 266 } 267} 268?>