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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Q&A

解決済

2回答

3362閲覧

WordPressにおいて、PHPで直接データベースから記事情報を得るときの処理について

mic

総合スコア9

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

0グッド

0クリップ

投稿2015/05/18 09:31

WordPressで、登録したユーザに
細かく閲覧権限を与えることができるプラグインの機能を使用して
記事の閲覧制限を行いたく、コードを作成いたしました。

プラグインはWishListMemberというプラグインです。

このプラグインを使用すると、例えば、

ユーザA

  • 閲覧レベル1
  • 閲覧レベル2

ユーザB

  • 閲覧レベル2
  • 閲覧レベル3

ユーザC

  • 閲覧レベル3
  • 閲覧レベル4

といったようにユーザ毎にレベルを設定できます。
また記事毎にもレベルが設定できます。
「閲覧レベル1」を持った記事は、
「閲覧レベル1」を持った「ユーザA」しか見ることができません。
同じように、
「閲覧レベル2」を持った記事は、
「閲覧レベル2」を持った「ユーザA」と「ユーザB」しか見ることができません。

しかし、このプラグインでは、
記事の閲覧制限はできますが、
記事が見れないユーザにも一覧表示されてしまうのです。

ややこしくて大変申し訳ないです…。
ここまでが前提条件です。

そこで、直接DBにアクセスし、
ユーザレベルと記事に設定されたレベルが一致した記事のみを一覧表示するようなコードを、

PHP初心者ながらに四苦八苦しながら何とか作成し、
無事に思った通りの結果を得ることができました。

が、問題はここからで、
このテーマを設置したさくらサーバで
503エラーが頻発するようになってしまいました。
(さくらのリソース情報によると、一番多いときで約10万回/1日です)

もしかしたらサーバやプランを変えることで解決できるのかもしれません。
さくらサーバにも現在問い合わせている状況です。

しかし素人が作ったプログラムのせいで、
エラー処理などが甘く、サーバに多大な負荷をかけている可能性が高いと思い、
みなさまのお力をお借りすることができればと考えております。

以下が実際に作成したコードです(名前などは変更してあります)。
post_contentlevelsには記事のレベルが、
user_userlevelsにはユーザに設定されたレベルが入っております。

拙いプログラムで大変恐縮ではございますが、
負荷を軽減するアドバイスや、
正しいエラー処理などを教えていただけると幸いです。

どうかよろしくお願い致します!!

lang

1<?php 2 3//データベース情報読み込み 4include( get_bloginfo('url').'/wp-config.php'); 5 6//データベース情報代入 7$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8'; //ホストとデータベース名 8$user = DB_USER; //ユーザ名 9$password = DB_PASSWORD; //パスワード 10 11//データベース接続 12try { 13 $dbh = new PDO($dsn,$user,$password); 14} catch(PDOException $e) { 15 var_dump($e->getMessage()); 16 exit; 17} 18 19//ユーザ情報取得 20$wpm_current_user = wp_get_current_user(); 21 22//ユーザレベル代入 23$user_id = $wpm_current_user->ID; 24 25//管理者以外の場合に実行する処理 26if ($user_id != 1) { 27 $sql = "SELECT `content_id` FROM `post_contentlevels` JOIN `user_userlevels` ON `post_contentlevels`.level_id=`user_userlevels`.level_id WHERE `user_userlevels`.user_id=$user_id"; 28 //クエリ発行、メンバーレベル識別子の取得 29 $stmt = $dbh->query($sql); 30 //データの数を数える 31 $count = $dbh->query($sql)->fetchColumn(); 32 //データが存在するときに実行する処理 33 if ( $count > 0 ) { 34 //変数宣言 35 $i = 0; 36 $post_pre = array(); 37 $num = 1; 38 //配列の数だけループ 39 foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $content_id) { 40 //記事IDから記事情報取得,配列として$postへ代入 41 $post = get_post($content_id['content_id'], "ARRAY_A"); 42 $post_pre[$i] = $post; 43 $i++; 44 } 45 46 //投稿日時でソート 47 foreach($post_pre as $key=>$value){ 48 $date[$key]=$value['post_date']; 49 } 50 51 //ソート 52 array_multisort($date,SORT_ASC,SORT_NATURAL,$post_pre); //昇順 53 54 //記事を表示するループ 55 for($n = 0; $i > 0; $i--){ 56 //記事IDからカテゴリIDを取得 57 foreach( (get_the_category( $post_pre[$n]['ID'] ) ) as $obj) 58 { 59 $cat_id = $obj->category_parent; 60 if( strcmp($cat_id,'0')==0 ) { 61 $cat_id = $obj->cat_ID; 62 } 63 } 64 //現在のカテゴリと一致し、かつ公開設定の投稿記事だけ表示 65 if($cat_id == $cat && $post_pre[$n]['post_status'] == 'publish' && $post_pre[$n]['post_type'] == 'post'){ 66 ?> 67 <div class="*****"> 68 <a href="<?php echo($catSlug);echo'/';echo($post_pre[$n]['ID']); ?>"> 69 <h2><?php echo($post_pre[$n]['post_title']); ?></h2> 70 </a> 71 </div> 72 <?php 73 } //if($cat_id == $cat && $post_pre[$n]['post_status'] == 'publish' && $post_pre[$n]['post_type'] == 'post') 74 $n++; 75 } //for($n = 0; $i > 0; $i--) 76 } //if ( $count > 0 ) 77 78 //記事IDがない場合に実行する処理 79 else { 80 echo "<p>表示可能な記事がありません</p>"; 81 } 82} //if ($user_id != 1) 83 84//管理者の場合に実行する処理 85else { 86 if(is_archive()) : query_posts($query_string.'&order=ASC'); endif; 87 if (have_posts()): 88 while (have_posts()): 89 the_post(); 90 get_template_part('content-archive'); 91 endwhile; 92 endif; 93} 94 95//データベース切断 96$dbh = null;

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

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

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

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

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

guest

回答2

0

HTTPレスポンスコードが503ならば、アプリでエラーがでてますね。

>(さくらのリソース情報によると、一番多いときで約10万回/1日です)
この時アクセスされてるURLの、IPアドレス・URLは一般の方なんですかね?

WordPressは内部からもCron起動などでCallされるケースがあるので、ユーザが取得できないケースでエラーなんか発生していないでしょうか?

503が発生する箇所を特定することを、オススメします。

頻発されてるようなので、私ならデバッグ文を埋め込み一時的に本番環境で寝かしときます。

投稿2015/05/18 15:40

kurosawa

総合スコア780

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

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

mic

2015/05/19 01:59

ご回答ありがとうございます! アクセスは私しかしておりません。 ただ、同サーバには他にもアクセスのあるサイトが入っているため、 もしかしたらそちらが原因かもしれません…。 引き続き調査続行してまいります。 >WordPressは内部からもCron起動などでCallされるケースがある なるほど…。 そのようなところでも負荷がかかっていないか調べてみますね。 ありがとうございます!
kurosawa

2015/05/19 08:57

1ユーザがブラウザからアクセスして、日に10万回503が返却されるという現象は、とても通常のアクセスで発生しているとは思えないんですよね。  1回/秒の503で、8万6千回/日です。 1日中テストとか入稿とかされてる状態が続き、そのあいだ1秒間に1回なんらかのアプリが失敗している。ということになります。 WordpressのCron設定がミスっていて、毎回wp-cron.phpが参照され、それが動作せず503で落ちている。とかないですかね? 503は高負荷だけに発生するものではありません。 自作箇所が本当にマズいのかどうか、まず切り分けをしたほうが良いと思います。 ウェブサーバのアクセスログから、503で落ちているリクエストのURLを見れば どのIPから来て、どのサイトのどの機能で落ちているかがわかると思うのですが、いかがでしょう。
mic

2015/05/19 15:11

ご返信ありがとうございます。 さくらからの返答により、 どうやら別サイトが障害の原因になっているかもしれないとのことでした。 今回アドバイスをお願いしたサイトのエラーログなどを見てみましたが、 CPU使用時間やメモリ消費に問題はなさそうでした。 そのため、 別サイトに障害の原因があると判断し、 kurosawaさまにアドバイスいただいたように、 アクセスログなどを見て原因を特定しようと思います。 熱心にアドバイスいただき、本当にありがとうございます。 大変参考になりました。 ですが、大変恐縮ではございますが、 今回、具体的なコードで効率化についておしえてくださった SaintKnowledgeさまのご回答をベストアンサーとさせてください。 アドバイスいただいた皆さま、誠にありがとうございました。
kurosawa

2015/05/19 15:25

ですよね。原因は別なのかなぁ〜と思っていました。 > SaintKnowledgeさまのご回答をベストアンサーとさせてください。 いえいえ、お気になさらないでください。 今回の問題が解決することが大事ですので! ロール制御の組み込み、がんばってください。
guest

0

ベストアンサー

負荷よりもSQLが気になります。いろいろな方法があるかと思いますが、私なら、ということで、先にuser_userlevelsからログインしている?ユーザのレベルを取得します。

その後、1ユーザに対してレベルが複数なら、

SELECT * FROM post_contentlevels INNER JOIN category ON category.id = post_contentlevels.category_id WHERE post_contentlevels.level_id IN (閲覧レベル1, 閲覧レベル2) AND post_status = 'publish' AND post_type = 'post' ORDER BY post_contentlevels.post_date

みたいにすると、ユーザレベルに応じた記事、カテゴリ名が表示され、かつ日付順に取り出せるかと。また約20行ほどコードが節約出来そうな気がします。(category ON category.id = post_contentlevels.category_id部分は想像ですので、使われている適切な名前に変えてください。)
ユーザのログインがありきで一覧を表示するなら、こうすればuser_userlevelsのJOINは不要と思います。

負荷については、データ件数によるかもしれません。数千件の記事データ×数千件のユーザ、でしょうか?いずれにせよ、すべてのデータを対象としているようなSQLに見受けられるので、上記の通りにすると劇的に変わるかもしれません。

投稿2015/05/18 14:02

編集2015/05/18 14:04
SaintKnowledge

総合スコア368

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

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

mic

2015/05/19 02:07

ご回答ありがとうございます! なるほど。 仰るとおり、そのような形で効率的なものに修正してみます! 記事は、まだテスト用の記事が10記事ほど、 ユーザもまだテストで作成したアカウントが1つだけです。 ですが、今後記事を増やしていくことを考えると、 効率よくやらないといけませんね…。 例文まで出していただき、ありがとうございました! アドバイス通り修正し、 問題が解決したらベストアンサーとさせてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問