1<?php 2/** 3 * PageMapper for SphinxSearch plugin 4 * Handles mapping between DokuWiki Page IDs and Sphinx CRCs 5 */ 6 7class PageMapper { 8 private ?PDO $_db = null; 9 private string $_dbFile = ''; 10 11 public function __construct() { 12 global $conf; 13 14 // 1. Resolve the savedir relative to DOKU_INC 15 // This handles cases where savedir is just 'data' or './data' 16 $saveDir = $conf['savedir']; 17 if (strpos($saveDir, '/') !== 0 && !preg_match('/^[a-z]:\\\/i', $saveDir)) { 18 // It is a relative path, anchor it to DOKU_INC 19 $saveDir = DOKU_INC . $saveDir; 20 } 21 22 $dbPath = $saveDir . '/sphinxsearchwas'; 23 24 // 2. Ensure the directory exists 25 if (!is_dir($dbPath)) { 26 @mkdir($dbPath, 0777, true); 27 } 28 29 $this->_dbFile = $dbPath . '/pages.db'; 30 31 // DEBUG: Uncomment the line below if it still fails, to see where it is trying to write 32 // file_put_contents('php://stderr', "Writing DB to: " . $this->_dbFile . "\n"); 33 34 $this->_initDb(); 35 } 36 37 /** 38 * Connect to SQLite and ensure the table exists 39 */ 40 private function _initDb(): void { 41 try { 42 $this->_db = new PDO("sqlite:" . $this->_dbFile); 43 $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 44 45 // Create the table if it doesn't exist 46 $sql = "CREATE TABLE IF NOT EXISTS pages ( 47 page TEXT, 48 title TEXT, 49 title_text TEXT, 50 hid TEXT, 51 crc INTEGER PRIMARY KEY 52 )"; 53 $this->_db->exec($sql); 54 55 // Optimization for SQLite 56 $this->_db->exec("PRAGMA journal_mode = WAL"); 57 $this->_db->exec("PRAGMA synchronous = NORMAL"); 58 59 } catch (PDOException $e) { 60 die("Database Error: " . $e->getMessage()); 61 } 62 } 63 64 /** 65 * Add or Update a page mapping 66 */ 67 public function add(string $page, string $title, string $title_text = '', string $hid = ''): void { 68 $crc = sprintf('%u', crc32($page . $hid) ?: 1); 69 70 $sql = "REPLACE INTO pages (page, title, title_text, hid, crc) 71 VALUES (:page, :title, :title_text, :hid, :crc)"; 72 73 try { 74 $stmt = $this->_db->prepare($sql); 75 $stmt->bindValue(':page', $page); 76 $stmt->bindValue(':title', $title); 77 $stmt->bindValue(':title_text', $title_text); 78 $stmt->bindValue(':hid', $hid); 79 $stmt->bindValue(':crc', $crc); 80 $stmt->execute(); 81 } catch (PDOException $e) { 82 // Ignore write errors during indexing to keep stream alive 83 } 84 } 85 86 /** 87 * Retrieve mapping by CRC 88 */ 89 public function getByCrc(array $crcs): array { 90 if (empty($crcs)) return []; 91 92 $placeholders = implode(',', array_fill(0, count($crcs), '?')); 93 $sql = "SELECT * FROM pages WHERE crc IN ($placeholders)"; 94 95 try { 96 $stmt = $this->_db->prepare($sql); 97 $stmt->execute(array_values($crcs)); 98 $results = []; 99 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 100 $results[$row['crc']] = $row; 101 } 102 return $results; 103 } catch (PDOException $e) { 104 return []; 105 } 106 } 107} 108