| 1 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
// Note that REAL cache should check for Last-Modified HTTP header at least;
|
|
|
4 |
// As I don't like idea of implementing the full-scaled HTTP protocol library
|
|
|
5 |
// and curl extension is very rare, this implementation of cache is very simple.
|
|
|
6 |
// Cache is cleared after the script finishes it work!
|
|
|
7 |
|
|
|
8 |
// Also, it can have problems with simultaneous access to the images.
|
|
|
9 |
|
|
|
10 |
// The class responsible for downloading and caching images
|
|
|
11 |
// as PHP does not support the static variables, we'll use a global variable
|
|
|
12 |
// containing all cached objects; note that cache consumes memory!
|
|
|
13 |
//
|
|
|
14 |
$GLOBALS['g_image_cache'] = array();
|
|
|
15 |
|
|
|
16 |
class Image {
|
|
|
17 |
var $_handle;
|
|
|
18 |
var $_filename;
|
|
|
19 |
var $_type;
|
|
|
20 |
|
|
|
21 |
function Image($handle, $filename, $type) {
|
|
|
22 |
$this->_handle = $handle;
|
|
|
23 |
$this->_filename = $filename;
|
|
|
24 |
$this->_type = $type;
|
|
|
25 |
}
|
|
|
26 |
|
|
|
27 |
function get_filename() {
|
|
|
28 |
return $this->_filename;
|
|
|
29 |
}
|
|
|
30 |
|
|
|
31 |
function get_handle() {
|
|
|
32 |
return $this->_handle;
|
|
|
33 |
}
|
|
|
34 |
|
|
|
35 |
function get_type() {
|
|
|
36 |
return $this->_type;
|
|
|
37 |
}
|
|
|
38 |
|
|
|
39 |
function sx() {
|
|
|
40 |
if (!$this->_handle) {
|
|
|
41 |
return 0;
|
|
|
42 |
};
|
|
|
43 |
|
|
|
44 |
return imagesx($this->_handle);
|
|
|
45 |
}
|
|
|
46 |
|
|
|
47 |
function sy() {
|
|
|
48 |
if (!$this->_handle) {
|
|
|
49 |
return 0;
|
|
|
50 |
};
|
|
|
51 |
|
|
|
52 |
return imagesy($this->_handle);
|
|
|
53 |
}
|
|
|
54 |
}
|
|
|
55 |
|
|
|
56 |
class ImageFactory {
|
|
|
57 |
// Static funcion; checks if given URL is already cached and either returns
|
|
|
58 |
// cached object or downloads the requested image
|
|
|
59 |
//
|
|
|
60 |
function get($url, &$pipeline) {
|
|
|
61 |
global $g_config;
|
|
|
62 |
if (!$g_config['renderimages']) { return null; };
|
|
|
63 |
|
|
|
64 |
global $g_image_cache;
|
|
|
65 |
|
|
|
66 |
// Check if this URL have been cached
|
|
|
67 |
//
|
|
|
68 |
if (isset($g_image_cache[$url])) {
|
|
|
69 |
// return do_image_open($g_image_cache[$url]);
|
|
|
70 |
return $g_image_cache[$url];
|
|
|
71 |
};
|
|
|
72 |
|
|
|
73 |
// Download image; we should do it before we call do_image_open,
|
|
|
74 |
// as it tries to open image file twice: first to determine image type
|
|
|
75 |
// and second to actually create the image - PHP url wrappers do no caching
|
|
|
76 |
// at all
|
|
|
77 |
//
|
|
|
78 |
$filename = ImageFactory::make_cache_filename($url);
|
|
|
79 |
|
|
|
80 |
// REQUIRES: PHP 4.3.0+
|
|
|
81 |
// we suppress warning messages, as missing image files will cause 'copy' to print
|
|
|
82 |
// several warnings
|
|
|
83 |
//
|
|
|
84 |
// @TODO: change to fetcher class call
|
|
|
85 |
//
|
|
|
86 |
|
|
|
87 |
$data = $pipeline->fetch($url);
|
|
|
88 |
|
|
|
89 |
if (is_null($data)) {
|
|
|
90 |
error_log("Cannot fetch image: ".$url);
|
|
|
91 |
return null;
|
|
|
92 |
};
|
|
|
93 |
|
|
|
94 |
$file = fopen($filename, 'wb');
|
|
|
95 |
fwrite($file, $data->content);
|
|
|
96 |
fclose($file);
|
|
|
97 |
$pipeline->pop_base_url();
|
|
|
98 |
|
|
|
99 |
// register it in the cached objects array
|
|
|
100 |
//
|
|
|
101 |
$handle = do_image_open($filename, $type);
|
|
|
102 |
if ($handle) {
|
|
|
103 |
$g_image_cache[$url] =& new Image($handle,
|
|
|
104 |
$filename,
|
|
|
105 |
$type);
|
|
|
106 |
} else {
|
|
|
107 |
$g_image_cache[$url] = null;
|
|
|
108 |
};
|
|
|
109 |
// return image
|
|
|
110 |
//
|
|
|
111 |
// return do_image_open($filename);
|
|
|
112 |
return $g_image_cache[$url];
|
|
|
113 |
}
|
|
|
114 |
|
|
|
115 |
// Makes the filename to contain the cached version of URL
|
|
|
116 |
//
|
|
|
117 |
function make_cache_filename($url) {
|
|
|
118 |
// We cannot use the $url as an cache image name as it could be longer than
|
|
|
119 |
// allowed file name length (especially after escaping specialy symbols)
|
|
|
120 |
// thus, we generate long almost random 32-character name using the md5 hash function
|
|
|
121 |
//
|
|
|
122 |
return CACHE_DIR.md5(time() + $url + rand());
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
// Checks if cache directory is available
|
|
|
126 |
//
|
|
|
127 |
function check_cache_dir() {
|
|
|
128 |
// TODO: some cool easily understandable error message for the case
|
|
|
129 |
// image cache directory cannot be created or accessed
|
|
|
130 |
|
|
|
131 |
// Check if CACHE_DIR exists
|
|
|
132 |
//
|
|
|
133 |
if (!is_dir(CACHE_DIR)) {
|
|
|
134 |
// Cache directory does not exists; try to create it (with read/write rightss for the owner only)
|
|
|
135 |
//
|
|
|
136 |
if (!mkdir(CACHE_DIR, 0700)) { die("Cache directory cannot be created"); }
|
|
|
137 |
};
|
|
|
138 |
|
|
|
139 |
// Check if we can read and write to the CACHE_DIR
|
|
|
140 |
//
|
|
|
141 |
// Note that directory should have 'rwx' (7) permission, so the script will
|
|
|
142 |
// be able to list directory contents; under Windows is_executable always returns false
|
|
|
143 |
// for directories, so we need to drop this check in this case.
|
|
|
144 |
//
|
|
|
145 |
// A user's note for 'is_executable' function on PHP5:
|
|
|
146 |
// "The change doesn't appear to be documented, so I thought I would mention it.
|
|
|
147 |
// In php5, as opposed to php4, you can no longer rely on is_executable to check the executable bit
|
|
|
148 |
// on a directory in 'nix. You can still use the first note's method to check if a directory is traversable:
|
|
|
149 |
// @file_exists("adirectory/.");"
|
|
|
150 |
//
|
|
|
151 |
if (!is_readable(CACHE_DIR) ||
|
|
|
152 |
!is_writeable(CACHE_DIR) ||
|
|
|
153 |
(!@file_exists(CACHE_DIR.'.'))) {
|
|
|
154 |
// omg. Cache directory exists, but useless
|
|
|
155 |
//
|
|
|
156 |
die("Check cache directory permissions; cannot either read or write to directory cache");
|
|
|
157 |
};
|
|
|
158 |
|
|
|
159 |
return;
|
|
|
160 |
}
|
|
|
161 |
|
|
|
162 |
// Clears the image cache (as we're neither implemented checking of Last-Modified HTTP header nor
|
|
|
163 |
// provided the means of limiting the cache size
|
|
|
164 |
//
|
|
|
165 |
// TODO: Will cause problems with simultaneous access to the same images
|
|
|
166 |
//
|
|
|
167 |
function clear_cache() {
|
|
|
168 |
foreach ($GLOBALS['g_image_cache'] as $key => $value) {
|
|
|
169 |
if (!is_null($value)) {
|
|
|
170 |
unlink($value->get_filename());
|
|
|
171 |
};
|
|
|
172 |
};
|
|
|
173 |
$g_image_cache = array();
|
|
|
174 |
}
|
|
|
175 |
}
|
|
|
176 |
?>
|