3 * our moto... "To Convert and Serve"!!!
6 * $x= new File_Convert("filename", "application/pdf");
7 * $fn = $x->convert("image/jpeg", 200, 0);
11 * $x= new File_Convert("filename", "application/pdf");
12 * $fn = $x->convert("application/pdf"); // does no conversion (as it's the same.
13 * $x->serve('inline'); // can fix IE Mess...
17 * delete_all : delete all the generated files after script execution when we call convert()
24 $x = new File_Convert(false);
25 print_r($x->getConvMethods('application/msword', 'application/pdf'));
26 print_r($x->getConvMethods('application/msword', 'image/jpeg'));
27 print_r($x->getConvMethods('application/acad', 'image/jpeg'));
28 var_dump($x->getConvMethods('application/acad', 'application/msword')); // impossible
30 $x = new File_Convert(file, 'app../excel',array('sheet'=>array(0,1,2...) ));
31 $out = $x->convert('text/csv');
38 static $options = array();
40 var $fn = ''; // filename
43 var $debug = false; // set to true to turn on deubgging
46 var $lastaction = false;
48 var $solutions = array();
50 function __construct($fn, $mimetype, $options=array())
54 if (!file_exists($fn)) {
55 throw new Exception("Source file does not exist:". $fn );
58 $this->mimetype = $mimetype;
59 self::$options = $options;
65 * check if conversion exists, and return the filename if it does.
69 function convertExists($toMimetype, $x= 0, $y =0)
71 static $actions = array();
73 if ($toMimetype != $this->mimetype) {
75 if (!isset($actions["{$this->mimetype} => $toMimetype"])) {
76 $actions["{$this->mimetype} => $toMimetype"] = $this->getConvMethods($this->mimetype, $toMimetype);;
79 $action = $actions["{$this->mimetype} => $toMimetype"];
82 // echo '<PRE>';print_r($action);
86 if (!file_exists($this->fn)) {
90 $fn = $action->convertExists($this->fn, $x, $y);
98 if (!preg_match('#^image/#', $toMimetype) || ( empty($x) && empty($y))) {
102 //echo "testing scale image";
103 require_once 'File/Convert/Solution/scaleimage.php';
104 $sc = new File_Convert_Solution_scaleimage($toMimetype, $toMimetype);
105 //$sc->convert = $this;
106 $sc->debug= $this->debug;
107 $this->solutions[] = $sc;
109 if (strpos($x, 'x')) {
110 $bits = explode('x', $x);
112 $y = empty($bits[1]) ? 0 : (int)$bits[1];;
115 if (!file_Exists($fn)) {
118 $fn = $sc->convertExists($fn, (int)$x, (int)$y);
121 //$this->target = $fn;
122 //$this->to = $toMimetype;
127 * actually run the convertion routine.
131 function convert($toMimetype, $x= 0, $y =0, $pg=false)
133 //print_R(func_get_args());
134 if ($toMimetype == 'image/jpg') {
135 $toMimetype = 'image/jpeg';
139 if(empty($pg) || is_nan($pg * 1)){
143 //echo '<PRE>'; print_r(array('convert', func_get_args()));
145 $toMimetype != $this->mimetype ||
147 $toMimetype == $this->mimetype &&
148 $toMimetype == 'image/gif'
152 $action = $this->getConvMethods($this->mimetype, $toMimetype);
154 //echo '<PRE>';print_r($action);
157 $this->debug("No methods found to convert {$this->mimetype} to {$toMimetype}");
160 $action->debug = $this->debug;
161 $fn = $action->runconvert($this->fn, $x, $y, $pg);
162 // delete the generated files after script execution
163 if(!empty(self::$options['delete_all'])) {
164 $this->deleteOnExitAdd($fn);
168 $this->to = $toMimetype;
169 $this->lastaction = $action->last ? $action->last : $action; // what failed.
173 // let's assume that conversions can handle scaling??
179 if (preg_match('#^image/#', $toMimetype) && $toMimetype != 'image/gif' && ( !empty($x) || !empty($y))) {
180 //var_dump(array($toMimetype));
182 require_once 'File/Convert/Solution.php';
183 $scf = (strpos($x, 'c') !== false ? 'scaleimagec' : 'scaleimage' );
184 require_once 'File/Convert/Solution/'. $scf . '.php';
185 $scls = 'File_Convert_Solution_' . $scf;
187 $sc = new $scls($toMimetype, $toMimetype);
188 $sc->debug= $this->debug;
189 $this->solutions[] = $sc;
190 $x = str_replace('c', 'x', $x);
192 if (strpos($x, 'x') !== false ) {
193 $bits = explode('x', $x);
195 $y = !is_numeric($bits[1]) ? '' : (int)$bits[1];
197 $x = strlen($x) ? (int) $x : '';
198 $y = strlen($y) ? (int) $y : '';
199 //print_r($x); print_r(' > '); print_r($y);exit;
201 $fn = $sc->runconvert($fn, $x, $y, $pg);
203 // delete the generated files after script execution
204 if(!empty(self::$options['delete_all'])) {
205 $this->deleteOnExitAdd($fn);
209 // print_r($this->target);
211 $this->to = $toMimetype;
217 function serveOnly($type=false, $filename =false, $delete_after = false)
219 $this->target = $this->fn;
220 $this->to = $this->mimetype;
221 $this->serve($type, $filename , $delete_after );
226 * Serve the file to a browser so it can be downloaded, or viewed.
228 * @param type string attachment or inline..
229 * @param filename string name of file
230 * @param delete_after boolean (false) delete file after sending..
233 function serve($type=false, $filename =false, $delete_after = false) // may die **/
235 if (empty($this->target)) {
236 // broken image? for images...
237 $cmd = isset($this->lastaction->cmd) ? $this->lastaction->cmd : "No Method";
238 die("not available in this format was: {$this->mimetype}, request: {$this->to}<BR>
239 Running - $cmd\n" . print_r(is_object($this->lastaction) ? $this->lastaction->log : '',true));
242 if (!file_exists($this->target))
244 trigger_error("Target does not exist: {$this->target}");
245 print_r($this->target);
252 $isIE = preg_match('#msie [0-9.]+#i', isset($_SERVER['HTTP_USER_AGENT']) ? isset($_SERVER['HTTP_USER_AGENT']) : '');
256 $ts = filemtime($fn);
258 $etag = md5($ts. '!' . $fn);
260 $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
261 trim($_SERVER['HTTP_IF_NONE_MATCH'],"'\"") : false;
263 $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
264 stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : false;
266 $ts_string = gmdate("D, d M Y H:i:s", $ts) . " GMT";
268 if ((($if_none_match && $if_none_match == $etag) || (!$if_none_match)) &&
269 ($if_modified_since && $if_modified_since == $ts_string))
271 header('HTTP/1.1 304 Not Modified');
276 //if (empty($_REQUEST['ts']) && !$isIE && $ifModifiedSince && strtotime($ifModifiedSince) >= $ts) {
277 // header('HTTP/1.0 304 Not Modified');
278 // exit; // stop processing
280 // ie kludge cause it's brain dead..
284 if ($isIE && preg_match('#^application/#i', $this->to)) {
285 // pdfs' break if we add this line?
286 //$mt = 'application/octet-stream' ;
287 $type = $type === false ? 'attachment' : $type;
289 $type = $type === false ? 'inline' : $type;
294 //if (!preg_match('#^image\/#i', $this->to)) {
296 // a reasonable expiry time - 5 minutes..
297 header("Expires: ". gmdate("D, d M Y H:i:s", strtotime("NOW + 5 MINUTES")) . " GMT");
298 header("Cache-Control: must-revalidate");
299 header("Pragma: public");
300 header("Last-Modified: " . $ts_string . " GMT");
301 header("ETag: \"{$etag}\"");
304 require_once 'File/MimeType.php';
305 $fmt = new File_MimeType();
306 $ext = $fmt->toExt($mt);
307 $sfn = basename($fn);
308 $sfn = preg_match('#\.'.$ext.'$#', $sfn) ? $sfn : $sfn. '.' .$ext;
311 if (empty($filename)) {
315 $filename = preg_replace('/[^\x00-\x7E]/', '', $filename);
317 header('Content-length: '. filesize($fn));
318 // if ($type != 'inline') {
319 header('Content-Disposition: '.$type.'; filename="' . htmlspecialchars($filename). '"');
322 // needs to be removed after debugging - otherwise it logs to error.log
323 //ini_set('display_errors', 0); //trigger_error("Serving: {$this->target} ". filesize($fn));
324 if ($_SERVER["REQUEST_METHOD"] == 'HEAD') {
328 //var_dump($fn, $mt); exit;
329 header('Content-type: '. $mt);
331 // even though we have done a file_exists above - it still errors out here occausionally.
332 $fh = @fopen($fn, 'rb');
335 // passthrough seems to have problems -- trying fread
336 while($fh && !feof($fh))
338 echo @fread($fh, 1024*8);
361 cls => instance of class
369 static $methods = false;
370 if ($methods !== false ) {
374 $base = __DIR__.'/Convert/Solution';
375 $dh = opendir($base);
376 while (false !== ($fn = readdir($dh))) {
377 if (substr($fn,0,1) == '.' ) {
380 require_once 'File/Convert/Solution/' . $fn;
381 $cls = 'File_Convert_Solution_'. str_replace('.php', '',$fn);
383 $ref = new ReflectionClass($cls);
384 $val = $ref->getStaticPropertyValue('rules');
386 foreach($val as $r) {
403 * This recursively calls to find the best match.
404 * First by matching the 'from'
406 * Then if multiple outputs are available,
407 * It will see if any of those can be used to generate the to, by recurivly calling it'self..
411 function getConvMethods($from, $to, $stack = array())
413 // these source types have to use unoconv....
414 //print_r(array('getConvMethods', func_get_args()));
415 // $pos[converter] => array( list of targets);
416 require_once 'File/Convert/Solution.php';
418 if (count($stack) > 4) { // too deepp.. pos. recursion.
422 // print_r(self::$methods);
423 foreach($this->methods() as $t) {
424 if (!in_array($from, $t['from'])) {
427 if (in_array($to,$t['to'])) {
429 $ret = new $cls($from, $to); // found a solid match - returns the method.
430 //$ret->convert = $this; // recursion?
431 $this->solutions[] = $ret;
437 $pos[$t['cls']] = $t['to']; // list of targets
444 foreach($pos as $conv => $ar) {
445 // array contains a list of pos. mimetypes.
447 foreach($ar as $targ) {
448 if ($from == $targ) {
449 continue; // skip going back...
451 if (in_array($targ, $stack)) {
452 continue; // going backwards..
454 // we need to build a list here.
460 $try = $this->getConvMethods($targ, $to, $ns);
461 // try will be an array of method, from, to (or false)
463 if ($try === false) {
464 continue; // mo way to convert
466 // print_r($conv);exit;
468 $first = new $conv($from, $targ);
469 //$first->convert = $this;
470 $sol_list= $first->add($try);
478 $this->debug("No methods found to convert {$from} to {$to}");
482 // find the shortest..
483 usort ( $res , array($this, 'solutionSort'));
485 $this->solutions[] = $best;
490 function solutionSort($a, $b) {
491 if ($a->count() == $b->count()) {
494 return $a->count() < $b->count() ? -1 : 1;
501 if (is_callable($this->debug)) {
502 call_user_func($this->debug,$str);
504 echo $str . "<br/>\n";
510 static $deleteOnExit = false;
512 * generate a tempory file with an extension (dont forget to delete it)
515 function deleteOnExitAdd($name)
517 if (self::$deleteOnExit === false) {
518 register_shutdown_function(array('File_Convert','deleteOnExit'));
519 self::$deleteOnExit = array();
521 self::$deleteOnExit[] = $name;
524 static function deleteOnExit()
527 foreach(self::$deleteOnExit as $fn) {
528 if (file_exists($fn)) {