با سلام به همراهان روکسو! در این مقاله آموزشی قصد داریم به شما نحوه ساخت Pagination یا صفحه بندی در php را آموزش دهیم.
معمولا زمانی که از دستور SELECT برای دریافت اطلاعات از پایگاه داده استفاده می کنیم، خروجی بسیار بزرگی خواهیم داشت. فرض کنید که می خواهیم پست های سایت خود را به کاربر نمایش دهیم و حدود 1000 پست مختلف نیز در پایگاه داده خود داریم. به نظر شما چطور باید این کار را انجام دهیم؟
اگر دستوری شبیه به دستور زیر را اجرا کنیم:
SELECT * FROM POSTS
تمام 1000 پست ها به سمت کاربر برگردانده می شود! جدا از هزینه پردازشی که چنین دستوری روی سرور ما می گذارد، تجربه بسیار بدی را نیز برای کاربران به وجود می آورد. تصور کنید در صفحه اول سایت خود 1000 پست را نمایش دهیم؛ کاربر باید 1000 پست را به همراه متن و تصاویرشان دریافت کند! سپس مرورگر همه را در صفحه اول نمایش دهد! حالا فرض کنید کاربر بخواهد به قسمت footer سایت برود تا اطلاعات تماس شما یا نماد تایید تجارت الکترونیک شما را چک کند! اگر 1 ساعت هم اسکرول کند به انتهای سایت شما نخواهد رسید. تمام این مشکلات و مشکلات متعدد دیگر از دلایل وجود مبحثی به نام Pagination یا صفحه بندی در php هستند. در واقع نمایش تمام نتایج در صفحه اول مانند چاپ کتابی است که تمام مطالبش در یک صفحه 20 متری قرار داشته باشد!
با استفاده از مبحث صفحه بندی در php می توانیم کاری کنیم که نتایج برگشت داده شده از سمت پایگاه داده را به قسمت های مساوی تقسیم کنیم تا کاربر مثلا 10 پست اول را در صفحه اول سایت ببیند و اگر دوست داشت پست های بیشتری را مشاهده کند روی شماره صفحات کلیک کند تا بین آن ها جا به جا شود. تکنولوژی مورد استفاده ما در این آموزش زبان PHP و پایگاه داده MySQL است.
برای شروع کار فایلی به نام pagination.php ایجاد کنید. در ابتدا باید به پایگاه داده خود متصل شویم:
$mysqli = mysqli_connect('localhost', 'root', '', 'pagination');
همانطور که می بینید با استفاده از رابط mysqli به پایگاه داده متصل شده ایم که قالب کلی زیر را دارد:
mysqli_connect(YOUR_HOST, YOUR_USERNAME, YOUR_PASSWORD, YOUR_DATABASE)
اگر با اتصال به پایگاه داده آشنا نیستید بهتر است روش اتصال PDO را یاد بگیرید؛ به مقالات آموزشی PDO در روکسو مراجعه کنید.
من برای اجرای مثال هایمان یک پایگاه داده به نام pagination طراحی کرده ام. کد های SQL طراحی این پایگاه داده را در اختیار شما قرار می دهم تا بتوانید با استفاده از آن پایگاه داده را برای خودتان بسازید:
CREATE DATABASE IF NOT EXISTS `pagination` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE `pagination`; CREATE TABLE IF NOT EXISTS `students` ( `id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `age` tinyint(1) NOT NULL, `joined` varchar(10) NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8; INSERT INTO `students` (`id`, `name`, `age`, `joined`) VALUES (1, 'David Deacon', 23, '17/08/2018'), (2, 'Sheri Warner', 19, '03/05/2018'), (3, 'Sean Glover', 24, '24/07/2018'), (4, 'John West', 17, '13/08/2018'), (5, 'Rufus Clarke', 20, '28/07/2018'), (6, 'Roosevelt Myers', 20, '25/07/2018'), (7, 'Elvira Andrews', 22, '02/07/2018'), (8, 'Richard Cook', 26, '19/07/2018'), (9, 'Lorenzo Harris', 23, '01/07/2018'), (10, 'Eduardo Hoffman', 17, '03/07/2018'), (11, 'Jeanne Fisher', 20, '13/08/2018'), (12, 'Tracy Bowers', 30, '07/07/2018'), (13, 'Heidi Lawrence', 18, '04/06/2018'), (14, 'Tara Holland', 25, '01/07/1991'), (15, 'Grant Edwards', 22, '22/06/2018'), (16, 'Bradford Green', 29, '02/05/2018'), (17, 'Gwen Schultz', 20, '02/05/2018'), (18, 'Hope Dawson', 28, '21/08/2018'), (19, 'Florence Osborne', 19, '17/05/2018'), (20, 'Rickey Poole', 26, '28/06/2018'), (21, 'Casey Sutton', 28, '06/07/2018'), (22, 'Willie Lowe', 23, '11/05/2018'), (23, 'Stephen Schultz', 28, '15/07/2018'), (24, 'Eileen Lynch', 18, '12/06/2018'), (25, 'Aaron Ruiz', 29, '02/05/2018'), (26, 'Mae Murray', 30, '24/06/2018'), (27, 'Regina Hanson', 21, '26/07/2018'), (28, 'Cameron Mclaughlin', 20, '29/07/2018'), (29, 'Earl Hale', 17, '30/06/2018'), (30, 'Marta Blair', 24, '10/06/2018'), (31, 'Alberta Silva', 22, '05/06/2018'), (32, 'Joanna Holmes', 20, '20/05/2018'), (33, 'Alex Brock', 30, '12/05/2018'), (34, 'Colin Wright', 19, '28/05/2018'), (35, 'Peter Schmidt', 25, '10/07/2018'), (36, 'Joshua Price', 27, '13/07/2018'), (37, 'Elias Chandler', 22, '19/07/2018'), (38, 'Stanley Ross', 21, '02/06/2018'), (39, 'Vera Cole', 26, '02/05/2018'), (40, 'Johnny Daniels', 29, '19/07/2018'), (41, 'Yvonne Hopkins', 21, '16/07/2018'); ALTER TABLE `students` ADD PRIMARY KEY (`id`); ALTER TABLE `students` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=42;
شما می توانید این کدهای SQL را در phpMyAdmin یا هر سیستم مدیریت پایگاه داده ای که دوست دارید اجرا کنید تا پایگاه داده برایتان ساخته شود. به فایل pagination.php
برگردید. در قدم اول باید متغیرهای مهمی را تعریف کنیم:
// Get the total number of records from our table "students". $total_pages = $mysqli->query('SELECT COUNT(*) FROM students')->fetch_row()[0]; // Check if the page number is specified and check if it's a number, if not return the default page number which is 1. $page = isset($_GET['page']) && is_numeric($_GET['page']) ? $_GET['page'] : 1; // Number of results to show on each page. $num_results_on_page = 5;
در خط اول با استفاده از دستور COUNT تعداد کل ردیف های موجود در جدول students را مشخص کرده ایم تا بعدا بتوانیم با تقسیم کردن آن بر عددی خاص بفهمیم در کل چند صفحه خواهیم داشت. مثلا اگر کل ردیف ها 500 ردیف باشد و ما بخواهیم در هر صفحه 10 پست نمایش داده شود بنابراین 50 صفحه خواهیم داشت. سپس با استفاده از دستور isset چک می کنیم که آیا page مشخص شده است یا خیر؛ page یک پارامتر ورودی به صورت GET در نوار آدرس مرورگر خواهد بود که برنامه نویسی آن به عهده شما است و به سایت شما بستگی دارد. این پارامتر معمولا به شکل زیر پاس داده خواهد شد:
pagination.php?page=3
البته حواستان باشد که اگر در برنامه نویسی سایت خود نام پارامتر پاس داده شده را چیزی به جز page بگذارید، باید به دنبال همان مقدار بگردید. در مرحله بعد، پس از آنکه مطمئن شدیم این پارامتر در url وجود دارد، در همان شرط بررسی کرده ایم که آیا از نوع عددی است؟ اگر عدد نبود صفحه 1 را در نظر می گیریم. علت این کار این است که page یک پارامتر ورودی در نوار آدرس مرورگر (GET) است بنابراین کاربران می توانند به راحتی و به صورت دستی مقدار متفاوتی را وارد url کنند که غیر عددی باشد. مثلا:
pagination.php?page=somethingElse
در آخر نیز متغیری تعریف کرده ایم که تعداد نتایج نمایش داده شده در هر صفحه را مشخص مکند؛ ما می خواهیم در هر صفحه 5 پست بیشتر نمایش داده نشود.
تا اینجای کار خوب پیش آمدیم. در ادامه نتایج را از پایگاه داده دریافت کرده و آن ها را در صفحه HTML نمایش خواهیم داد.
تا اینجا توضیح دادیم که چطور یک پایگاه داده و جدول (students) بسازیم. سپس برخی از موارد بدیهی و مقدمات صفحه بندی مطالب در PHP را برایتان توضیح دادیم و حالا باید نتایج را از پایگاه داده ای که چند لحظه پیش ساختیم، دریافت کنیم:
if ($stmt = $mysqli->prepare('SELECT * FROM students ORDER BY name LIMIT ?,?')) { // Calculate the page to get the results we need from our table. $calc_page = ($page - 1) * $num_results_on_page; $stmt->bind_param('ii', $calc_page, $num_results_on_page); $stmt->execute(); // Get the results... $result = $stmt->get_result(); $stmt->close(); }
در کد بالا و در قدم اول دستور خود را prepare کرده ایم تا از بروز حملات SQL Injection جلوگیری کنیم. متغیر calc_page$ نیز همان ایندکس آغازین در جدول ما است و کدی که برایش می بینید قانون ثابتی است که همیشه برایش نوشته می شود. شما می توانید آن را در پروژه خود کپی کنید. این کد می گوید page را از url گرفته و 1 واحد از آن کم کن سپس نتیجه را در متغیر num_results_on_page (تعداد پست ها در هر صفحه) ضرب کن. مثلا اگر در صفحه 1 باشیم 1 منهای 1 می شود صفر که در هر چه ضرب شود همان صفر خواهد بود بنابراین ایندکس شروع نتایج در جدول پایگاه داده صفر خواهد بود؛ به زبان ساده تر از همان نتیجه اول به تعداد مورد نظرمان نتایج را برگردان. اگر یادتان رفته است دستور LIMIT ساختار زیر را دارد:
SELECT * FROM your_table LIMIT 5, 5
این دستور می گوید ردیف های 6 و 7 و 8 و 9 و 10 را برگردان! توجه داشته باشید که ایندکس از صفر شروع می شود و پارامترهای LIMIT نیز همان ایندکس ها هستند بنابراین LIMIT 5, 5 یعنی از ایندکس 5 شروع کن (که می شود ردیف ششم) و 5 ایندکس جلوتر برو. اگر برای دستور LIMIT فقط یک پارامتر بنویسید، مقدار عدد اول (که به آن offset می گوییم) صفر در نظر گرفته می شود یعنی:
SELECT * FROM your_table LIMIT 5
این دستور می گوید: 5 ردیف اول را برگردان.
در مرحله بعد با دستور bind_param پارامتر ها را به کوئری prepare شده می چسبانیم. اگر از این مقاله یادتان باشد دو حرف i که پشت سر هم آمده اند مخفف integer (عدد صحیح) هستند. یعنی فقط عدد صحیح قبول کن. ما می توانستیم چهار نوع مقدار را در این قسمت مشخص کنیم:
در آخر هم با دستور execute کوئری را اجرا کرده و با get_result نتایج را گرفته ایم. در حال حاضر نتایج ما در متغیر result قرار دارد.
در قدم بعدی باید نتایج دریافت شده را نمایش دهیم. حتما متوجه شده اید که در کدهای SQL برای ساخت پایگاه داده یک جدول به نام students داریم. ما می خواهیم دانش آموزان را به صورت صفحه بندی شده در یک جدول نمایش دهیم. البته شما می توانید با سلیقه خودتان آن ها را در چیز دیگری به غیر از جدول ها نمایش دهید اما انتخاب ما برای این آموزش بدین شکل است:
<table> <tr> <th>Name</th> <th>Age</th> <th>Join Date</th> </tr> <?php while ($row = $result->fetch_assoc()): ?> <tr> <td><?php echo $row['name']; ?></td> <td><?php echo $row['age']; ?></td> <td><?php echo $row['joined']; ?></td> </tr> <?php endwhile; ?> </table>
اگر در مورد نحوه دریافت داده ها (مانند متد fetch_assoc چیزی نمیدانید به دوره های PHP و SQL ما مراجعه کنید). خلاصه دستورات بالا این است که نتایج را به صورت یک آرایه متناظر (associative array) دریافت میکنیم و با دستور while تک تک نتایج دریافت شده را در جدول نمایش می دهیم. این جدول شامل name (نام دانش آموز) و Age (سن دانش آموز) و Join Date (تاریخ ثبت نام دانش آموز) می باشد.
حالا نوبت نمایش pagination یا صفحه بندی در php است قبل از شروع کدنویسی به یاد داشته باشید که استایل pagination ما مانند تصویر زیر است:
حالا کدهای Pagination:
<?php if (ceil($total_pages / $num_results_on_page) > 0): ?> <ul class="pagination"> <?php if ($page > 1): ?> <li class="prev"><a href="pagination.php?page=<?php echo $page-1 ?>">Prev</a></li> <?php endif; ?> <?php if ($page > 3): ?> <li class="start"><a href="pagination.php?page=1">1</a></li> <li class="dots">...</li> <?php endif; ?> <?php if ($page-2 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-2 ?>"><?php echo $page-2 ?></a></li><?php endif; ?> <?php if ($page-1 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-1 ?>"><?php echo $page-1 ?></a></li><?php endif; ?> <li class="currentpage"><a href="pagination.php?page=<?php echo $page ?>"><?php echo $page ?></a></li> <?php if ($page+1 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+1 ?>"><?php echo $page+1 ?></a></li><?php endif; ?> <?php if ($page+2 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+2 ?>"><?php echo $page+2 ?></a></li><?php endif; ?> <?php if ($page < ceil($total_pages / $num_results_on_page)-2): ?> <li class="dots">...</li> <li class="end"><a href="pagination.php?page=<?php echo ceil($total_pages / $num_results_on_page) ?>"><?php echo ceil($total_pages / $num_results_on_page) ?></a></li> <?php endif; ?> <?php if ($page < ceil($total_pages / $num_results_on_page)): ?> <li class="next"><a href="pagination.php?page=<?php echo $page+1 ?>">Next</a></li> <?php endif; ?> </ul> <?php endif; ?>
اولین کاری که در کد بالا انجام داده ایم بررسی این مورد است که آیا تعداد صفحات ما بیشتر از 1 صفحه است؟ چراکه اگر فقط یک صفحه داشته باشیم نیازی ندارد صفحه بندی خاصی را نمایش دهیم (بی معنی است). سپس چک کرده ایم که آیا صفحه فعلی (مقدار page در url در حال حاضر) بزرگ تر از 1 است یا خیر. اگر بزرگ تر بود یعنی صفحاتی قبل از آن وجود دارد بنابراین دکمه «صفحه قبل» را نمایش می دهیم که همان عبارت Prev در کد بالا است. همچنین می خواهیم اگر page بیشتر از 3 بود دکمه صفحه اول را نیز نمایش دهیم. این کارها بر اساس سلیقه شخصی ما است و شما می توانید منطق کد خود را کاملا تغییر دهید. دلیل این کار من این است که اگر page بالاتر از 3 باشد (مثلا در صفحه 20 باشیم)، استفاده از دکمه «صفحه قبل» سخت می شود و کاربر باید 19 بار کلیک کند تا به صفحه اول برسد بنابراین صفحه اول را نمایش می دهیم تا کار کاربر راحت تر شود. دکمه ای که سه نقطه دارد نیز برای زیباتر شدن و جداسازی دکمه های فعلی از دکمه های قبلی است (به تصویری که بالاتر به شما دادم توجه کنید). کدهای پس از آن نیز بسیار ساده هستند؛ دکمه فعلی را برای صفحه فعلی نوشته ایم و سپس دو دکمه بعد و قبل از آن را نیز نشان داده ایم. سپس دکمه سه نقطه و دکمه آخرین صفحه را با همان شرط قبلی (وجود حداقل دو صفحه تا آخرین صفحه) نمایش داده ایم. در مرحله آخر نیز دکمه «صفحه بعد» (عبارت next در کد بالا) را کدنویسی کرده ایم. بنابراین مثلا اگر در صفحه 5 باشیم دکمه ها بدین شکل خواهند بود:
1 ... 3 4 5 6 7 ... 14
برای استایل دهی جدول نیز از استایل های زیر استفاده کرده ایم:
table { border-collapse: collapse; width: 500px; } td, th { padding: 10px; } th { background-color: #54585d; color: #ffffff; font-weight: bold; font-size: 13px; border: 1px solid #54585d; } td { color: #636363; border: 1px solid #dddfe1; } tr { background-color: #f9fafb; } tr:nth-child(odd) { background-color: #ffffff; } .pagination { list-style-type: none; padding: 10px 0; display: inline-flex; justify-content: space-between; box-sizing: border-box; } .pagination li { box-sizing: border-box; padding-right: 10px; } .pagination li a { box-sizing: border-box; background-color: #e2e6e6; padding: 8px; text-decoration: none; font-size: 12px; font-weight: bold; color: #616872; border-radius: 4px; } .pagination li a:hover { background-color: #d4dada; } .pagination .next a, .pagination .prev a { text-transform: uppercase; font-size: 12px; } .pagination .currentpage a { background-color: #518acb; color: #fff; } .pagination .currentpage a:hover { background-color: #518acb; }
نتیجه نهایی کد ما جدولی به شکل زیر است:
کد کامل فایل pagination.php را نیز در اختیار شما می گذارم تا با آن تمرین کنید:
<?php // Below is optional, remove if you have already connected to your database. $mysqli = mysqli_connect('localhost', 'root', '', 'pagination'); // Get the total number of records from our table "students". $total_pages = $mysqli->query('SELECT * FROM students')->num_rows; // Check if the page number is specified and check if it's a number, if not return the default page number which is 1. $page = isset($_GET['page']) && is_numeric($_GET['page']) ? $_GET['page'] : 1; // Number of results to show on each page. $num_results_on_page = 5; if ($stmt = $mysqli->prepare('SELECT * FROM students ORDER BY name LIMIT ?,?')) { // Calculate the page to get the results we need from our table. $calc_page = ($page - 1) * $num_results_on_page; $stmt->bind_param('ii', $calc_page, $num_results_on_page); $stmt->execute(); // Get the results... $result = $stmt->get_result(); ?> <!DOCTYPE html> <html> <head> <title>PHP & MySQL Pagination by CodeShack</title> <meta charset="utf-8"> <style> html { font-family: Tahoma, Geneva, sans-serif; padding: 20px; background-color: #F8F9F9; } table { border-collapse: collapse; width: 500px; } td, th { padding: 10px; } th { background-color: #54585d; color: #ffffff; font-weight: bold; font-size: 13px; border: 1px solid #54585d; } td { color: #636363; border: 1px solid #dddfe1; } tr { background-color: #f9fafb; } tr:nth-child(odd) { background-color: #ffffff; } .pagination { list-style-type: none; padding: 10px 0; display: inline-flex; justify-content: space-between; box-sizing: border-box; } .pagination li { box-sizing: border-box; padding-right: 10px; } .pagination li a { box-sizing: border-box; background-color: #e2e6e6; padding: 8px; text-decoration: none; font-size: 12px; font-weight: bold; color: #616872; border-radius: 4px; } .pagination li a:hover { background-color: #d4dada; } .pagination .next a, .pagination .prev a { text-transform: uppercase; font-size: 12px; } .pagination .currentpage a { background-color: #518acb; color: #fff; } .pagination .currentpage a:hover { background-color: #518acb; } </style> </head> <body> <table> <tr> <th>Name</th> <th>Age</th> <th>Join Date</th> </tr> <?php while ($row = $result->fetch_assoc()): ?> <tr> <td><?php echo $row['name']; ?></td> <td><?php echo $row['age']; ?></td> <td><?php echo $row['joined']; ?></td> </tr> <?php endwhile; ?> </table> <?php if (ceil($total_pages / $num_results_on_page) > 0): ?> <ul class="pagination"> <?php if ($page > 1): ?> <li class="prev"><a href="pagination.php?page=<?php echo $page-1 ?>">Prev</a></li> <?php endif; ?> <?php if ($page > 3): ?> <li class="start"><a href="pagination.php?page=1">1</a></li> <li class="dots">...</li> <?php endif; ?> <?php if ($page-2 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-2 ?>"><?php echo $page-2 ?></a></li><?php endif; ?> <?php if ($page-1 > 0): ?><li class="page"><a href="pagination.php?page=<?php echo $page-1 ?>"><?php echo $page-1 ?></a></li><?php endif; ?> <li class="currentpage"><a href="pagination.php?page=<?php echo $page ?>"><?php echo $page ?></a></li> <?php if ($page+1 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+1 ?>"><?php echo $page+1 ?></a></li><?php endif; ?> <?php if ($page+2 < ceil($total_pages / $num_results_on_page)+1): ?><li class="page"><a href="pagination.php?page=<?php echo $page+2 ?>"><?php echo $page+2 ?></a></li><?php endif; ?> <?php if ($page < ceil($total_pages / $num_results_on_page)-2): ?> <li class="dots">...</li> <li class="end"><a href="pagination.php?page=<?php echo ceil($total_pages / $num_results_on_page) ?>"><?php echo ceil($total_pages / $num_results_on_page) ?></a></li> <?php endif; ?> <?php if ($page < ceil($total_pages / $num_results_on_page)): ?> <li class="next"><a href="pagination.php?page=<?php echo $page+1 ?>">Next</a></li> <?php endif; ?> </ul> <?php endif; ?> </body> </html> <?php $stmt->close(); } ?>
یادتان باشد که راه های بسیار مختلفی برای صفحه بندی مطالب در PHP یا ساخت pagination در سایت شما وجود دارد و مرز و حدودی نمی شناسد (چه از نظر استایل دهی ها و چه از نظر کدهای HTML و PHP) اما روشی که به شما آموزش دادیم یکی از امن ترین و بهترین روش های موجود در حال حاضر در صفحه بندی مطالب در PHP است. امیدوارم توانسته باشم آموزش خوبی را برای شما تهیه کرده باشم.
منبع: وب سایت codeshack
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.