1<?php 2 3namespace dokuwiki\Search\Index; 4 5use dokuwiki\Search\Exception\IndexWriteException; 6 7/** 8 * Access to a single index file 9 * 10 * Access using this class always happens by loading the full index into memory. 11 * All modifications need to be explicitly made permanent using the save() method. 12 * Should be used for small indexes that receive many changes at once. 13 */ 14class MemoryIndex extends AbstractIndex 15{ 16 17 /** @var string the raw data lines of the index, no newlines */ 18 protected $data; 19 20 /** 21 * Loads the full contents of the index into memory 22 * 23 * @inheritdoc 24 */ 25 public function __construct($idx, $suffix = '') 26 { 27 parent::__construct($idx, $suffix); 28 29 $this->data = []; 30 if (!file_exists($this->filename)) return; 31 $this->data = file($this->filename, FILE_IGNORE_NEW_LINES); 32 33 } 34 35 /** @inheritdoc */ 36 public function changeRow($rid, $value) 37 { 38 if ($rid > count($this->data)) { 39 $this->data = array_pad($this->data, $rid, ''); 40 } 41 $this->data[$rid] = $value; 42 } 43 44 /** @inheritdoc */ 45 public function retrieveRow($rid) 46 { 47 if (isset($this->data[$rid])) return $this->data[$rid]; 48 return ''; 49 } 50 51 /** @inheritdoc */ 52 public function getRowIDs($values) 53 { 54 $values = array_map('trim', $values); 55 $values = array_fill_keys($values, 1); // easier access as associative array 56 57 $result = []; 58 $count = count($this->data); 59 for ($ln = 0; $ln < $count; $ln++) { 60 $line = $this->data[$ln]; 61 if (isset($values[$line])) { 62 $result[$line] = $ln; 63 unset($values[$line]); 64 } 65 } 66 67 // if there are still values, they have not been found and will be appended 68 foreach (array_keys($values) as $value) { 69 $this->data[] = $value; 70 $result[$value] = $ln++; 71 } 72 73 return $result; 74 } 75 76 /** 77 * Save the changed index back to its file 78 * 79 * @throws IndexWriteException 80 */ 81 public function save() 82 { 83 global $conf; 84 85 $tempname = $this->filename . '.tmp'; 86 87 $fh = @fopen($tempname, 'w'); 88 if (!$fh) { 89 throw new IndexWriteException("Failed to write $tempname"); 90 } 91 fwrite($fh, implode("\n", $this->data)); 92 if (!empty($lines)) { 93 fwrite($fh, "\n"); 94 } 95 fclose($fh); 96 97 if ($conf['fperm']) { 98 chmod($tempname, $conf['fperm']); 99 } 100 101 if (!io_rename($tempname, $this->filename)) { 102 throw new IndexWriteException("Failed to write {$this->filename}"); 103 } 104 } 105 106} 107