Skip to content

Commit ab6c48d

Browse files
fukuballclaude
andcommitted
fix: 修正 code review 問題 - 硬編碼字典檔案使用與記憶體洩漏處理
修正兩個關鍵問題: 1. JiebaAnalyse::init() 硬編碼使用 idf.txt 而非 $f_name 變數 2. init() 方法中的檔案操作缺乏適當的錯誤處理與清理 變更內容: - 修正 JiebaAnalyse.php 中硬編碼的字典檔案路徑 - 在所有檔案操作中加入錯誤檢查與異常處理 - 使用 try-finally 確保檔案控制器正確關閉 - 增強 JSON 解碼的錯誤處理 - 防止記憶體洩漏並提供清楚的錯誤訊息 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 26ca2c4 commit ab6c48d

File tree

4 files changed

+120
-55
lines changed

4 files changed

+120
-55
lines changed

src/class/Finalseg.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,17 @@ public static function loadModel($f_name, $options = array())
120120

121121
$options = array_merge($defaults, $options);
122122

123-
return json_decode(file_get_contents($f_name), true);
123+
$content = file_get_contents($f_name);
124+
if ($content === false) {
125+
throw new \Exception("Failed to read model file: " . $f_name);
126+
}
127+
128+
$decoded = json_decode($content, true);
129+
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
130+
throw new \Exception("Failed to decode JSON from model file: " . $f_name . " - " . json_last_error_msg());
131+
}
132+
133+
return $decoded;
124134
} // end function loadModel
125135

126136
/**

src/class/Jieba.php

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,11 @@ public static function genTrie($f_name, $options = array())
366366

367367
$options = array_merge($defaults, $options);
368368

369-
self::$trie = new MultiArray(file_get_contents($f_name . '.json'));
369+
$trie_content = file_get_contents($f_name . '.json');
370+
if ($trie_content === false) {
371+
throw new \Exception("Failed to read trie file: " . $f_name . '.json');
372+
}
373+
self::$trie = new MultiArray($trie_content);
370374

371375
// Check if cache file exists and is valid for performance optimization
372376
$cache_file = $f_name . '.cache';
@@ -451,27 +455,34 @@ public static function loadUserDict($f_name, $options = array())
451455

452456
self::$user_dictname[] = $f_name;
453457
$content = fopen($f_name, "r");
454-
while (($line = fgets($content)) !== false) {
455-
$explode_line = explode(" ", trim($line));
456-
$word = $explode_line[0];
457-
$freq = isset($explode_line[1]) ? $explode_line[1] : 1;
458-
$tag = isset($explode_line[2]) ? $explode_line[2] : null;
459-
$freq = (float) $freq;
460-
if (isset(self::$original_freq[$word])) {
461-
self::$total -= self::$original_freq[$word];
462-
}
463-
self::$original_freq[$word] = $freq;
464-
self::$total += $freq;
465-
$l = mb_strlen($word, 'UTF-8');
466-
$word_c = array();
467-
for ($i = 0; $i < $l; $i++) {
468-
$c = mb_substr($word, $i, 1, 'UTF-8');
469-
$word_c[] = $c;
458+
if ($content === false) {
459+
throw new \Exception("Failed to open user dictionary file: " . $f_name);
460+
}
461+
462+
try {
463+
while (($line = fgets($content)) !== false) {
464+
$explode_line = explode(" ", trim($line));
465+
$word = $explode_line[0];
466+
$freq = isset($explode_line[1]) ? $explode_line[1] : 1;
467+
$tag = isset($explode_line[2]) ? $explode_line[2] : null;
468+
$freq = (float) $freq;
469+
if (isset(self::$original_freq[$word])) {
470+
self::$total -= self::$original_freq[$word];
471+
}
472+
self::$original_freq[$word] = $freq;
473+
self::$total += $freq;
474+
$l = mb_strlen($word, 'UTF-8');
475+
$word_c = array();
476+
for ($i = 0; $i < $l; $i++) {
477+
$c = mb_substr($word, $i, 1, 'UTF-8');
478+
$word_c[] = $c;
479+
}
480+
$word_c_key = implode('.', $word_c);
481+
self::$trie->set($word_c_key, array("end" => ""));
470482
}
471-
$word_c_key = implode('.', $word_c);
472-
self::$trie->set($word_c_key, array("end" => ""));
483+
} finally {
484+
fclose($content);
473485
}
474-
fclose($content);
475486
self::__calcFreq();
476487
self::$dag_cache = array();
477488

src/class/JiebaAnalyse.php

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,23 @@ public static function init($options = array())
8989
} else {
9090
$f_name = "idf.txt";
9191
}
92-
$content = fopen(dirname(dirname(__FILE__)) . "/dict/idf.txt", "r");
93-
94-
while (($line = fgets($content)) !== false) {
95-
$explode_line = explode(" ", trim($line));
96-
$word = $explode_line[0];
97-
$freq = $explode_line[1];
98-
$freq = (float) $freq;
99-
self::$idf_freq[$word] = $freq;
92+
$content = fopen(dirname(dirname(__FILE__)) . "/dict/" . $f_name, "r");
93+
94+
if ($content === false) {
95+
throw new \Exception("Failed to open IDF dictionary file: " . $f_name);
96+
}
97+
98+
try {
99+
while (($line = fgets($content)) !== false) {
100+
$explode_line = explode(" ", trim($line));
101+
$word = $explode_line[0];
102+
$freq = $explode_line[1];
103+
$freq = (float) $freq;
104+
self::$idf_freq[$word] = $freq;
105+
}
106+
} finally {
107+
fclose($content);
100108
}
101-
fclose($content);
102109

103110
asort(self::$idf_freq);
104111
$keys = array_keys(self::$idf_freq);
@@ -206,14 +213,21 @@ private static function requireInitialization()
206213
public static function setStopWords($stop_words_path, $options = array())
207214
{
208215
$content = fopen($stop_words_path, "r");
216+
217+
if ($content === false) {
218+
throw new \Exception("Failed to open stop words file: " . $stop_words_path);
219+
}
209220

210-
while (($line = fgets($content)) !== false) {
211-
$stop_word = strtolower(trim($line));
212-
if (! in_array($stop_word, self::$stop_words)) {
213-
self::$stop_words[] = $stop_word;
221+
try {
222+
while (($line = fgets($content)) !== false) {
223+
$stop_word = strtolower(trim($line));
224+
if (! in_array($stop_word, self::$stop_words)) {
225+
self::$stop_words[] = $stop_word;
226+
}
214227
}
228+
} finally {
229+
fclose($content);
215230
}
216-
fclose($content);
217231
}
218232

219233
/**

src/class/Posseg.php

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,40 +57,60 @@ public static function init($options = array())
5757

5858
if (Jieba::$dictname != '') {
5959
$content = fopen(dirname(dirname(__FILE__)) . '/dict/' . Jieba::$dictname, 'r');
60-
while (($line = fgets($content)) !== false) {
61-
$explode_line = explode(' ', trim($line));
62-
$word = $explode_line[0];
63-
$freq = $explode_line[1];
64-
$tag = $explode_line[2];
65-
self::$word_tag[$word] = $tag;
60+
if ($content === false) {
61+
throw new \Exception("Failed to open dictionary file: " . Jieba::$dictname);
6662
}
67-
fclose($content);
68-
}
69-
70-
71-
if (sizeof(Jieba::$user_dictname) != 0) {
72-
for ($i = 0; $i < sizeof(Jieba::$user_dictname); $i++) {
73-
$content = fopen(Jieba::$user_dictname[$i], 'r');
63+
64+
try {
7465
while (($line = fgets($content)) !== false) {
7566
$explode_line = explode(' ', trim($line));
7667
$word = $explode_line[0];
7768
$freq = $explode_line[1];
7869
$tag = $explode_line[2];
7970
self::$word_tag[$word] = $tag;
8071
}
72+
} finally {
8173
fclose($content);
8274
}
8375
}
8476

77+
78+
if (sizeof(Jieba::$user_dictname) != 0) {
79+
for ($i = 0; $i < sizeof(Jieba::$user_dictname); $i++) {
80+
$content = fopen(Jieba::$user_dictname[$i], 'r');
81+
if ($content === false) {
82+
throw new \Exception("Failed to open user dictionary file: " . Jieba::$user_dictname[$i]);
83+
}
84+
85+
try {
86+
while (($line = fgets($content)) !== false) {
87+
$explode_line = explode(' ', trim($line));
88+
$word = $explode_line[0];
89+
$freq = $explode_line[1];
90+
$tag = $explode_line[2];
91+
self::$word_tag[$word] = $tag;
92+
}
93+
} finally {
94+
fclose($content);
95+
}
96+
}
97+
}
98+
8599
$content = fopen(dirname(dirname(__FILE__)) . '/dict/pos_tag_readable.txt', 'r');
100+
if ($content === false) {
101+
throw new \Exception("Failed to open pos_tag_readable.txt file");
102+
}
86103

87-
while (($line = fgets($content)) !== false) {
88-
$explode_line = explode(' ', trim($line));
89-
$tag = $explode_line[0];
90-
$meaning = $explode_line[1];
91-
self::$pos_tag_readable[$tag] = $meaning;
104+
try {
105+
while (($line = fgets($content)) !== false) {
106+
$explode_line = explode(' ', trim($line));
107+
$tag = $explode_line[0];
108+
$meaning = $explode_line[1];
109+
self::$pos_tag_readable[$tag] = $meaning;
110+
}
111+
} finally {
112+
fclose($content);
92113
}
93-
fclose($content);
94114

95115
self::$is_initialized = true;
96116
} // end function init
@@ -162,7 +182,17 @@ public static function loadModel($f_name, $options = array())
162182

163183
$options = array_merge($defaults, $options);
164184

165-
return json_decode(file_get_contents($f_name), true);
185+
$content = file_get_contents($f_name);
186+
if ($content === false) {
187+
throw new \Exception("Failed to read model file: " . $f_name);
188+
}
189+
190+
$decoded = json_decode($content, true);
191+
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
192+
throw new \Exception("Failed to decode JSON from model file: " . $f_name . " - " . json_last_error_msg());
193+
}
194+
195+
return $decoded;
166196
} // end function loadModel
167197

168198
/**

0 commit comments

Comments
 (0)