したがって、タスク:
Microsoft Word文書がDoc形式でダウンロードされるポータルがあります。 一般に公開する前に、処理する必要があります。 正確さはそれほど重要ではないため、単純化するために次のアルゴリズムを使用します。
- 新しいドキュメントを作成します。
- ソースからデータを貼り付けます(ファイルを挿入)。
- 元のファイルではなく、受信したファイルを保存します。
すぐに言います:Win2k3 + Office + Apache + PHP5を搭載した追加サーバーがDocファイルに関与しています。 おそらく、コメントの中で、FreeBSDで同様の操作を実行するにはどうすればよいかという答えが見つかります:-)
最初の質問への答え:なぜこの処理が必要なのですか?
試行錯誤を通じて、これはすべてのドキュメントに対して実行する必要があるアクションの最小シーケンスであると結論付けられました。
これには2つの理由があります。
- まず、ファイルを挿入すると、その内容(テキスト、フォーマット、画像)のみが挿入され、マクロは残されます。 これにより、Normal.dotに侵入する可能性のある悪意のあるコードを取り除くことができます:-)もちろん、マクロを保存する必要がある場合、このオプションは機能しませんが、ほとんどのタスクにはマクロは必要ありません。
- 次に、ソースファイルが書き込み用にロックされている場合、変更できません。 新しいドキュメントはこのロックを継承しません。
2番目の質問への答え:ドキュメントの処理はどのように実装されましたか?
試行錯誤により、数世代のプロセッサが作成されました。 実際には、最初は、正常に動作しているプログラムがしばらくしてエラーを生成し始めました。 その結果、処理は停止しました。 そして、停止が頻繁になったとき、前の決定の失敗を認め、新しい決定を発明しなければなりませんでした。
だから。
第一世代: "mainscript.exe"
このスクリプトは、コマンドラインオプションを使用してWordを起動しました。 それらの1つは処理中のファイルの名前で、2つ目は処理マクロの名前です。 2分後、プログラムは開始したプロセスを強制終了しました。 スクリプト自体はCGIを介して実行されました。
マイナスのうち、注意することができます:
- プログラムは正確に2分働いた
- 頻繁にフリーズし、プログラムとWord。 その結果、多数のハングプロセスがwinword.exeとmainscript.exeを処理します。
第二世代:シンプルなPHP-COM / OLE
最初の世代が私の前に実現された場合、2番目は1番目のアドオンです。 マクロから同じアクションを実装する簡単なスクリプトが作成されました。 あるスクリプトが別のスクリプトに置き換えられました。 ローカルでは、すべてが完璧に機能しました。 平均ファイルの処理には15秒かかりました(2分ではなく)。 スクリプトはサーバーに転送されます。 テスト。 同じ15秒。 作業を開始し、...
Winwordsが落ちる、ハングする、スローダウンする...例外が常に表示されます。 さらに、PHPスクリプトはmax_execution_timeより長い時間ハングし、実行中のwinword.exeプロセスをスローした場合にのみサグします。 理由は明確ではありませんが、Googleは、オフィスがサーバーアプリケーションを対象としておらず、私の状況でのその動作が予測できないことをMicrosoftが警告する記事に導きます。 また、そこで複数のwinwordプロセスを実行することは推奨されませんでした。
すぐに言ってやった:
第3世代:winword.exeへのアクセスの独占
別の処理要求は、Wordが既に実行されているかどうかを確認します。 このチェックは、データベースまたはPIDファイルを介して実行できます。 私はDBを使いました。 フラグフィールドの値は、リクエストごとに増加します。 多くのリクエストがあった場合、ハングしたプロセスがハングしていることを意味し、次にkillword.exeマジックプログラムが起動します。 それは、winword.exeと呼ばれるすべてのプロセスを愚かに殺します。
すべてが正常に機能しているように見えますが、時間の経過とともにスクリプトの実行時間が増加し、キルワードを実行する必要がますます多くなっています。 永続的な例外...
第4世代:リリースハンドラー
エラーの原因を丹念に調べた結果、非常に興味深い結果が得られました。 ファイルを開いたり保存した後、制御はphpスクリプトに戻りますが、同時にCOMサーバーはしばらくビジーのままです。 この時点で次のコマンドをCOMサーバーに送信すると、Exceptionにジャンプします 。 その後、Wordを強制終了して、最初からやり直すことができます。
この問題は、一時フォルダーにコピーするだけで解決しました。 Wordがフォルダーをスキャンして一時ファイルなどを探していることが判明しました。 時間が経つにつれて、ソースフォルダー内のファイルの数が増加し、スクリプトがクラッシュし始めました。
一般に、最後の作業スキームが最も効率的でした。 「メモリ不足」などのエラーが表示される場合がありますが、これは非常にまれであり、依然として秘密です:-)
だから: DOCハンドラー操作スキーム
ハンドラーは、tmanager.phpとhandler.phpの2つのファイルで構成されます。
1. tmanger.php
これは常に動作する(またはタスクスケジューラを介して定期的に起動する)デーモンです。 n秒ごとに、彼はデータベースのテーブルをチェックして、次の処理要求(いわゆるキュー)を探します。
アプリケーションがある場合は、次のアクションを実行します。
- 一時フォルダー(%SYSTEM_ROOT%\ TEMPを含む)からすべてのファイルを削除します
- すべてのワードプロセスを強制終了します(killword.exe)
- ソースファイルを一時フォルダーにコピーする
- handler.phpを実行します(curl経由)
- 結果のファイルを共有フォルダーにコピーします
- 一時ファイルと不要なプロセスをクリーンアップする
- データベースキューからエントリを削除する
2. handler.php
これはハンドラーそのものです。 別のファイルでは、ハングした場合に取り出されます。 しばらくして結果が返されない場合、tmanager.phpはkillwordを起動します。
以下はその簡略化されたコードです。
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
<?php try { $doc = new COM( "Word.Document" ); $doc->Range->InsertFile( 'E:\\tmp\\tmp1.doc' ); // $doc->SaveAs( 'E:\\tmp\\tmp2.doc' ); $doc = null ; } catch (Exception $e) { print '3' ; $doc = null ; die(); } print 0; ?> * This source code was highlighted with Source Code Highlighter .
tmanager.phpスクリプトは、handler.phpファイルをスクリプトに渡して処理します。 後者はそれを処理し、新しいファイルを作成します。 handler.phpがハングした場合、tmanager.phpはwinwordを強制終了します。
結論
- 直接送信されたファイルを開かずに、ファイルを挿入してください。
- 複数のWinword.exeプロセスを実行しないでください-競合する可能性があります。
- 多数のファイルを含むフォルダー内のファイルを開いたり保存したりしないでください。Wordはこれらのファイルをスキャンし、同時に「スローダウン」を試みます。
- COMで動作するプロセスをメインプロセスから分離します。 これにより、最初のハング時にいくつかのアクションを実行できます。
更新:サーバーの自動化に関する記事へのリンクが見つかりました。 最後の読書以来、彼女はロシア語になり、少し成長しました。