Ejemplo n.º 1
0
function rtf2text($filename)
{
    // Read the data from the input file.
    $text = file_get_contents($filename);
    if (!strlen($text)) {
        return "";
    }
    // Create empty stack array.
    $document = "";
    $stack = array();
    $j = -1;
    // Read the data character-by- character…
    for ($i = 0, $len = strlen($text); $i < $len; $i++) {
        $c = $text[$i];
        // Depending on current character select the further actions.
        switch ($c) {
            // the most important key word backslash
            case "\\":
                // read next character
                $nc = $text[$i + 1];
                // If it is another backslash or nonbreaking space or hyphen,
                // then the character is plain text and add it to the output stream.
                if ($nc == '\\' && rtf_isPlainText($stack[$j])) {
                    $document .= '\\';
                } elseif ($nc == '~' && rtf_isPlainText($stack[$j])) {
                    $document .= ' ';
                } elseif ($nc == '_' && rtf_isPlainText($stack[$j])) {
                    $document .= '-';
                } elseif ($nc == '*') {
                    $stack[$j]["*"] = true;
                } elseif ($nc == "'") {
                    $hex = substr($text, $i + 2, 2);
                    if (rtf_isPlainText($stack[$j])) {
                        $document .= html_entity_decode("&#" . hexdec($hex) . ";");
                    }
                    //Shift the pointer.
                    $i += 2;
                    // Since, we’ve found the alphabetic character, the next characters are control word
                    // and, possibly, some digit parameter.
                } elseif ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                    $word = "";
                    $param = null;
                    // Start reading characters after the backslash.
                    for ($k = $i + 1, $m = 0; $k < strlen($text); $k++, $m++) {
                        $nc = $text[$k];
                        // If the current character is a letter and there were no digits before it,
                        // then we’re still reading the control word. If there were digits, we should stop
                        // since we reach the end of the control word.
                        if ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                            if (empty($param)) {
                                $word .= $nc;
                            } else {
                                break;
                            }
                            // If it is a digit, store the parameter.
                        } elseif ($nc >= '0' && $nc <= '9') {
                            $param .= $nc;
                        } elseif ($nc == '-') {
                            if (empty($param)) {
                                $param .= $nc;
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                    // Shift the pointer on the number of read characters.
                    $i += $m - 1;
                    // Start analyzing what we’ve read. We are interested mostly in control words.
                    $toText = "";
                    switch (strtolower($word)) {
                        // If the control word is "u", then its parameter is the decimal notation of the
                        // Unicode character that should be added to the output stream.
                        // We need to check whether the stack contains \ucN control word. If it does,
                        // we should remove the N characters from the output stream.
                        case "u":
                            $toText .= html_entity_decode("&#x" . dechex($param) . ";");
                            $ucDelta = @$stack[$j]["uc"];
                            if ($ucDelta > 0) {
                                $i += $ucDelta;
                            }
                            break;
                            // Select line feeds, spaces and tabs.
                        // Select line feeds, spaces and tabs.
                        case "par":
                        case "page":
                        case "column":
                        case "line":
                        case "lbr":
                            $toText .= "\n";
                            break;
                        case "emspace":
                        case "enspace":
                        case "qmspace":
                            $toText .= " ";
                            break;
                        case "tab":
                            $toText .= "\t";
                            break;
                            // Add current date and time instead of corresponding labels.
                        // Add current date and time instead of corresponding labels.
                        case "chdate":
                            $toText .= date("m.d.Y");
                            break;
                        case "chdpl":
                            $toText .= date("l, j F Y");
                            break;
                        case "chdpa":
                            $toText .= date("D, j M Y");
                            break;
                        case "chtime":
                            $toText .= date("H:i:s");
                            break;
                            // Replace some reserved characters to their html analogs.
                        // Replace some reserved characters to their html analogs.
                        case "emdash":
                            $toText .= html_entity_decode("&mdash;");
                            break;
                        case "endash":
                            $toText .= html_entity_decode("&ndash;");
                            break;
                        case "bullet":
                            $toText .= html_entity_decode("&#149;");
                            break;
                        case "lquote":
                            $toText .= html_entity_decode("&lsquo;");
                            break;
                        case "rquote":
                            $toText .= html_entity_decode("&rsquo;");
                            break;
                        case "ldblquote":
                            $toText .= html_entity_decode("&laquo;");
                            break;
                        case "rdblquote":
                            $toText .= html_entity_decode("&raquo;");
                            break;
                            // Add all other to the control words stack. If a control word
                            // does not include parameters, set &param to true.
                        // Add all other to the control words stack. If a control word
                        // does not include parameters, set &param to true.
                        default:
                            $stack[$j][strtolower($word)] = empty($param) ? true : $param;
                            break;
                    }
                    // Add data to the output stream if required.
                    if (rtf_isPlainText($stack[$j])) {
                        $document .= $toText;
                    }
                }
                $i++;
                break;
                // If we read the opening brace {, then new subgroup starts and we add
                // new array stack element and write the data from previous stack element to it.
            // If we read the opening brace {, then new subgroup starts and we add
            // new array stack element and write the data from previous stack element to it.
            case "{":
                array_push($stack, $stack[$j++]);
                break;
                // If we read the closing brace }, then we reach the end of subgroup and should remove
                // the last stack element.
            // If we read the closing brace }, then we reach the end of subgroup and should remove
            // the last stack element.
            case "}":
                array_pop($stack);
                $j--;
                break;
                // Skip “trash”.
            // Skip “trash”.
            case '\\0':
            case '\\r':
            case '\\f':
            case '\\n':
                break;
                // Add other data to the output stream if required.
            // Add other data to the output stream if required.
            default:
                if (rtf_isPlainText($stack[$j])) {
                    $document .= $c;
                }
                break;
        }
    }
    // Return result.
    return $document;
}
Ejemplo n.º 2
0
             $i++;
             break;
         case "{":
             array_push($stack, $stack[$j++]);
             break;
         case "}":
             array_pop($stack);
             $j--;
             break;
         case '\\0':
         case '\\r':
         case '\\f':
         case '\\n':
             break;
         default:
             if (rtf_isPlainText($stack[$j])) {
                 $trueText .= $c;
             }
             break;
     }
 }
 $length = strlen($trueText);
 $size = $length;
 if ($size > 1000) {
     $prefix = "KB";
 }
 if ($size > 1000000) {
     $prefix = "MB";
 }
 if ($size > 1000000000) {
     $prefix = "GB";
Ejemplo n.º 3
0
function rtf2text($filename)
{
    // Пытаемся прочить данные из переданного нам rtf-файла, в случае успеха -
    // продолжаем наше злобненькое дело.
    $text = file_get_contents($filename);
    if (!strlen($text)) {
        return "";
    }
    # Speeding up via cutting binary data from large rtf's.
    if (strlen($text) > 1024 * 1024) {
        $text = preg_replace("#[\r\n]#", "", $text);
        $text = preg_replace("#[0-9a-f]{128,}#is", "", $text);
    }
    # For Unicode escaping
    $text = str_replace("\\'3f", "?", $text);
    $text = str_replace("\\'3F", "?", $text);
    // Итак, самое главное при чтении данных из rtf'а - это текущее состояние
    // стека модификаторов. Начинаем мы, естественно, с пустого стека и отрицательного
    // его (стека) уровня.
    $document = "";
    $stack = array();
    $j = -1;
    $fonts = array();
    // Читаем посимвольно данные...
    for ($i = 0, $len = strlen($text); $i < $len; $i++) {
        $c = $text[$i];
        // исходя из текущего символа выбираем, что мы с данными будем делать.
        switch ($c) {
            // итак, самый важный ключ "обратный слеш"
            case "\\":
                // читаем следующий символ, чтобы понять, что нам делать дальше
                $nc = $text[$i + 1];
                // Если это другой бэкслеш, или неразрывный пробел, или обязательный
                // дефис, то мы вставляем соответствующие данные в выходной поток
                // (здесь и далее, в поток втавляем только в том случае, если перед
                // нами именно текст, а не шрифтовая вставка, к примеру).
                if ($nc == '\\' && rtf_isPlainText($stack[$j])) {
                    $document .= '\\';
                } elseif ($nc == '~' && rtf_isPlainText($stack[$j])) {
                    $document .= ' ';
                } elseif ($nc == '_' && rtf_isPlainText($stack[$j])) {
                    $document .= '-';
                } elseif ($nc == '*') {
                    $stack[$j]["*"] = true;
                } elseif ($nc == "'") {
                    $hex = substr($text, $i + 2, 2);
                    if (rtf_isPlainText($stack[$j])) {
                        #echo $hex." ";
                        #dump($stack[$j], false);
                        #dump($fonts, false);
                        if (!empty($stack[$j]["mac"]) || @$fonts[$stack[$j]["f"]] == 77) {
                            $document .= from_macRoman(hexdec($hex));
                        } elseif (@$stack[$j]["ansicpg"] == "1251" || @$stack[$j]["lang"] == "1029") {
                            $document .= chr(hexdec($hex));
                        } else {
                            $document .= "&#" . hexdec($hex) . ";";
                        }
                    }
                    #dump($stack[$j], false);
                    // Мы прочитали два лишних символа, должны сдвинуть указатель.
                    $i += 2;
                    // Так перед нами буква, а это значит, что за \ идёт упраляющее слово
                    // и возможно некоторый циферный параметр, которые мы должны прочитать.
                } elseif ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                    $word = "";
                    $param = null;
                    // Начинаем читать символы за бэкслешем.
                    for ($k = $i + 1, $m = 0; $k < strlen($text); $k++, $m++) {
                        $nc = $text[$k];
                        // Если текущий символ буква и до этого не было никаких цифр,
                        // то мы всё ещё читаем управляющее слово, если же были цифры,
                        // то по документации мы должны остановиться - ключевое слово
                        // так или иначе закончилось.
                        if ($nc >= 'a' && $nc <= 'z' || $nc >= 'A' && $nc <= 'Z') {
                            if (empty($param)) {
                                $word .= $nc;
                            } else {
                                break;
                            }
                            // Если перед нами цифра, то начинаем записывать параметр слова.
                        } elseif ($nc >= '0' && $nc <= '9') {
                            $param .= $nc;
                        } elseif ($nc == '-') {
                            if (empty($param)) {
                                $param .= $nc;
                            } else {
                                break;
                            }
                            // В любом другом случае - конец.
                        } else {
                            break;
                        }
                    }
                    // Сдвигаем указатель на количество прочитанных нами букв/цифр.
                    $i += $m - 1;
                    // Начинаем разбираться, что же мы такое начитали. Нас интересует
                    // именно управляющее слово.
                    $toText = "";
                    switch (strtolower($word)) {
                        // Если слово "u", то параметр - это десятичное представление
                        // unicode-символа, мы должны добавить его в выход.
                        // Но мы должны учесть, что за символом может стоять его
                        // замена, в случае, если программа просмотрщик не может работать
                        // с Unicode, поэтому при наличии \ucN в стеке, мы должны откусить
                        // "лишние" N символов из исходного потока.
                        case "u":
                            $toText .= html_entity_decode("&#x" . sprintf("%04x", $param) . ";");
                            $ucDelta = !empty($stack[$j]["uc"]) ? @$stack[$j]["uc"] : 1;
                            /*for ($k = 1, $m = $i + 2; $k <= $ucDelta && $m < strlen($text); $k++, $m++) {
                            			$d = $text[$m];
                            			if ($d == '\\') {
                            				$dd = $text[$m + 1];
                            				if ($dd == "'")
                            					$m += 3;
                            				elseif($dd == '~' || $dd == '_')
                            					$m++;
                            			}
                            		}
                            		$i = $m - 2;*/
                            #$i += $m - 2;
                            if ($ucDelta > 0) {
                                $i += $ucDelta;
                            }
                            break;
                            // Обработаем переводы строк, различные типы пробелов, а также символ
                            // табуляции.
                        // Обработаем переводы строк, различные типы пробелов, а также символ
                        // табуляции.
                        case "par":
                        case "page":
                        case "column":
                        case "line":
                        case "lbr":
                            $toText .= "\n";
                            break;
                        case "emspace":
                        case "enspace":
                        case "qmspace":
                            $toText .= " ";
                            break;
                        case "tab":
                            $toText .= "\t";
                            break;
                            // Добавим вместо соответствующих меток текущие дату или время.
                        // Добавим вместо соответствующих меток текущие дату или время.
                        case "chdate":
                            $toText .= date("m.d.Y");
                            break;
                        case "chdpl":
                            $toText .= date("l, j F Y");
                            break;
                        case "chdpa":
                            $toText .= date("D, j M Y");
                            break;
                        case "chtime":
                            $toText .= date("H:i:s");
                            break;
                            // Заменим некоторые спецсимволы на их html-аналоги.
                        // Заменим некоторые спецсимволы на их html-аналоги.
                        case "emdash":
                            $toText .= html_entity_decode("&mdash;");
                            break;
                        case "endash":
                            $toText .= html_entity_decode("&ndash;");
                            break;
                        case "bullet":
                            $toText .= html_entity_decode("&#149;");
                            break;
                        case "lquote":
                            $toText .= html_entity_decode("&lsquo;");
                            break;
                        case "rquote":
                            $toText .= html_entity_decode("&rsquo;");
                            break;
                        case "ldblquote":
                            $toText .= html_entity_decode("&laquo;");
                            break;
                        case "rdblquote":
                            $toText .= html_entity_decode("&raquo;");
                            break;
                            # Skipping binary data...
                        # Skipping binary data...
                        case "bin":
                            $i += $param;
                            break;
                        case "fcharset":
                            $fonts[@$stack[$j]["f"]] = $param;
                            break;
                            // Всё остальное добавим в текущий стек управляющих слов. Если у текущего
                            // слова нет параметров, то приравляем параметр true.
                        // Всё остальное добавим в текущий стек управляющих слов. Если у текущего
                        // слова нет параметров, то приравляем параметр true.
                        default:
                            $stack[$j][strtolower($word)] = empty($param) ? true : $param;
                            break;
                    }
                    // Если что-то требуется вывести в выходной поток, то выводим, если это требуется.
                    if (rtf_isPlainText($stack[$j])) {
                        $document .= $toText;
                    }
                } else {
                    $document .= " ";
                }
                $i++;
                break;
                // Перед нами символ { - значит открывается новая подгруппа, поэтому мы должны завести
                // новый уровень стека с переносом значений с предыдущих уровней.
            // Перед нами символ { - значит открывается новая подгруппа, поэтому мы должны завести
            // новый уровень стека с переносом значений с предыдущих уровней.
            case "{":
                if ($j == -1) {
                    $stack[++$j] = array();
                } else {
                    array_push($stack, $stack[$j++]);
                }
                break;
                // Закрывающаяся фигурная скобка, удаляем текущий уровень из стека. Группа закончилась.
            // Закрывающаяся фигурная скобка, удаляем текущий уровень из стека. Группа закончилась.
            case "}":
                array_pop($stack);
                $j--;
                break;
                // Всякие ненужности отбрасываем.
            // Всякие ненужности отбрасываем.
            case "":
            case "\r":
            case "\f":
            case "\\b":
            case "\t":
                break;
                // Остальное, если требуется, отправляем на выход.
            // Остальное, если требуется, отправляем на выход.
            case "\n":
                $document .= " ";
                break;
            default:
                if (rtf_isPlainText($stack[$j])) {
                    $document .= $c;
                }
                break;
        }
    }
    // Возвращаем, что получили.
    return html_entity_decode(iconv("windows-1251", "utf-8", $document), ENT_QUOTES, "UTF-8");
}