-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcsvCache.php
More file actions
72 lines (70 loc) · 2.37 KB
/
Copy pathcsvCache.php
File metadata and controls
72 lines (70 loc) · 2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
// Ignore blank spreadsheet rows, but never accept an empty table or an HTML error page.
function parseCachedCsv($content)
{
if (!is_string($content) || trim($content) === '' || preg_match('/^\s*</', $content)) {
return null;
}
$stream = fopen('php://temp', 'r+');
fwrite($stream, $content);
rewind($stream);
$rows = [];
while (($row = fgetcsv($stream)) !== false) {
if (trim($row[0] ?? '') === '') {
continue;
}
if (count($row) < 2) {
fclose($stream);
return null;
}
$rows[] = $row;
}
fclose($stream);
return $rows ?: null;
}
// Readers see either the previous complete file or the new validated file.
function loadCsvCache($filename, $url, $refresh = false, $download = null)
{
$cached = parseCachedCsv(@file_get_contents($filename));
if ($cached && !$refresh) {
return $cached;
}
$lock = fopen($filename . '.lock', 'c');
if (!$lock || !flock($lock, LOCK_EX)) {
throw new RuntimeException('Unable to lock CSV cache: ' . $filename);
}
$temporary = null;
try {
$cached = parseCachedCsv(@file_get_contents($filename));
if ($cached && !$refresh) {
return $cached;
}
for ($attempt = 0; $attempt < 2; $attempt++) {
$content = $download
? $download($url)
: @file_get_contents($url, false, stream_context_create(['http' => ['timeout' => 10]]));
$rows = parseCachedCsv($content);
if (!$rows) {
continue;
}
$temporary = tempnam(dirname($filename), '.csv-');
if ($temporary === false || file_put_contents($temporary, $content) !== strlen($content)
|| !chmod($temporary, 0644) || !rename($temporary, $filename)) {
throw new RuntimeException('Unable to write CSV cache: ' . $filename);
}
$temporary = null;
return $rows;
}
if ($cached) {
error_log('CSV refresh failed; keeping previous data: ' . $filename);
return $cached;
}
throw new RuntimeException('Unable to load valid CSV data: ' . $filename);
} finally {
if ($temporary && file_exists($temporary)) {
unlink($temporary);
}
flock($lock, LOCK_UN);
fclose($lock);
}
}