PHPについて質問です。


最初に正解に導いていただいた方に300ポイント差し上げます。
ただし回答が正解であっても私が理解できない可能性があります。
初心者の私が理解できたかどうかということで判断しますので、
あらかじめご了承ください。

googleの検索結果ページにある「1234・・」というようなリンクを作り、
データを1ページ10件ごとに分けて表示したいです。
一般的にはPearのpagerを使うのでしょうが、
うまく使えません。そこで下記のいずれかでご回答ください。

①Pearのpagerの使い方を初心者でもわかるよう説明してください。
これについてはネットで結構調べましたが解決できませんでした。

②あるいは下記のスクリプトの使い方を教えてください。
http://ryouchi.seesaa.net/article/45846102.html
たとえば50件あるデーを10件ずつ5ページに分けるよう設定したつもりですが、
「12345」という数字のリンクは表示されるだけで、
どのページも50件のデータが1ページに表示されます。
またこの関数に使われているidという概念もよくわからないので、
これは何を意味しているのかということも併せてご説明ください。

Vista,PHP5,Firefoxでやっています。
よろしくお願いします。

回答の条件
  • 1人2回まで
  • 登録:2008/11/18 16:40:57
  • 終了:2008/11/24 23:53:54

ベストアンサー

id:tobeoscontinue No.4

tobeoscontinue回答回数214ベストアンサー獲得回数542008/11/21 16:13:34

ポイント300pt
①Pearのpagerの使い方を初心者でもわかるよう説明してください。
<?php
require_once 'Pager.php';

$data = range(1,50);

$params = array('mode'=>'Sliding','perPage'=>10,'delta'=>4,'itemData'=>$data);

$pager = & Pager::factory($params);
foreach ($pager->getPageData() as $d) echo "<p>$d</p>";
echo "<hr>";
echo $pager->links;
?>

$dataはテスト用のダミーデータです。

$paramsの'itemData'でPagerにデータを渡します。こうすることでgetPageData()で、そのページで表示する分だけのデータを受け取ることができます。後は$pager->linksでリンクのhtmlを表示できます。

factoryへ渡す$paramsについてはhttp://pear.php.net/manual/ja/package.html.pager.factory.phpで知ることができます。

データが小さい場合はいいのでしょうが、DB内のデータを全て取り込むというのでは現実的ではありません。

"totalItems"を指定すればgetOffsetByPageID()でfrom,toを入手できますので、それで必要な部分だけ読み込むことができます。http://www.alberton.info/pear_pager_tutorial_database_results.ht...

②あるいは下記のスクリプトの使い方を教えてください。

この関数はリンクのhtmlは生成しますが、データの表示については感知しません。

idはページ指定の受渡しのためにGETを用いているのですが、その名前を指定するものです。

Pearのpagerで言う"urlVar"です。(固定にすると名前がぶつかる場合があるための配慮ではないでしょうか。)

<?php
$data = range(1,50);

$f = (max(1, intval($_GET[PAGE_VALUE]))-1)*PER_PAGE;
$t = min($f+PER_PAGE, count($data))-$f;
foreach (array_slice($data, $f, $t) as $d) echo "<p>$d</p>";
echo "<hr>";
pager(PAGE_VALUE,count($data));
?>

$_GET[PAGE_VALUE]の値を表示とpager関数と別々に処理しないといけないというのはしっくりしませんが。


いずれにしろ、htmlの生成までしてしまうので気にいらなければ修正が必要になります。

pager関数のほうが小さくて簡単だと思いますがPearのpagerを真似て(微妙に異なります)Classにしてみました。

<?php
class Pager {
  private $params;
  private $now;  // 現在ページ
  private $max;  // 最大ページ
  function __construct($params) {
    $default = array("urlVar"=>'p',"url"=>$_SERVER['SCRIPT_NAME'].'?','delta'=>5,'perPage'=>10,
      'prevImg'=>'&lt;', 'nextImg'=>'&gt;', "separator"=>'&nbsp;|&nbsp;');
    $this->params = array_merge($default, $params);
    if (isset($params["itemData"]))
      $this->params["totalItems"] = count($params["itemData"]);
    $id = $this->params["urlVar"];
    $this->max = intval(($this->params["totalItems"]-1)/$this->params["perPage"])+1;
    $this->now = min(max(1, intval($_GET["$id"])), $this->max);
  }
  function getOffsetByPageID($now=NULL) {
    $now = ($now === NULL) ? $this->now : $now;
    $wing = $this->params["perPage"];
    $from = ($now-1)* $wing;
    return array($from, min($from+$wing, $this->params["totalItems"])-$from);
  }
  function getPageData($pageID=NULL) {
    list($s, $l) = $this->getOffsetByPageID($pageID);
    return array_slice($this->params["itemData"], $s, $l);
  }
  function rangeBar($delta) {
    $left = max(1, $this->now-$delta);
    $right = min($left+$delta+$delta-1, $this->max);
    if ($right-$left+1 < $delta+$delta) $left = max(1, $right-$delta-$delta+1);
    return range($left, $right);
  }
  function toAncher($no,$value) {
    return '<a href="'.$this->params["url"].$this->params["urlVar"].'='.$no.'">'.$value.'</a>';
  }
  function toArrow($no, $value) {
    return (0 < $no && $no <= $this->max) ? $this->toAncher($no, $value) : '';
  }
  function func_map($no) {
    return ($this->now != $no) ? $this->toAncher($no, $no) : $no;
  }
  function __toString() {
    return ($this->max < 2) ? '' :
     implode("&nbsp;:&nbsp;", array_filter(array(
        $this->toArrow($this->now-1, $this->params["prevImg"]),
        implode($this->params["separator"],
          array_map(array($this,"func_map"), $this->rangeBar($this->params["delta"]))),
        $this->toArrow($this->now+1, $this->params["nextImg"]))));
  }
}
?>

ぐっと詰めて書いたのでわかりづらいですがhtmlの部分はtoAncher()の一行です。

やっていることはrangeBar()で[1,2,3,...10]のような配列を作ることです。後はこの配列をhtmlに変換するだけ。

<?php
$data = range(1,50);

$params = array('perPage'=>10, 'itemData'=>$data);

$pager = new Pager($params);
foreach ($pager->getPageData() as $d) echo '<p>'.$d.'</p>';
echo '<hr>';
echo $pager;
?>
id:taroemon

ご回答ありがとうございます。

風邪を引いていたので、いただいたご回答を試すことができませんでした。

返事が遅れて済みません。


①の回答について

下記のようなエラーが出ました。

Warning: Unexpected character in input: ' in (中略)/Pager/Sliding.php on line 287


②の回答について

かなり手応えを感じています。ちょっと時間を加えればうまくいきそうです。

1ページ目に50件のデータが表示され、2ページ目に何もないという状態になっています。

また最初の1ページ目には「?id=1」と表示されません。


急いでお返事するために、あまり時間をかけて試してません。

いただいたご回答を元にもう少しがんばってみようとお思います。

2008/11/23 23:38:55

その他の回答(3件)

id:goodvn No.1

goodvn回答回数228ベストアンサー獲得回数182008/11/18 18:16:51

ポイント20pt

http://www.phpbook.jp/pear/pear_pager/

この辺にある,サンプルプログラムを全部書き写して動かしてみましたか?

プログラムを覚えるには,ひたすら書くのも手です.ここで聞いてる時間に,コードをたくさん書いた方が覚えられると思います.

ちなみに,ご質問のページング処理というのは,ウェブサービスを作る上で,常に面倒な処理の一つです.PEAR::Pager も一つの手ですが,慣れてくれば,いろんな方法があることが分かるでしょう.

私の場合は,テンプレートエンジンに Smarty,元データは RMDBS(MySQLなど) を使うために,それに適した独自のページング処理を行っています.RMDBS の場合,SQL で,

LIMIT 21,11

といったように,ページングに適したデータ数が取得できるので,このデータを使うことで解決しています.11件取ってきてるのは,10件表示後に,まだ続きがあるかを知る事で,"次へ" のリンクを出すか決定するためです.

Google みたいなリンクを出す場合は,総数を知らないといけないので,そういう処理も必要ですね.

id:taroemon

ご回答ありがとうございます。

風邪を引いていたので、いただいたご回答を試すことができませんでした。

返事が遅れて済みません。

ご紹介いただいたリンク大変参考になりました。じっくり拝見します。

2008/11/23 23:05:36
id:Quphondi No.2

Quphondi回答回数59ベストアンサー獲得回数22008/11/18 23:13:27

ポイント20pt

私が実装したときに作ったミニマムの動作サンプルコードです。

<?php
require_once("Pager/Pager.php");

$totalItems = 50; // 表示対象となる全ての要素の数
                   // RDBと連携する場合は、全要素数を取得する
$ROW_MAX = 10;     // 1ページあたりの表示要素数

// 各ページの表示関数関数
function showPage($start,$cnt){
	print("<li>Start:$start - Item Per Page:$cnt");
	print("<ol>");
	for($i=0; $i<$cnt; $i++){
		$item = $start +$i;
		print("<li>[$item]");
	}
	print("<ol>");
}

// Pager のパラメータ
$params = array(
	"perPage"    => $ROW_MAX,
	"totalItems" => $totalItems,
);
$o_page = Pager::factory($params); // コンストラクタではなく、factoryで生成
$navi   = $o_page->getLinks();
print($navi['all']);
print("<hr />");
showPage(($o_page->getCurrentPageID()-1)*$ROW_MAX,$ROW_MAX);
?>

Pear::Pager自体は、Pageナビゲーションの部分を生成してくれるだけです。ページ表示を行う部分(関数)は別途書く必要があります。上記のサンプルではshowPage()がそれに当たります。

RDBと連携しているのであれば、limit句、offset句で最大表示数と表示開始要素を指定してあげます。具体的にはこんなコードです。

 

$sql ="select * from db_samlpe  limit $cnt offset $start;";

 ひとまず、こんなところで

 

id:taroemon

ご回答ありがとうございます。

風邪を引いていたので、いただいたご回答を試すことができませんでした。

返事が遅れて済みません。


いただいたスクリプトをそのまま貼り付けてみたところ下記のようなエラーが複数できました。

Warning:: Unexpected character in input: ' in (中略)/Pager/Common.php on line 962

複数のエラーはいずれも962行目に関することのようです。

おそらくこれは簡単なことで解決できるのかもしれませんが、私にはうまくいきませんでした。

ちなみにRDBは使用していません。


急いでお返事するために、あまり時間をかけて試してません。

いただいたご回答を元にもう少しがんばってみようとお思います。

2008/11/23 23:05:23
id:ilo No.3

sakai回答回数9ベストアンサー獲得回数22008/11/19 19:00:18

ポイント20pt

2のスクリプトの使い方ですが、指定ページから10件表示するという処理は自分で作成しないといけません。

そのためには現在開いているページ番号を取得する必要があります。

ページ番号はどこに設定されているかというと、

pager関数の第一引数をidにした場合は、ページ毎のリンク先URLに?id=1といった形で設定されています。


実際にこの値を取り出すには、$_GETという配列を利用します。

$_GET['id']で現在開いているページ番号が取得できます。

ただし最初にページを開いた場合は$_GET['id']に何も入っていないので、$_GET['id']が空の場合は1ページにするという処理が必要になります。

あとはPER_PAGEに取得件数が定義されているので、この二つのデータを利用して取得するデータを絞りこんで下さい。


ご質問のあったidはページ番号のことです。

id:taroemon

ご回答ありがとうございます。

風邪を引いていたので、いただいたご回答を試すことができませんでした。

返事が遅れて済みません。


やっとこの関数のidのことが完全に理解することができました。

作成されたファイルには「12345」というリンクがあるのですが、

1ページ目のアドレスには「?id=1」という表記がありません。

2ページ目以降には?id=2」等とあるのですが、1ページ目と同じ内容になってしまいます。

また、1ページに10件ごとの情報を5ページ、合計50件の情報を表示したいのですが、

全部のページが1ページに50件の情報が掲載されているという状態になってしまいます。


急いでお返事するために、あまり時間をかけて試してません。

いただいたご回答を元にもう少しがんばってみようとお思います。

2008/11/23 23:05:12
id:tobeoscontinue No.4

tobeoscontinue回答回数214ベストアンサー獲得回数542008/11/21 16:13:34ここでベストアンサー

ポイント300pt
①Pearのpagerの使い方を初心者でもわかるよう説明してください。
<?php
require_once 'Pager.php';

$data = range(1,50);

$params = array('mode'=>'Sliding','perPage'=>10,'delta'=>4,'itemData'=>$data);

$pager = & Pager::factory($params);
foreach ($pager->getPageData() as $d) echo "<p>$d</p>";
echo "<hr>";
echo $pager->links;
?>

$dataはテスト用のダミーデータです。

$paramsの'itemData'でPagerにデータを渡します。こうすることでgetPageData()で、そのページで表示する分だけのデータを受け取ることができます。後は$pager->linksでリンクのhtmlを表示できます。

factoryへ渡す$paramsについてはhttp://pear.php.net/manual/ja/package.html.pager.factory.phpで知ることができます。

データが小さい場合はいいのでしょうが、DB内のデータを全て取り込むというのでは現実的ではありません。

"totalItems"を指定すればgetOffsetByPageID()でfrom,toを入手できますので、それで必要な部分だけ読み込むことができます。http://www.alberton.info/pear_pager_tutorial_database_results.ht...

②あるいは下記のスクリプトの使い方を教えてください。

この関数はリンクのhtmlは生成しますが、データの表示については感知しません。

idはページ指定の受渡しのためにGETを用いているのですが、その名前を指定するものです。

Pearのpagerで言う"urlVar"です。(固定にすると名前がぶつかる場合があるための配慮ではないでしょうか。)

<?php
$data = range(1,50);

$f = (max(1, intval($_GET[PAGE_VALUE]))-1)*PER_PAGE;
$t = min($f+PER_PAGE, count($data))-$f;
foreach (array_slice($data, $f, $t) as $d) echo "<p>$d</p>";
echo "<hr>";
pager(PAGE_VALUE,count($data));
?>

$_GET[PAGE_VALUE]の値を表示とpager関数と別々に処理しないといけないというのはしっくりしませんが。


いずれにしろ、htmlの生成までしてしまうので気にいらなければ修正が必要になります。

pager関数のほうが小さくて簡単だと思いますがPearのpagerを真似て(微妙に異なります)Classにしてみました。

<?php
class Pager {
  private $params;
  private $now;  // 現在ページ
  private $max;  // 最大ページ
  function __construct($params) {
    $default = array("urlVar"=>'p',"url"=>$_SERVER['SCRIPT_NAME'].'?','delta'=>5,'perPage'=>10,
      'prevImg'=>'&lt;', 'nextImg'=>'&gt;', "separator"=>'&nbsp;|&nbsp;');
    $this->params = array_merge($default, $params);
    if (isset($params["itemData"]))
      $this->params["totalItems"] = count($params["itemData"]);
    $id = $this->params["urlVar"];
    $this->max = intval(($this->params["totalItems"]-1)/$this->params["perPage"])+1;
    $this->now = min(max(1, intval($_GET["$id"])), $this->max);
  }
  function getOffsetByPageID($now=NULL) {
    $now = ($now === NULL) ? $this->now : $now;
    $wing = $this->params["perPage"];
    $from = ($now-1)* $wing;
    return array($from, min($from+$wing, $this->params["totalItems"])-$from);
  }
  function getPageData($pageID=NULL) {
    list($s, $l) = $this->getOffsetByPageID($pageID);
    return array_slice($this->params["itemData"], $s, $l);
  }
  function rangeBar($delta) {
    $left = max(1, $this->now-$delta);
    $right = min($left+$delta+$delta-1, $this->max);
    if ($right-$left+1 < $delta+$delta) $left = max(1, $right-$delta-$delta+1);
    return range($left, $right);
  }
  function toAncher($no,$value) {
    return '<a href="'.$this->params["url"].$this->params["urlVar"].'='.$no.'">'.$value.'</a>';
  }
  function toArrow($no, $value) {
    return (0 < $no && $no <= $this->max) ? $this->toAncher($no, $value) : '';
  }
  function func_map($no) {
    return ($this->now != $no) ? $this->toAncher($no, $no) : $no;
  }
  function __toString() {
    return ($this->max < 2) ? '' :
     implode("&nbsp;:&nbsp;", array_filter(array(
        $this->toArrow($this->now-1, $this->params["prevImg"]),
        implode($this->params["separator"],
          array_map(array($this,"func_map"), $this->rangeBar($this->params["delta"]))),
        $this->toArrow($this->now+1, $this->params["nextImg"]))));
  }
}
?>

ぐっと詰めて書いたのでわかりづらいですがhtmlの部分はtoAncher()の一行です。

やっていることはrangeBar()で[1,2,3,...10]のような配列を作ることです。後はこの配列をhtmlに変換するだけ。

<?php
$data = range(1,50);

$params = array('perPage'=>10, 'itemData'=>$data);

$pager = new Pager($params);
foreach ($pager->getPageData() as $d) echo '<p>'.$d.'</p>';
echo '<hr>';
echo $pager;
?>
id:taroemon

ご回答ありがとうございます。

風邪を引いていたので、いただいたご回答を試すことができませんでした。

返事が遅れて済みません。


①の回答について

下記のようなエラーが出ました。

Warning: Unexpected character in input: ' in (中略)/Pager/Sliding.php on line 287


②の回答について

かなり手応えを感じています。ちょっと時間を加えればうまくいきそうです。

1ページ目に50件のデータが表示され、2ページ目に何もないという状態になっています。

また最初の1ページ目には「?id=1」と表示されません。


急いでお返事するために、あまり時間をかけて試してません。

いただいたご回答を元にもう少しがんばってみようとお思います。

2008/11/23 23:38:55
  • id:taroemon
    皆さんご回答ありがとうございます。

    回答へのお返事にもありますととおり、体調を崩しており、
    現在、じっくりと取り組むことができません。
    締め切りが迫ってきたのでとりあえずお返事をしましたが、
    時間をかければいずれかの回答を手がかりにうまくいきそうな手応えをつかんでいます。
    もし、締め切り後にうまくいきましたら、
    コメント欄にその旨報告し、後日ポイント送信にて、残りのポイントをお送りさせていただきます。

    また、エラーを解決していただいた方には、
    当該回答の方のポイントとあわせて300ポイントとさせていただきます。
    質問者個人の主観に基づいて割り振らせていただきますのであらかじめご了承ください。
  • id:tobeoscontinue
    ①の回答について
    >下記のようなエラーが出ました。
    >Warning: Unexpected character in input: ' in (中略)/Pager/Sliding.php on line 287
    原因は特定できませんがファイルに全角の空白など変な文字コードが含まれているということは無いでしょうか。

    ②の回答について
    >1ページ目に50件のデータが表示され、2ページ目に何もないという状態になっています。
    pager関数はデータの表示には感知していませんのでどのように表示しているかによります。
    コピペしたコードでそうなるようでしたら$fと$tの値を確認してみてください。

    >また最初の1ページ目には「?id=1」と表示されません。
    現在表示しているページにリンクしても意味が無いということだと思いますが、わざわざリンクが付かないようにしています。
    表示した方がいいというのであれば
    $page_footer.= " ".(($id==$i)?"<span style='font-Size:120%'>$i</span>":"<ahref=\"$PHP_SELF?$idname=$i$other_param\">$i</a>");

    $page_footer.= " "."<a href=\"$PHP_SELF?$idname=$i$other_param\">$i</a>";
    とすれば表示されます。
  • id:taroemon
    tobeoscontinueさん

    おかげさまでうまくいきました。
    まだちょっと不安定なところもありますので、
    この件で後日あらためて質問するかもしれません。
    お時間がありましたらまたご回答ください。
    ありがとうございました。
  • id:tobeoscontinue
    私の書いたコードへの質問でしたらここのコメントに書いていただければと思います。
    また多くのポイントをありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません