質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

解決済

2回答

1665閲覧

Ajaxでフォームの内容をPHPに渡してPDFを作成し文字列を引き渡し、受け取った文字列をjavascriptでPDF化したい

coool

総合スコア29

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

0クリップ

投稿2023/06/01 08:15

編集2023/06/02 01:04

実現したいこと

Laravel8を利用し、WEBアプリを作成しています。
実現したい流れとしては下記の通りです。

①クライアント側でフォームを入力する
②フォーム入力後、ダウンロードボタンを押させる。
**③ボタン押下後、サーバーに保存してあるPDFのテンプレートを使用してフォーム内容を書き込み、一度ローカルデバイスに作成したPDFをダウンロードさせる。
**→こちらが今回の質問項目です。
④デバイス上にPDFがダウンロードされたのを確認した後、改めて送信用のボタンを押させて内容をPOSTし、データをサーバーに保存する

聞きたいこと

上記③の内容を、下記のやり方で行おうと考えております。
HTML上で作成したフォームを非同期でPOSTしてPHPにフォーム内容を受け渡し、TCPDFを活用してPDF化。
その後、PDFを文字列として出力(Output($path, "S"))し、出力した文字列をJSON形式でクライアント側に受け渡します。
受け取った文字列をjavascriptでBlobの形へ変換し、自動でダウンロードを行おうと考えています。
伺いたいのは下記の点です。

  • 文字列形式のPDFを受け渡すところまで成功しましたが、その文字列をjavascriptでBlobの形に変換ができません。
  • タブレットでの運用を考えていますが、Ajaxリクエスト成功時に自動ダウンロードをさせることは可能でしょうか。(Safari使用)

前提

Laravel8.83.27
PHP 8.1.17
使用ブラウザ:Safari/Chrome
参考にしたサイト:https://kumatech-lab.com/tcpdf-output
(非同期でダウンロード)

エラー文

pdf_receipt_head.js:306 Uncaught TypeError: str.blob is not a function
(let blob = str.blob(); →js26行目☓)

該当のソースコード

javascript

1$("#download").click(function () { 2 var formdata = new FormData($('#form-id')[0]); 3 4 $.ajax({ 5 headers: { 6 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') 7 }, //Headers 必須。呪文 8 url: "{{ route('ajaxdownload.post') }}", 9 method: 'POST', //リクエストタイプ 10 dataType: 'JSON', 11 data: form, 12 processData: false, 13 contentType: false, 14 data: formdata, 15 //リクエストが完了するまで実行される 16 beforeSend: function () { 17 document.getElementById('download_message').innerHTML = "ダウンロード中。。。"; 18 } 19 }) 20 // Ajaxリクエスト成功時の処理 21 .done(function (json) { 22 console.log(json); 23 let str = JSON.stringify(json); 24//↑ここまで成功! 25//↓ここからが分からず。。。。 26 let blob = str.blob(); 27 const url = URL.createObjectURL(blob); 28 const a = document.createElement('a'); 29 document.body.appendChild(a); 30 a.href = url; 31 32 let filename = 'sample.pdf'; 33 a.download = filename; 34 a.click(); 35 a.remove(); 36 37 console.log("ajaxでPDFのDL成功!"); 38 }) 39 // Ajaxリクエスト失敗時の処理 40 .fail(function (jqXHR, textStatus, errorThrown) { 41 alert('ダウンロードに失敗しました。本ページのスクリーンショットを保存し、送信ボタンを押してください。'); 42 console.log("ajax通信に失敗しました。Chromeコンソール画面のプレビューからエラー詳細を確認してください。"); 43 console.log("jqXHR : " + jqXHR.status); // HTTPステータスが取得 44 console.log("textStatus : " + textStatus); // タイムアウト、パースエラー 45 console.log("errorThrown : " + errorThrown.message); // 例外情報 46 document.getElementById('download_message').innerHTML = "ダウンロード失敗。スクリーンショットを撮ってください。"; 47 }) 48 // 成否にかかわらず実行 49 .always(function () { 50 $('#post_button').show(); 51 }) 52 53})

PHP

1public function ajax_download(Request $e) 2 { 3 //連想配列を作成 4 $request = [ 5 //formの中身を連想配列に変換 6 ]; 7 $pdfdata = $this->pdf_export($request); //←このfunctionの中でnew TCPDF_FONTS();し、受け取ったformの内容を座標指定してPDFを作成 8 $pdf = $pdfdata["pdf"]; 9 $path = $pdfdata["path"];//PDFの格納先のpath 10 $JSON_PDF = mb_convert_encoding($pdf->Output($path, "S"), 'UTF-8', 'UTF-8'); 11 $array = ['JSON_PDF' => $JSON_PDF]; 12 //json形式で返却 13 return response()->json($array); 14 }

補足情報(FW/ツールのバージョンなど)

知識不足な上丸投げな質問しかできず申し訳ありません。。
もしかしたら基礎的な知識が不足している場合もありますので、必要な情報が他にあればご指摘いただければ幸いです。
ご教授お願い致します!

2023.06.02
ご指摘をいただき、文章を修正いたしました。
AbeTakashi様、ご指摘ありがとうございます!

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AbeTakashi

2023/06/01 11:26

この質問文で具体的に何をしたいかが伝わってないと思います。特に「javascriptを用いてPDFを再構築」「javascriptでどうやってPDF形式に直せばいいのか」あたりの表現は他人に伝わる表現ではなく、これだけの情報量だと(エスパーが登場しない限りは)回答できる人がいないかと思います。 やりたいことが伝わるように参考画像、フローチャートやシーケンス図、似たようなサービスをしてるところがあればそれらの参考URLなどがあると、答えられる人がいるかもしれません。これらの情報を質問文を編集して追記することをオススメします。
yambejp

2023/06/02 00:30

状況がわからないのですが、サーバー側で一旦pdf化してそれを文字列にしてクライアントに返すなら、最初からpdf化なんてしなければいいのでは?
coool

2023/06/02 00:57

>AbeTakashi様 ご指摘ありがとうございます! 申し訳ありません。。 自分でも理解しきれておらず、的確な質問ができていませんでした。 編集いたしました。 >yambejp様 やりたいことの全体像のご説明ができておりませんでした。 分かりにくく申しわけありません。。 フローの追記をいたしました。
Lhankor_Mhy

2023/06/02 00:57

文字列形式のPDFとは、どのようなフォーマットですか? PHPは全く詳しくないのですが、普通にバイナリやBase64で送信することはできないのでしょうか。
coool

2023/06/02 01:12 編集

>Lhankor_Mhy様 TCPDFで出力をする「Output」関数を使用する際、出力形式は下記の5種類から選べるそうです。 「I」・・・表示 「D」・・・ダウンロード 「F」「FI」「FD」・・・ファイル作成 「FI」は表示も 「FD」はダウンロードも 「E」・・・メール用文字列を返却 「S」・・・文字列を返却 base64も考えはしたのですが、TCPDFで出力できる形式がどれもしっくりこず。 一旦今回はこちらのサイトの通りに出力形式「S」を利用してクライアント側でblobの形にする方法を試しています。 (https://kumatech-lab.com/tcpdf-output ) お恥ずかしい話ですが、実際のところ私自身「文字列形式のPDF」がどのようなフォーマットか理解ができておりません。 申し訳ございません。。 「D」も試してはみましたが、うまくいきませんでした。
Lhankor_Mhy

2023/06/02 01:18

あー、「参考にしたサイト」を拝見して、なんとなく、たぶん、バイナリかな? という気分になりました。 それで、jQuery は blob を扱えないから JSON で渡しているのですね。 たぶん、jQuery を諦めて、「参考にしたサイト」のように処理するのが早いですが、jQuery は必須条件なのですか?
Lhankor_Mhy

2023/06/02 01:29

もし、どうしても jQuery でバイナリやblobを受信したい、ということであれば、なんらかのプラグインが必要になるような気がします。(最新のバージョンまではキャッチアップしてませんが、少なくとも2系ぐらいまでは) この辺りが参考になるのでは。 https://qiita.com/yuma84/items/fefb95c1a10396070cd2 あと、メールの添付ファイルはBase64なので、「メール用文字列」というのはワンチャンあるのでは、という感想を持ちました。
coool

2023/06/02 01:32

Laravelを利用した際の書き方がjQueryを使用したものしか見たことがなかったので、jQueryに固執していました。ちょっと試してみます!
coool

2023/06/02 01:34

>Lhankor_Mhy様 参考サイトまでありがとうございます!
coool

2023/06/02 02:31

>Lhankor_Mhy様 ありがとうございます!!!! https://github.com/henrya/js-jquery/tree/master/BinaryTransport こちらを追加したところ、PC上ではうまくいきました!!!!! 残念ながらSafariではDLしたはずのPDF形式がHTMLになってしまいうまく表示されませんでしたが、PC上で動作を確認できただけで一歩前進することができました。 ありがとうございます!
guest

回答2

0

自己解決

Jqueryはバイナリを取得できないため、JSON形式での引き渡しを行おうとして詰まっていました。
しかしこちらの記事を参考にしてバイナリをJqueryで取得できる関数の読み込みを行った結果、無事ダウンロードが完了しました!
Lhankor_Mhy様、そしてアドバイスを頂けた皆様、本当にありがとうございます!

javascript

1 2 $.ajax({ 3 headers: { 4 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') 5 }, //Headers 必須。呪文 6 url: "{{ route('ajaxdownload.post') }}", 7 method: 'POST', //リクエストタイプ 8 dataType: 'JSON', 9 data: form, 10 processData: false, 11 contentType: false, 12 data: formdata, 13 //リクエストが完了するまで実行される 14 beforeSend: function () { 15 document.getElementById('download_message').innerHTML = "ダウンロード中。。。"; 16 } 17 }) 18 // Ajaxリクエスト成功時の処理 19 .done(function (json) { 20 console.log(json); 21 const url = URL.createObjectURL(json); 22 const a = document.createElement('a'); 23 document.body.appendChild(a); 24 a.href = url; 25 26 let filename = 'sample.pdf'; 27 a.download = filename; 28 a.click(); 29 a.remove(); 30 document.getElementById('download_message').innerHTML = "ダウンロードに成功しました!<br><span class='text-danger fw-bold'>続いて送信ボタンを押してください。</span>"; 31 }) 32 // Ajaxリクエスト失敗時の処理 33 .fail(function (jqXHR, textStatus, errorThrown) { 34 alert('ダウンロードに失敗しました。本ページのスクリーンショットを保存し、送信ボタンを押してください。'); 35 console.log("ajax通信に失敗しました。Chromeコンソール画面のプレビューからエラー詳細を確認してください。"); 36 console.log("jqXHR : " + jqXHR.status); // HTTPステータスが取得 37 console.log("textStatus : " + textStatus); // タイムアウト、パースエラー 38 console.log("errorThrown : " + errorThrown.message); // 例外情報 39 document.getElementById('download_message').innerHTML = "ダウンロード失敗。スクリーンショットを撮ってください。"; 40 }) 41 // 成否にかかわらず実行 42 .always(function () { 43 $('#post_button').show(); 44 }) 45 46}) 47/** 48* 49* jquery.binarytransport.js 50* 51* @description. jQuery ajax transport for making binary data type requests. 52* @version 1.0 53* @author Henry Algus <henryalgus@gmail.com> 54*https://qiita.com/yuma84/items/fefb95c1a10396070cd2 55* 56*/ 57 58(function ($, undefined) { 59 "use strict"; 60 61 // use this transport for "binary" data type 62 $.ajaxTransport("+binary", function (options, originalOptions, jqXHR) { 63 // check for conditions and support for blob / arraybuffer response type 64 if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) { 65 return { 66 // create new XMLHttpRequest 67 send: function (headers, callback) { 68 // setup all variables 69 var xhr = new XMLHttpRequest(), 70 url = options.url, 71 type = options.type, 72 async = options.async !== false, 73 // blob or arraybuffer. Default is blob 74 dataType = options.responseType || "blob", 75 data = options.data || null, 76 username = options.username || null, 77 password = options.password || null; 78 79 xhr.addEventListener('load', function () { 80 var data = {}; 81 data[options.dataType] = xhr.response; 82 // make callback and send data 83 callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders()); 84 }); 85 xhr.addEventListener('error', function () { 86 var data = {}; 87 data[options.dataType] = xhr.response; 88 // make callback and send data 89 callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders()); 90 }); 91 92 xhr.open(type, url, async, username, password); 93 94 // setup custom headers 95 for (var i in headers) { 96 xhr.setRequestHeader(i, headers[i]); 97 } 98 99 xhr.responseType = dataType; 100 xhr.send(data); 101 }, 102 abort: function () { } 103 }; 104 } 105 }); 106})(window.jQuery); 107

PHP

1public function ajax_download(Request $e) 2 { 3 //連想配列を作成 4 $request = [ 5 //formの中身を連想配列に変換 6 ]; 7 $pdfdata = $this->pdf_export($request); //←このfunctionの中でnew TCPDF_FONTS();し、受け取ったformの内容を座標指定してPDFを作成 8 $pdf = $pdfdata["pdf"]; 9 $path = $pdfdata["path"];//PDFの格納先のpath 10//JSON形式での引き渡しをやめて、そのままreturn 11   $PDF = $pdf->Output($path, "S"); 12 return $PDF; 13 }

投稿2023/06/02 04:41

coool

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

非同期で受け取ったpdfファイルを別のサーバーに非同期でおくればよいのでしょうか?
(pdfをPHPで作る部分は命題がブレるので最初からpdfファイルがあるものとして回答)

javascript

1<script> 2let blob=null; 3document.addEventListener('click',async ({target})=>{ 4 if(target.matches('#get')){ 5 blob=await fetch('test.pdf').then(res=>res.blob()); 6 const src=await new Promise(resolve => { 7 const reader = new FileReader(); 8 reader.onloadend = () => resolve(reader.result); 9 reader.readAsDataURL(blob); 10 }); 11 document.querySelector('iframe').src=src; 12 } 13 if(target.matches('#send') && blob){ 14 const body = new FormData(); 15 body.append("myfile",blob,"new.pdf"); 16 fetch("upload.php",{method:"post",body}).then(res=>res.text()).then(console.log); 17 } 18}); 19</script> 20 21<input type="button" value="get" id="get"> 22<iframe src=""></iframe> 23<input type="button" value="send" id="send">

※上記iframeにpdfを表示する必要はありませんが

投稿2023/06/02 04:03

編集2023/06/02 04:27
yambejp

総合スコア115245

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coool

2023/06/02 04:51

回答ありがとうございます! わかりにくい説明で申し訳ありません… ①非同期で受け取ったPDFファイルを一回デバイスに保存 ②ダウンロード完了後、別のサーバーに同期処理で送る という処置を行いたかったです。 未熟な質問で本当にお恥ずかしいばかりです。。。 アドバイスを頂いたことを踏まえて再度コードを書いたところ無事ダウンロードは動いたため、自己完結という形でクローズさせていただきます。 色々とお知恵をいただき、ありがとうございます! いただいたコードは今後の参考にさせていただきたいと思います。 本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問