БлогNot. Перехват нужного типа файлов web-сервером или разбор FB2 на PHP

Перехват нужного типа файлов web-сервером или разбор FB2 на PHP

Представим, что нам нужно выводить в браузере файл некоторого формата, обращаясь к нему по прямому URL, то есть, переход по ссылке

http://localhost/fb2/test.fb2

будет означать обработку и вывод в браузер файла test.fb2, находящегося в папке fb2 на локальном сервере. Так как сам браузер отображать формат FB2 не умеет, нам придётся передавать такие файлы на обработку какому-то скрипту, написанному на PHP или другом серверном языке.

Для простоты предположим, что все файлы нужного формата собраны в одной папке. В таком случае решением будут всего 2 строки в файле .htaccess, который мы поместим в эту же папку:

AddDefaultCharset utf-8
RewriteEngine On 
RewriteRule ^(.*).fb2$ index.php?f=$1 [L]

Вместо fb2 можно вписать другой тип файла, а вместо f - другое имя параметра URL-запроса.

Осталось реализовать файл index.php, который будет разбирать и выводить в браузер переданный ему FB2. Ниже приводится простой вариант разбора FB2 на PHP, основанный на том, что FB2 представляет собой обычный XML-файл.

Показанный код не является корректным разбором формата FB2 и просто демонстрирует подход к решению этой задачи. Тестовый файл .fb2 я взял вот отсюда и основное его содержимое скрипт всё же вывел :)

Предполагается, что сам скрипт и отображаемые файлы FB2 закодированы в Юникоде (UTF-8).

Выводимые на страницу картинки у нас для простоты пишутся прямо в папку скрипта, в реальном решении такой подход не годится. Также в сети есть гораздо более мощные решения для разбора формата FB2, например, здесь, но с их установкой и настройкой всё равно придётся повозиться.

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8"/>
  <title>FB2 file</title>
 </head>
<body>
<?php
class fictionbook {
 public  $book;
 public $table_of_content = array();
 public $book_info = array();
    
 function book_load ($file) {
  if (file_exists($file)) {
   $this->book = simplexml_load_file ($file);
   if ($this->book === false) {
    exit ('<p>Неверная разметка XML в файле '.$file.'</p>');
   }
   $this->title_info();
  } 
  else {
   exit('<p>Не удалось открыть файл '.$file.'</p>');
  }
 }
    
 function title_info (){
  $title_info = 'title-info';
  foreach ($this->book->description->$title_info->children() as $key=>$children) {
   switch ($key) {
    case 'genre':
     $this->book_info['genre'][] = $children; 
    break;
    case 'book-title':
     $this->book_info['book-title'] = $children; 
    break;
    case 'author':
     $last_name = 'last-name';
     $first_name = 'first-name';
     $middle_name = 'middle-name';
     $home_page = 'home-page';
     $this->book_info['author'][] = array (   
      'first-name'=>$children->$first_name, 'middle-name'=>$children->$middle_name, 
      'last-name'=>$children->$last_name,   'home-page'=>$children->$home_page, 
      'email'=>$children->email
     );
    break;
    case 'annotation':
     $this->book_info['annotation'] = $children->asXML(); 
    break;
    case 'coverpage':
     $this->book_info['coverpage'] = $children->image; 
    break;
    case 'date':
     $this->book_info['date'] = $children; 
    break;
    case 'translator':
     $last_name = 'last-name';
     $first_name = 'first-name';
     $middle_name = 'middle-name';
     $home_page = 'home-page';
     $this->book_info['translator'][] = array (   
      'first-name'=>$children->$first_name, 'middle-name'=>$children->$middle_name, 
      'last-name'=>$children->$last_name,   'home-page'=>$children->$home_page, 
      'email'=>$children->email
     );
    break;
    case 'lang':
     $this->book_info['lang'] = $children;
    break;
    case 'year':
     $this->book_info['year'] = $children; 
    break;                    
   }
  }
  $this->table_of_content = $this->table_of_content();
 }
    
 function print_image ($image) {
  $image =  $image->asXML();
  preg_match("/[\"|\']\#([\S]+\.[\S]+)[\"|\']/i", $image, $image_name);
  $image_name = $image_name[1];
  foreach ($this->book->binary as $binary){
   if ($binary[id] == $image_name){
    $image = base64_decode($binary);
    //Пишем файл прямо в папку скрипта - так делать не надо!
    $file = fopen($image_name, 'w');
    fwrite($file, $image);
    fclose($file);
    echo '<img src="'.$image_name.'">';
   }
  }        
 }
    
 function table_of_content ($book=false) {
  if (!empty($this->table_of_content)) {
   return $this->table_of_content;
  }
  if ($book === false){
   $book = $this->book->body;
  }
  foreach ($book as $key=>$body) {
   if (isset($body->title)) {
    $title = $this->clear_string($body->title->asXML());
    if (!empty($title)) {
     $title_array[] = $title;                    
    }
   }
   $title_array_temp = $this->table_of_content($body->section);
   if (!empty($title_array_temp)){$title_array[] = $title_array_temp;}
  }
  return $title_array;
 }

 function content ($book=false, $i=-1) {
  if ($book === false) {
   $book = $this->book->body;
  }
  ++$i;
  foreach ($book->children() as $key=>$body) {
   switch ($key) {
    case 'image': 
     $this->print_image ($body);
    break;
    case 'title':
     if ($i == 0) $i=1;
     $title = $this->clear_string($body->asXML());
     echo ''.$title;
    break;
    case 'section': 
     $this->content($body, $i);
    break;
    case 'epigraph':
     echo ''.$this->clear_string($body->asXML()).'';
    break;
    default:
     echo $this->clear_string($body->asXML(), false);
    break;
   }
  }
 }
    
 function print_table_of_content ($table = false) {
  if (!$table) {
   $table = $this->table_of_content;
  }
  foreach ($table as $row) { 
   if (is_array($row)) {
    $this->print_table_of_content($row);
   }
   else {
    echo ''.$row;
   }
  }
 }
        
 private function clear_string ($string, $p = true) {
  $string = preg_replace('/\|\<\/title\>/im', '', $string);
  $string = preg_replace('/\s+/m', " ", $string);
  $string = preg_replace('/^\s+|\s+$/', '', $string);
  if ($p) $string = preg_replace('/\|\<\/p\>/im', '', $string);
  return $string;
 }
}

libxml_use_internal_errors(true); //Отключили встроенный контроль ошибок XML!
$book  = new fictionbook;
if (!isset($_GET['f'])) {
 exit ('<p>Не передано имя файла .fb2</p>');
}
$fname = basename(htmlspecialchars(trim($_GET['f'])));
$book->book_load($fname.'.fb2');
$book->print_table_of_content();
$book->content();
?>
</body></html>

04.04.2018, 12:41 [2854 просмотра]


теги: textprocessing программирование php форматы xml сервер fb2

показать комментарии (1)