1<?php 2 3use dokuwiki\Extension\AdminPlugin; 4use dokuwiki\File\PageResolver; 5 6/** 7 * Plugin CSVtoDWPages: Convert CSV file to DW Pages 8 * 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 * @author Ninja Dave <dokuwiki [at] reprah [dot] com> 11 */ 12 13/** 14 * All DokuWiki plugins to extend the admin function 15 * need to inherit from this class 16 */ 17class admin_plugin_csvtodwpages extends AdminPlugin 18{ 19 /** 20 * Version: see lang.php 21 */ 22 23 protected $params; 24 protected $paramcount; 25 26 private $nl = "\n"; 27 28 /** 29 * access for managers 30 */ 31 function forAdminOnly() 32 { 33 return false; 34 } 35 36 /** 37 * return sort order for position in admin menu 38 */ 39 function getMenuSort() 40 { 41 return 1; 42 } 43 44 /** 45 * handle user request 46 */ 47 function handle() 48 { 49 global $INPUT; 50 global $params; 51 global $paramcount; 52 53 $fieldnames = array('csvdw_namespace','csvdw_delim','csvdw_pagename','csvdw_csvdata','csvdw_csvtemplate','csvdw_overwrite','csvdw_dummyrun' ,'csvdw_trim'); 54 55 if ($INPUT->has('csvdw_submit') && checkSecurityToken()) { 56 57 foreach ($fieldnames as $key) { 58 if (!blank($INPUT->param($key))){ 59 $paramcount++; 60 $params[$key] = $INPUT->param($key); 61 } 62 } 63 } 64 } 65 66 /** 67 * output appropriate html 68 */ 69 function html() 70 { 71 global $params; 72 global $paramcount; 73 74 $fieldcount = 0; 75 76 // update the label when the namespace is changed 77 echo "<script language='javascript'>function csvtodw_nslabel(){document.getElementById('csvtodw_nslabel').innerHTML=document.getElementById('csvtodw_ns').value;};</script>"; 78 79 echo $this->locale_xhtml('intro') . $this->nl; 80 echo '<form method="post" action="" class="csvtodwpages">' . $this->nl; 81 echo '<input type="hidden" name="do" value="admin"/>' . $this->nl; 82 echo '<input type="hidden" name="page" value="'.$this->getPluginName().'"/>' . $this->nl; 83 formSecurityToken(); 84 85 echo '<fieldset class="csvtodwpages">' . $this->nl; 86 87 echo '<table class="csvtodwpages"><tr><td>' . $this->nl; 88 89 echo '<h4>'.$this->getLang('csvdw_namespace').'</h4>' . $this->nl; 90 echo '<input type="text" name="csvdw_namespace" value="'.$this->_field('csvdw_namespace','').'" id="csvtodw_ns" onblur="csvtodw_nslabel()"/>' . $this->nl; 91 $fieldcount++; 92 93 echo '</td><td>' . $this->nl; 94 95 echo '<h4>'.$this->getLang('csvdw_pagename').'</h4>' . $this->nl; 96 echo '<input type="text" name="csvdw_pagename" value="'.$this->_field('csvdw_pagename','').'"/>' . $this->nl; 97 $fieldcount++; 98 99 echo '</td><td>' . $this->nl; 100 101 echo '<h4>'.$this->getLang('csvdw_delim').'</h4>' . $this->nl; 102 echo '<input type="text" name="csvdw_delim" maxlength="1" value="'.$this->_field('csvdw_delim',',').'"/>' . $this->nl; 103 $fieldcount++; 104 105 echo '</td></tr></table>' . $this->nl; 106 107 echo '<h4>'.$this->getLang('csvdw_csvtemplate').'</h4>' . $this->nl; 108 echo '<textarea name="csvdw_csvtemplate" class="edit">'.$this->_field('csvdw_csvtemplate').'</textarea><br/><br/>' . $this->nl; 109 $fieldcount++; 110 111 echo '<h4>'.$this->getLang('csvdw_csvdata').'</h4>' . $this->nl; 112 echo '<textarea name="csvdw_csvdata" class="edit">'.$this->_field('csvdw_csvdata').'</textarea><br/><br/>' . $this->nl; 113 $fieldcount++; 114 115 echo '<table class="csvtodwpages"><tr><td>' . $this->nl; 116 117 echo '<h4>'.sprintf($this->getLang('csvdw_overwrite'), $this->_field('csvdw_namespace','csvexploded')).'</h4>' . $this->nl; 118 echo '<input type="radio" class="csvtodwpages" name="csvdw_overwrite[]" value="true" id="owt" '.$this->_field('csvdw_overwrite','true',true).'/> ' . $this->nl; 119 echo '<label class="csvtodwpages" for="owt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="owf">'.$this->getLang('csvdw_no').'</label>' . $this->nl; 120 echo '<input type="radio" class="csvtodwpages" name="csvdw_overwrite[]" value="false" id="owf" '.$this->_field('csvdw_overwrite','false',true).'/>' . $this->nl; 121 $fieldcount++; 122 123 echo '</td><td>' . $this->nl; 124 125 echo '<h4>'.$this->getLang('csvdw_dummyrun').'</h4>' . $this->nl; 126 echo '<input type="radio" class="csvtodwpages" name="csvdw_dummyrun[]" value="true" id="drt" '.$this->_field('csvdw_dummyrun','true',true).'/> ' . $this->nl; 127 echo '<label class="csvtodwpages" for="drt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="drf">'.$this->getLang('csvdw_no').'</label>' . $this->nl; 128 echo '<input type="radio" class="csvtodwpages" name="csvdw_dummyrun[]" value="false" id="drf" '.$this->_field('csvdw_dummyrun','false',true).'/>' . $this->nl; 129 $fieldcount++; 130 131 echo '</td><td>' . $this->nl; 132 133 echo '<h4>'.$this->getLang('csvdw_trim').'</h4>' . $this->nl; 134 echo '<input type="radio" name="csvdw_trim[]" value="true" id="trimt" '.$this->_field('csvdw_trim','true',true).'/> ' . $this->nl; 135 echo '<label class="csvtodwpages" for="trimt">'.$this->getLang('csvdw_yes').'</label> --- <label class="csvtodwpages" for="trimf">'.$this->getLang('csvdw_no').'</label>' . $this->nl; 136 echo '<input type="radio" name="csvdw_trim[]" value="false" id="trimf" '.$this->_field('csvdw_trim','false',true).'/>' . $this->nl; 137 $fieldcount++; 138 139 echo '</td></tr></table>' . $this->nl; 140 141 // required fields warning 142 echo (is_numeric($paramcount) && $paramcount !== $fieldcount) ? "<span class='csvtodwpageswarning'>".$this->getLang('csvdw_allfields')."</span><br/>" : '' . $this->nl; 143 144 echo '<input type="submit" name="csvdw_submit" class="csvtodwpages" value="'.$this->getLang('csvdw_submitbtn').'"/>' . $this->nl; 145 146 echo '<div class="csvtodwpages_ver">'.$this->getLang('csvdw_ver').'</div>'; 147 echo '</fieldset>'; 148 149 echo '</form>'; 150 151 // if all form values recieved, let's explode! 152 if ($paramcount == $fieldcount) { 153 $this->_csvexploder(); 154 155 } elseif ($paramcount > $fieldcount) { 156 // something weird going on 157 echo '<br/><fieldset><span class="csvtodwpageswarning">Incorrect number of form parameters received. We\'re screwed!<br/>Needed '.$fieldcount.', got '.$paramcount.'</span></fieldset>' . $this->nl; 158 } 159 } 160 161 162 /** 163 * take form values and explode the submitted csvdata into dokuwiki pages based on submitted csvtemplate 164 */ 165 function _csvexploder() 166 { 167 global $conf; // get dokuwiki conf array 168 global $params; 169 global $paramcount; 170 global $ID; 171 172 $resolver = new PageResolver($ID); 173 174 175 $namespace = strtolower($params['csvdw_namespace']); // which namespace to create pages within 176 177 $pagename_column = $params['csvdw_pagename']; // which column(s) in the csv file used for the pagename 178 179 $indexpage = (empty($conf['start'])) ? 'start' : $conf['start']; // the dokuwiki index page name 180 181 $csvdata = $params['csvdw_csvdata']; // the dokuwiki page in which you pasted the csv data 182 $csvtemplate = $params['csvdw_csvtemplate']; // the dokuwiki page you created holding the template 183 $csvdelim = $params['csvdw_delim'][0]; // the csv delimiter character (single character) 184 185 $overwrite_files = ($params['csvdw_overwrite'][0] == 'true') ? TRUE : FALSE; // set this to TRUE to overwrite existing pages 186 $dummyrun = ($params['csvdw_dummyrun'][0] == 'true') ? TRUE : FALSE; // is this just a dummy run? 187 $trimspaces = ($params['csvdw_trim'][0] == 'true') ? TRUE : FALSE; // is this just a dummy run? 188 189 $indexpagecontent = $this->getLang('csvdw_indexpagecontent'); // template for autogenerated index page 190 191 // $dr = rtrim( $_SERVER['DOCUMENT_ROOT'], "/" ) .'/'; 192 193 // get field names from first row 194 $csvfieldnames = str_getcsv(strtok($csvdata, PHP_EOL), $csvdelim); 195 196 // if we have some csvfieldnames lets rock'n'roll 197 if ($csvfieldnames !== FALSE) { 198 199 if ($dummyrun) { 200 echo $this->getLang('csvdw_dummyrunnotice') . $this->nl; 201 } 202 203 echo $this->getLang('csvdw_explodednotice') . $this->nl; 204 205 if (array_count_values($csvfieldnames) >= 1) { 206 207 while (($line = strtok(PHP_EOL)) !== FALSE) { 208 209 $line = str_getcsv($line, $csvdelim); 210 211 if (!empty(array_filter($line))) { 212 213 // get clean copy of the template 214 $thispage = $csvtemplate; 215 216 // set the page name for the index page text 217 $pagename = $this->_get_filename($pagename_column, $line); 218 219 // clean output filename to dokuwiki standards 220 $cleanpagename = cleanID($pagename); 221 222 $indexpagecontent .= " * [[$cleanpagename|$pagename]]\r\n"; 223 224 // replace the template [placeholder] names with content 225 foreach ($csvfieldnames as $key => $field) { 226 $thispage = str_replace('['.strtolower($field).']', $trimspaces ? trim($line[$key]) : $line[$key], $thispage); 227 } 228 229 // create wiki page 230 $filecreated = FALSE; 231 232 if ($overwrite_files !== TRUE && page_exists($resolver->resolveId($namespace.':'.$cleanpagename))) { 233 echo $this->getLang('csvdw_skipnoticep'); // msg($this->getLang('csvdw_skipnotice')); 234 } else { 235 if ($dummyrun) { 236 $filecreated = TRUE; 237 } else { 238 // we are assuming that if the file exists after saveWikiText() then it was created 239 // Unfortunately saveWikiText() doesn't provide a return value to indicate if it succeeded or failed. 240 // This leaves it possible that a page existed previously but we were unable to overwrite it. 241 // The DW notice system will put a notice in the exploded file list to indicate the failure though. 242 // see io_writeWikiPage() and _io_writeWikiPage_action() in .\dokuwiki\inc\io.php 243 saveWikiText($resolver->resolveId($namespace.':'.$cleanpagename), $thispage, $this->getLang('csvdw_summary')); 244 $filecreated = page_exists($resolver->resolveId($namespace.':'.$cleanpagename)); 245 } 246 247 if ($filecreated == FALSE) { 248 echo $this->getLang('csvdw_errornotice'); 249 } else { 250 echo $this->getLang('csvdw_creatednoticep'); 251 } 252 } 253 254 echo wikiFN($resolver->resolveId($namespace.':'.$cleanpagename))."<br/>" . $this->nl; 255 } 256 257 } 258 259 // show an example template page if this is a dummy run 260 // (uses the data from the last processed csv row) 261 if ($dummyrun) { 262 echo $this->getLang('csvdw_examplepagenotice') . $this->nl; 263 echo nl2br($thispage) . $this->nl; 264 } 265 266 echo "<br/><br/><hr/>" . $this->nl; 267 268 // create index page 269 $filecreated = FALSE; 270 271 if ($overwrite_files !== TRUE && page_exists($resolver->resolveId($namespace.':'.$indexpage))) { 272 echo $this->getLang('csvdw_skipnoticei'); // msg($this->getLang('csvdw_skipnoticei')); 273 274 } else { 275 if ($dummyrun) { 276 $filecreated = TRUE; 277 } else { 278 saveWikiText($resolver->resolveId($namespace.':'.$indexpage), $indexpagecontent, $this->getLang('csvdw_summary')); 279 $filecreated = page_exists($resolver->resolveId($namespace.':'.$indexpage)); 280 } 281 if ($filecreated == FALSE) { 282 echo $this->getLang('csvdw_errornotice'); 283 } else { 284 echo $this->getLang('csvdw_creatednoticei'); 285 } 286 } 287 288 // echo wikiFN(resolve_id($namespace, $indexpage))."<br/>" . $this->nl; 289 echo wikiFN($resolver->resolveId($namespace.':'.$indexpage))."<br/>" . $this->nl; 290 } 291 292 echo "<br/>" . $this->nl; 293 294 // null is used as the first param to wl() as it's the only way to get the URL 295 // to work on both our dev server (excludes the doku.php in url) and the live 296 // server (includes doku.php in url) 297 echo 'Go to <a href="' . wl(null, '', false) . $resolver->resolveId($namespace.':'.$indexpage) . '">' . $namespace . ':' . $indexpage . '</a><br/>' . $this->nl; 298 } 299 300 strtok('',''); // release strtok memory 301 } 302 303 /** 304 * Helper to build a unique pagename from specified csv column data 305 * 306 * Will combine multiple column data together if comma separated list 307 * is supplied. Each field will be separated with underscores _ 308 * 309 * @param $pagecols string Single int value or comma separated list eg. 0,3 310 * @param $line array An array containing the csv values for the current row 311 * @return string A page name combining all row values separated with _ eg. youngstown_oh 312 */ 313 protected function _get_filename($pagecols='', &$line) 314 { 315 $pagename = ''; 316 $pagecols = explode(',', $pagecols); 317 318 // combine column data into filename 319 foreach ($pagecols as $col) { 320 $pagename .= trim($line[$col]).'_'; 321 } 322 323 return rtrim($pagename, "_"); 324 } 325 326 /** 327 * Helper to repopulate form field values from POST data 328 * 329 * @param $field = fieldname 330 * @param $default = default value to return if no value present 331 * @param $isradio = flag indicating if field is a radiobutton - return 'checked' instead of value 332 * @return string : form field value or default 333 * @return array : first element of array if incoming field was an array (multivalue field) 334 */ 335 protected function _field($field, $default='', $isradio=false) 336 { 337 global $params; 338 global $paramcount; 339 340 $val = ''; 341 if (!blank($params[$field])) { 342 $val = is_array($params[$field]) ? $params[$field][0] : $params[$field]; 343 } 344 345 if ($isradio) { 346 if ($val==$default) { 347 return 'checked'; 348 } 349 return ''; 350 } 351 352 return !blank($val) ? $val : $default; 353 } 354 355} 356 357