Egyszerű CGI számláló bash, perl és C nyelveken

Először is engedélyezzük a cgi modul-t az Apache webszerverünkben. Ez pár sor Debian 10.5 alatt root-ként (rendszergazdaként).

root@gergo1:/etc/apache2/mods-enabled# ln -s ../mods-available/cgi.load
root@gergo1:/etc/apache2/mods-enabled# ls -l
..
lrwxrwxrwx 1 root root 26 Aug 12 02:24 cgi.load -> ../mods-available/cgi.load
root@gergo1:/etc/apache2/mods-enabled# service apache2 reload

root@gergo1:/etc/apache2/conf-enabled# ls -l
..
lrwxrwxrwx 1 root root 36 Aug 28  2017 serve-cgi-bin.conf -> ../conf-available/serve-cgi-bin.conf

Nézzük a serve-cgi-bin.conf konfigurációs file tartalmát!

<IfModule mod_alias.c>
        <IfModule mod_cgi.c>
                Define ENABLE_USR_LIB_CGI_BIN
        </IfModule>

        <IfModule mod_cgid.c>
                Define ENABLE_USR_LIB_CGI_BIN
        </IfModule>

        <IfDefine ENABLE_USR_LIB_CGI_BIN>
                ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
                <Directory "/usr/lib/cgi-bin">
                        AllowOverride None
                        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                        Require all granted
                </Directory>
        </IfDefine>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Látható, hogy a /usr/lib/cgi-bin könyvtárban kell létrehozzuk a számlálóinkat bash, perl és C nyelveken. Nézzük az elsőt bash shell script nyelven!

#!/bin/bash

printf "Content-type: text/html\n\n"
let COUNTER++
printf "$COUNTER\n"

És akkor teszteljük le parancssorból, majd web-en!

gvamosi@gergo1:/usr/lib/cgi-bin$ chmod +x counter.sh 
gvamosi@gergo1:/usr/lib/cgi-bin$ ./counter.sh 
Content-type: text/html

1

Látható, hogy 1-et ír ki, ha parancssorban futtatjuk.

Ha megnézzük weben is a http://localhost/cgi-bin/counter.sh cím alatt, ugyanez az eredmény. Látható, hogy elég a Content-type beállítása a válasz fejlécében, majd kettő soremelés után bármit kiírathatunk. 🙂

A Content-type egyébként az ún. media type (régebben MIME type) értéket tartalmazza. Részletek: https://en.wikipedia.org/wiki/Media_type.

És akkor nézzük ugyanezt perl nyelven!

#!/usr/bin/perl

use strict;
use warnings;

print "Content-type: text/html\n\n";

my $a = 0;
&number();

sub number {
  $a++;
  print "number \$a = $a\n";
}

A parancs kimenete hasonlatos mind parancssorban, mind a http://localhost/cgi-bin/counter.pl webcím alatt.

gvamosi@gergo1:/usr/lib/cgi-bin$ chmod +x counter.pl 
gvamosi@gergo1:/usr/lib/cgi-bin$ ./counter.pl 
Content-type: text/html

number $a = 1

Végül nézzük meg C nyelven. Megjegyzem: a C nyelvű scriptet a gcc programcsomag segítségével le kell fordítanunk. 🙂

#include <stdio.h>

int i=0;

int incrementcount()
{

  i++;
  return i;
}

int main()
{
  printf("Content-type: text/html\n\n");
  printf("The current count is: ");
  printf("%d\n", incrementcount());
  return 0;
}

És akkor nézzük meg a fordítást majd a kimenetet. Ugyanez lesz látható a http://localhost/cgi-bin/counter.cgi webcím alatt is.

gvamosi@gergo1:/usr/lib/cgi-bin$ gcc counter.c -o counter.cgi
gvamosi@gergo1:/usr/lib/cgi-bin$ ls -l
total 32
-rw-r--r-- 1 gvamosi gvamosi   216 Aug 12 03:05 counter.c
-rwxr-xr-x 1 gvamosi gvamosi 16720 Aug 12 03:05 counter.cgi
-rwxr-xr-x 1 gvamosi gvamosi   158 Aug 12 02:47 counter.pl
-rwxr-xr-x 1 gvamosi gvamosi    84 Aug 12 02:37 counter.sh
gvamosi@gergo1:/usr/lib/cgi-bin$ ./counter.cgi 
Content-type: text/html

The current count is: 1

Bámulatos, nem? 🙂 Hogy mire lesz jó ez az egész három különböző nyelvű, méghozzá benne egy natív C implementáció is? A következő fejezetekben kiderül!

Megjegyzés: natívan, bár gyorsabb a végeredmény, azért nem fejlesztünk többnyire, mert rendkívül bonyoluttá válik összetett oldalak esetén a programkód. Továbbá elég egy pici hiba, és már is “vulnerable”, azaz sérülékeny lehet a weboldalunk, amit a hacker-ek ún. exploit-tal ki tudnak használni, azaz adott esetben fel is törthetik az oldalainkon keresztül a szervereinket.

Kapcsolat oldal, levélküldés levélszerveren át

Először is telepítsük a sendmail levélszervert és a mail levelező programot, hogy legalább localhost-on le tudjuk tesztelni a levélküldést. Nagyon nem lesz nehéz dolgunk a CodeIgniter-t illetőleg, mivel támogatja a sendmail levelező csomagot.

root@gergo1:~# apt install sendmail
root@gergo1:~# apt-get install mailutils

Ezután teszteljük le a levélküldést. Tegyük fel, hogy fut a sendmail felépítmény (szerver, leírás https://en.wikipedia.org/wiki/Sendmail).

gvamosi@gergo1:/var/www/html/apartman/application$ mail -s "Teszt levél" gvamosi@localhost < /dev/null
mail: Null message body; hope that's ok
gvamosi@gergo1:/var/www/html/apartman/application$ mail
"/var/mail/gvamosi": 1 message 1 new
>N   1 gvamosi            Fri Aug  7 00:46  14/520   Teszt levél
? q
Held 1 message in /var/mail/gvamosi

Láthatjuk, hogy a levelünk “Teszt levél” tárggyal és üres tartalommal elküldésre került és szerencsésen meg is érkezett. 🙂 Helyben került kézbesítve, helyi feladótól. Ne ijedjünk meg, ha picit lassú a kézbesítés, a névfeloldás megy nehezen a sendmail-ünknek, mivel nem vagyunk internetre kötött ún. SMTP host, azaz hivatalos levélküldő szerver. Attól sem kell félnünk, hogy igazi levelet tudunk küldeni a nagyvilágba, ez így lehetetlen. 🙂

Részleteket az internetes levelezésről az alábbi címen találhatunk https://hu.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol.

Mindez szép és jó, de hogyan küldjük el akkor egy webes form-ból a levelet az adminisztrátornak, tehát a kapcsolatfelvételi formot hogyan is programozzuk le?

Vegyünk egy sima, nem JavaScript-es form-ot az egyszerűség kedvéért, majd használjuk a CodeIgniter email könyvtárát. Annyi lesz az egész, hogy be kell konfiguráljuk a sendmail-ünket, és meg kell hívnunk a megfelelő rutinokat a controller-ünkben űrlapküldés után.

Elsőnek hozzuk létre a kapcsolati űrlapot views/contact.php néven!

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li class="active"><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_contact'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-8 animate-box">
                                        <div class="form-wrap">
                                                <div class="row">
                                                        <form action="send" method="POST">
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="name" class="form-control" placeholder="Your name">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="email" class="form-control" placeholder="Your email">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <textarea id="message" name="message" class="form-control" id="" cols="30" rows="15" placeholder="Your message"></textarea>
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="submit" value="Send message" class="btn btn-primary btn-modify">
                                                                </div>
                                                        </div>
                                                        </form>
                                                </div>
                                        </div>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Látható, hogy ez egy sima form. Nem is fűzök hozzá magyarázatot.

Majd hozzük létre a visszajelző oldalt views/contact_sent.php néven!

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li class="active"><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_contact'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-8 animate-box">
                                        <div class="form-wrap">
                                                <div class="row">
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <h3><font color="red">Thank you for contacting us!</font></h3>
                                                                </div>
                                                        </div>
                                                </div>
                                        </div>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Ez is beton egyszerű.

Nézzük meg azt a három metódust, amivel a controllers/Apartments.php vezérlőnket bővítettük!

        public function contact() {
                $data = array();

                $this->template->set('title', $this->lang->line('menu_contact'));
                $this->template->load('menu_layout', 'contents', 'contact', $data);
        }

        public function send() {

                $this->load->library('email');

                $config['protocol'] = 'sendmail';
                $config['mailpath'] = '/usr/sbin/sendmail';
                $config['charset'] = 'utf-8';

                $this->email->initialize($config);

                $this->email->from($this->input->post('email'), $this->input->post('name'));
                // mail of administrator
                $this->email->to('gvamosi@localhost');
                $this->email->subject('Mail from booking site');
                $this->email->message($this->input->post('message'));

                $this->email->send();

                redirect(base_url('index.php/apartments/contact_sent'));
        }

        public function contact_sent() {
                $data = array();

                $this->template->set('title', $this->lang->line('menu_contact'));
                $this->template->load('menu_layout', 'contents', 'contact_sent', $data);
        }

A contact() metódus csupán kirajzol egy oldalt, ahogy a contact_sent() is. Az érdekesebb metódusunk a send(), amiben a tulajdonképpeni levélküldés történik. Ennyi az egész! 🙂 A valóságban persze az adminisztrátorok és a fejlesztők együttműködésére és közreműködésére van szükség mind fejlesztés, mind pedig a webalkalmazás telepítése során.

És akkor nézzük a http://localhost/apartman/index.php/apartments/contact oldalunkat!

Kis várakozás után megkapjuk a levelünket. Kettes sorszámmal látható a parancssori levelezőnkben. 🙂

gvamosi@gergo1:/var/www/html/apartman/application$ mail
"/var/mail/gvamosi": 2 messages 1 new 1 unread
 U   1 gvamosi            Fri Aug  7 00:46  17/564   Teszt levél
>N   2 Teszt Elek         Fri Aug  7 01:14  23/823   Mail from booking site
? q
Held 2 messages in /var/mail/gvamosi

Jelszóvédelem az admin oldalra, avagy az authentikáció egyszerű megoldása

Az adminisztrátori vagyis foglalás-menedzsment funkcionalitás eleve rejtve van a kíváncsi tekintetek elől, hiszen ha kint is van az Interneten, vagyis a “webtérben” az oldal, link nincs az admin oldalunkra a honlapon. Azonban ennél azért nagyobb biztonságra lesz szükségünk, ezért az egész admin funkcionalitást el kell rejtsük egy jelszóval védett területre.

A jelszavas védelmet a CodeIgniter keretrendszer alapban nem támogatja, viszont egyszerűen megvalósíthatjuk. Egyszerűen úgy működik, hogy a controller-ben a kívánt funkciók hívása előtt megvizsgáljuk, hogy előzőleg tároltunk-e el a szerver session-jében “user” változót a korábban lezajló login folyamat során, amelyben adatbázisban ellenőrizzük a felhasználó/jelszó párt. Van benne még technikailag pár átirányítás, hogy a webalkalmazásunk “visszataláljon” a “hívó” oldalra (referer) a sikeres jelszó hitelesítés (authentikáció) vagyis belépés (login) után.

És akkor most nézzük a konkrét implementációt.

Először is kell egy modell. Ez az models/Auth_model.php file-unk. Összezsúfoltam picit a kódot – nem szokásom amúgy -, hogy minél kevesebb sorban oldjam meg a feladatot. 🙂

<?php
class Auth_model extends CI_Model {
 public function login(){
  $query = $this->db->get_where('users', array('name' => $this->input->post('username'), 'password' => $this->input->post('password'))); 
  $result = $query->result();
  return (empty($result)?false:(empty($result[0])?false:true));
 }
}

Ez a login() metódus egy boolean – logikai – értékkel tér vissza attól függően, hogy megvan-e az adatbázisban a felhasználó/jelszó páros. Pár technikai észrevétel: a felhasználónévnek egyedinek kell lenni (ezt egy ún. unique key vagyis egyedi kulcs bitosítja SQL technikában), hogy nyilvánvalóan különbözzenek a felhasználóink. A gyakorlatban általában az e-mail címeket választják ki a mérnökök erre a célra, hiszen az mindenképpen egyedi. 🙂 Aztán a jelszó. Nem kódoltam le ebben a pilot alkalmazásban, de illik valamilyen egyirányú kódoló algoritmussal titkosítani, hogy senki se fejthesse vissza a jelszavakat az adatbázis ismeretében. 🙂

Nézzük a meg views/login.php view-nkat.

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_booking'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-8 animate-box">
                                        <div class="form-wrap">
                                                <div class="row">
                                                        <form action="login" method="POST">
                                                        <?php if ($auth_errors) { ?>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <h3><font color="red"><?php echo $auth_errors; ?></font></h3>
                                                                </div>
                                                        </div>
                                                        <?php } ?>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="username" class="form-control" placeholder="User Name">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="password" name="password" class="form-control" placeholder="Password">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="submit" value="Login" class="btn btn-primary btn-modify">
                                                                </div>
                                                        </div>
                                                        </form>
                                                </div>
                                        </div>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Ebben érdekes, hogy egy sima formot használunk, nem JavaScript-eset, és hogy password típusú mezőbe kérjük be a jelszót, amit nem lehet elolvasni a képernyőn, miközben begépeljük, csak pontokat látni a karakterek helyén. Ez a biztonságot szolgálja. Más kérdés, hogy a billentyűzetről is le tudja olvasni egy ügyes tekintetű illető a jelszót, úgyhogy ilyenkor illik “nem oda nézni” a harmadik félnek. 🙂

Majd nézzük a szintén nem túl bonyolult controller-ünket (controllers/AuthController.php). Megjegyzem, hogy végre beállítottam a config/config.php => $config['base_url'] = 'http://localhost/apartman/'; értéket, hogy használhassam az a base_url($path) metódust a redirect-ek (átirányítások) miatt. 🙂

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class AuthController extends CI_Controller {
  public function __construct(){
    parent::__construct();
  }
  public function is_logged($referer){
    $user = $this->session->userdata('user');
    if (empty($user)) {
      // not authenticated
      $this->session->set_userdata('login_url', $referer);
      redirect(base_url('index.php/AuthController/login_form'));
    }
  }
  public function login_form(){
    $data = array();

    $data['auth_errors'] = '';
    if (!empty($this->session->flashdata('auth_errors'))) {
      $data['auth_errors'] = $this->session->flashdata('auth_errors');
    }

    $this->template->set('title', 'Login');
    $this->template->load('menu_layout', 'contents', 'login', $data);
  }
  public function login(){
   $this->load->model('auth_model');

   $success = $this->auth_model->login(); 

   if ($success) {
     $this->session->set_userdata('user', $this->input->post('username'));
     redirect($this->session->userdata('login_url'));
   } else {
     // login fail
     $this->session->set_flashdata('auth_errors', 'Login failed.');
     redirect($_SERVER['HTTP_REFERER']);
   }
  }
  public function logout(){
    $this->session->set_userdata('login_url', null);
    $this->session->set_userdata('user', null);
  }
}

Látható, hogy három fontos metódust tartamaz. Az is_logged($referer) gondoskodik arról, hogy megvizsgáljuk, van-e belépett felhasználó (user) a session-ben. A login_form() hibaüzenetek kezelését, illetve a login form kirajzolását végzi, míg a login() a tulajdonképpeni beléptetést a modellhívással. A logout() csak játék, technikailag vettem fel. Egyszerűen töröl minden session-ban tárolt változót.

Ezt a controller-t az alkalmazásunk fő vezérlőjében (controllers/Apartments.php) az alábbi módon használjuk.

<?php
include APPPATH.'controllers/AuthController.php';
class Apartments extends AuthController {

        public function admin() {

                // check if user is authenticated
                // config/config.php => $config['base_url'] = 'http://localhost/apartman/';
                $this->is_logged(base_url('index.php/apartments/admin'));
                
                $this->load->model('reservations_model');

                $data['query'] = $this->reservations_model->get_reservations();

                $this->template->set('title', 'Admin');
                $this->template->load('menu_layout', 'contents' , 'admin', $data);
        }

        public function admin_approve_ajax($id) {

                // check if user is authenticated
                $this->is_logged(base_url('index.php/apartments/admin'));

                $this->load->model('reservations_model');

                $this->reservations_model->approve_reservation($id);
                $data = $this->reservations_model->get_reservation($id)[0];

                header('Content-Type: application/json');
                echo json_encode($data);
        }

}

Látható, hogy az AuthController-t include-oljuk a kód elején, majd extends-szel alaposztályként hivatkozunk rá. Innentől egy is_logged($referer) hívással mindkét adminisztrátori metódus legelején eldöntjük, hogy “be van-e lépve” az adminisztrátor. Ha nem, akkor átirányítjuk a login form-ra, ha igen, megy tovább a buli. 🙂

És akkor nézzük a login form-unkat! A http://localhost/apartman/index.php/AuthController/login_form webcím alatt látható, ha az admin oldalt szeretnénk megnyitni, és a session változó már elévült a webszerverünkön vagy netán kipróbáltuk a logout() funkciót. 🙂

Admin funkció, foglalás jóváhagyása, AJAX JSON :)

Most már, hogy egy űrlapon keresztül foglalásokat lehet elküldeni, szükségünk lesz egy admin oldalra, ahol az apartman ügyintézője meg tudja tekinteni, illetve jóvá tudja hagyni a foglalásokat.

Hogy mit jelent itt az hogy AJAX JSON? Elég érdekes öszvér elnevezés. 🙂 AJAX-szal normál esetben egy XML adatstruktúrát vinnénk át az aszinkron javascript üzenetben, ami valahogy így nézne ki egy konkrét foglalás (reservation) adataira.

<xml>
<reservation>
<apartment_id>1</apartment_id>
<approved>1</approved>
..
</reservation>
</xml>

Mégis azonban az ún. JSON formátumot használjuk, ami egy konkrét esetben az alábbi szerverválaszt adja.

{
apartment_id: "1",
approved: "1",
checkin: "2020-07-29",
checkout: "2020-08-01",
created_at: "2020-08-03 03:34:11",
email: "aaa@aaa.hu",
id: "10",
locale: null,
message: "aaa",
name: "aaa",
phone: "",
updated_at: "2020-08-05 01:08:08"
}

Látható, hogy egy eléggé egyszerű adatszerkezet. A JSON leírása részletesen az alábbi címen érhető el: https://hu.wikipedia.org/wiki/JSON.

És akkor nézzük meg a konkrét implementációt. Először is bővítenünk kell a models/Reservations_model.php modellünket három metódussal.


        public function get_reservations() {
                $this->db->select()->from('reservations')->order_by('created_at', 'DESC');
                $query = $this->db->get();
                return $query->result();
        }

        public function get_reservation($id) {
                $query = $this->db->get_where('reservations', array('id' => $id));
                return $query->result();
        }

        public function approve_reservation($id) {
                $date = date('Y-m-d H:i:s');
                $this->db->set('updated_at', $date);
                $this->db->set('approved', 1);
                $this->db->where('id', $id);
                $this->db->update('reservations');
        }

Az első get_reservations() metódus a foglalások keletkezésének idejével csökkenő sorrendben egy listát ad vissza a foglalások adataival.

A második get_reservation($id) metódus egy konkrét foglalás adatait adja vissza.

A harmadik approve_reservation($id) metódus pedig UPDATE-eli, tehát frissíti a megadott ID-jű foglalás rekordunkat a frissítés dátumával és beállítja az jóváhagyott foglalás értékét 1-esre, ami esetünkben a jóváhagyás tényét jelzi adatbázis szinten.

Nézzük a views/admin.php view-nkat, hogy mi is kerül bele.

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="booking_ajax"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_booking'); ?></h2>
<table border="1">
<tr>
<th>Name</th><th>Email</th><th>Message</th><th>Checkin</th><th>Checkout</th><th>Created at</th><th>Updated at</th><th>Locale</th><th>Approved</th><th></th>
</tr>
<?php foreach ($query as $item):?>
<tr>
<form>
<td><?php echo $item->name;?></td>
<td><?php echo $item->email;?></td>
<td><?php echo $item->message;?></td>
<td><?php echo $item->checkin;?></td>
<td><?php echo $item->checkout;?></td>
<td><?php echo $item->created_at;?></td>
<td id="updated<?php echo $item->id;?>"><?php echo $item->updated_at;?></td>
<td><?php echo $item->locale;?></td>
<td id="approved<?php echo $item->id;?>"><?php echo $item->approved==1?'true':'false';?></td>
<td><input id="approve_button<?php echo $item->id;?>" type="button" value="Approve" class="btn btn-primary btn-modify" <?php echo $item->approved==1?'disabled':'';?>></td>
</form>
<script>
    $(document).ready(function(){
        $( "#approve_button<?php echo $item->id;?>" ).click(function(event)
        {
            $.ajax(
                {
                    type:"post",
                    url: "<?php echo $my_base_url; ?>index.php/apartments/admin_approve_ajax/<?php echo $item->id;?>",
                    data:{ },
                    contentType: "application/json",
                    dataType:"json", 
                    success:function(response)
                    {
                        console.log(response);
                        var obj = $.parseJSON(JSON.stringify(response));
                        $("#updated<?php echo $item->id;?>").html(obj.updated_at);
                        $('#approved<?php echo $item->id;?>').html(obj.approved==1?'true':'false');
                        $('#approve_button<?php echo $item->id;?>').prop('disabled', obj.approved==1?true:false);
                    },
                    error: function(response)
                    {
                        console.log(response);
                        alert("Invalide id=<?php echo $item->id;?>!");
                    }
                }
            );
        });
    });
</script>
</tr>
<?php endforeach;?>
</table>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Látható, hogy ebbe egy táblázat került a foglalások adataival, melynek minden sora egy-egy foglalást tartalmaz. Erről az iterációról a <?php foreach ($query as $item):?><?php endforeach;?> blokk gondoskodik. Minden sort a foglalás ID-je azonosít. Minden sorhoz kerül egy-egy JavaScript blokk is a megfelelő Approve (Jóváhagy) gomb megfelelő “clickeseményének lekezelésével.

Felhívnám a figyelmet a JSON üzenet dekódolására. Ez a var obj = $.parseJSON(JSON.stringify(response)); sorban történik. Először szükséges sztringgé alakítani a válaszüzenetet, mivel az objektum-ként érkezik. Ez a JSON.stringify metódussal történik. Utána csak egy sima parse-olásra lesz szükségünk. 🙂

Nézzük meg végül a controllers/Apartments.php controller-ünket. Két új metódussal bővül. Az admin() metódusban csak kirajzoljuk az oldalunkat a modell réteg lista SQL SELECT metódusának meghívásával. Az admin_approve_ajax($id) metódusban pedig SQL UPDATE hívás majd egy SQL SELECT hívás történik a modell rétegben, illetve a válasz üzenet JSON becsomagolása.

        public function admin() {
                
                $this->load->model('reservations_model');

                $data['query'] = $this->reservations_model->get_reservations();

                $this->template->set('title', 'Admin');
                $this->template->load('menu_layout', 'contents' , 'admin', $data);
        }

        public function admin_approve_ajax($id) {

                $this->load->model('reservations_model');

                $this->reservations_model->approve_reservation($id);
                $data = $this->reservations_model->get_reservation($id)[0];

                header('Content-Type: application/json');
                echo json_encode($data);
        }

Látható, hogy viszonylag egyszerűen megoldottuk az egész adminisztrátori funkcionalitást az AJAX form vezérlés / adatátvitel és a JSON adatformátum hsználatával. 🙂

És akkor lássuk az admin oldalt (http://localhost/apartman/index.php/apartments/admin), egy jóváhagyott foglalással!

Látható, hogy a legfelső, az Approved true, tehát jóváhagyott rendelés – mivel csak angol nyelven implementáltam mindent az egyszerűség kedvéért – melletti Approve gomb már kiszürkült, nem megnyomható újra. Az Updated at – frissítés dátuma – pedig a késői vagy kora hajnali órát jelzi, amikor elkészültem a pilot kódokkal. 🙂

jQuery UI datepicker – a checkin és checkout mezők ellátása dátumválasztóval

Szeretnénk elérni, hogy a dátum mezőket ki lehessen választani a népszerű módon úgy, hogy “feljön” egy kis naptár egy ún. popup ablakban, ahol rákattintunk a kívánt napra, és a kivlasztott dátum bemásolódik a beviteli mezőnkbe a megadott formátumban.

Ehhez le kell tölenünk a jQuery UI-t a https://jqueryui.com/download/all/ webcímről, majd az assets könyvtárunk megfelelő js, css és css/image könyvtáraiba kell bemásolnunk a megfelelő file-okat.

A jQuery UI ún. datepicker – dátumválasztó widget-ét fogjuk használni. Leírása itt https://jqueryui.com/datepicker/.

A views/layouts/menu_layout.php sablonunkba a fejlécben (<head>) fell kell vegyük a jquery-ui.css illetve jquery-ui.js file-okat.

        <!-- jquery ui -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/jquery-ui.css">

        <!-- jquery ui -->
        <script src="<?php echo $my_base_url?>assets/js/jquery-ui.js"></script>

Ezek után a views/booking_ajax.php view-nkban a <script> részhez az alábbi két új függvényt fűzzük hozzá a $(document).ready(function() rész alá új elemként.

        $( "#checkin" ).datepicker({ dateFormat: "yy-mm-dd" });
        $( "#checkout" ).datepicker({ dateFormat: "yy-mm-dd" });

Itt egy sima inicializálásról van szó ID Selector alapján, a megfelelő ISO 8601 formátumban. Már működik is! 🙂

Lehetne hozzá sőt kell is még írni egy belső validációt, ami mégegyszer ellenőrzi a dátumformátumot adatbázisba írás előtt, de most ettől eltekintunk.

Ugyanígy kimaradtak az form serialize aspektusai is az előző fejezet AJAX űrlapküldésénél, továbbá még két apróság. Ugyanis a kettővel ezelőtti fejezetben nem másoljuk be a mező értékeket abban az esetben a form-unkba, ha valami validációs hiba történik, illetve az előző fejezetben nem töröljük a form mezőket (reset), ha sikeres a foglalás.

Apróságnak tűnnek, de ezek különböztetnek meg egy professzionális weblapot egy kezdetlegesebbtől. 🙂

jQuery AJAX – form elküldése a “háttérben” – foglalás oldal újratöltve

Az AJAX, azaz Asynchronous JavaScript and XML arra szolgál, hogy ne kelljen az egész weblapot újratölteni a form elküldésekor, hanem csak az adatokat, mintegy csendben a “háttérben” elküldeni, majd valami <div> tag-ben megjeleníteni a kívánt felhasználói üzeneteket. Részletesebb leírás az alábbi címen található https://hu.wikipedia.org/wiki/Ajax_(programoz%C3%A1s).

Nem nagyobb feladatra vállalkozunk, minthogy az előbbi foglalás-űrlap elküldésünket aszinkron JavaScript hívásra cseréljük.

Először pár apróság. A views/layouts/menu_layout.php file-ban előre kell vennünk a fejlécbe a JavaScript forrás beillesztéseket, hogy tudjuk használni a jQuery funkcionalitásait.

Aztán át kell “drótoznunk” a menüt pl. a views/photos.php file-ban.

<li><a href="booking_ajax"><?php echo $this->lang->line('menu_booking'); ?></a></li>

Nézzük a views/booking_ajax.php oldalunk tartalmát.

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li class="active"><a href="booking_ajax"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_booking'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-4 animate-box">
                                        <h3>Contact Information</h3>
                                        <ul class="contact-info">
                                                <li><i class="icon-location4"></i>1117 Budapest, Irinyi J. utca 42.</li>
                                                <li><i class="icon-phone3"></i>+ 1235 2355 98</li>
                                                <li><i class="icon-location3"></i><a href="#">info@yoursite.com</a></li>
                                                <li><i class="icon-globe2"></i><a href="#">www.yoursite.com</a></li>
                                        </ul>
                                </div>
                                <div class="col-md-8 animate-box">
                                        <div class="form-wrap">
                                                <div class="row">
                                                        <form id="ajax_form" action="book_ajax" method="POST">
                                                        <div class="col-md-12" id="response_message" style="display: none;">
                                                                <div class="form-group" id="response_message_text">
                                                                        <!--<h3><font color="red">MESSAGE</font></h3>-->
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="name" type="text" name="name" class="form-control" placeholder="Name">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="email" type="text" name="email" class="form-control" placeholder="Email">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="phone" type="text" name="phone" class="form-control" placeholder="Phone">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <textarea id="message" name="message" class="form-control" id="" cols="30" rows="15" placeholder="Message"></textarea>
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="checkin" type="text" name="checkin" class="form-control" placeholder="Check-in">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="checkout" type="text" name="checkout" class="form-control" placeholder="Check-out">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input id="submit_button" type="button" value="Book" class="btn btn-primary btn-modify">
                                                                </div>
                                                        </div>
                                                        </form>
                                                </div>
                                        </div>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->
<script>
    $(document).ready(function(){
        $( "#submit_button" ).click(function(event)
        {
            event.preventDefault();
            var name = $("#name").val();
            var email = $("#email").val();
            var phone = $("#phone").val();
            var message = $("#message").val();
            var checkin = $("#checkin").val();
            var checkout = $("#checkout").val();
            var data = $("#ajax_form").serialize();

            $.ajax(
                {
                    type:"post",
                    url: "<?php echo $my_base_url; ?>index.php/apartments/book_ajax",
                    data:{ name: name, email: email, phone: phone, message: message, checkin: checkin, checkout: checkout },
                    success:function(response)
                    {
                        console.log(response);
                        $("#response_message_text").html("<h3><font color=\"red\">" + response + "</font></h3>");
                        $('#response_message').show();
                    },
                    error: function()
                    {
                        alert("Invalide!");
                    }
                }
            );
        });
    });
</script>

Nézzük mi változott! Minden form mezőnek, az elküldő gombnak és a felhasználói üzenet résznek (#response_message_text és #response_message) egyedi azonosítót, id-attribútumot adtunk, hogy a JavaScript részben #id néven hivatkozhassunk rájuk. Ezt a hivatkozási módszert amúgy css szelektornak hívjuk, ezen belül is ún. ID Selector, részletek itt https://www.w3.org/wiki/CSS3/Selectors.

Látható a <script> tag-ben az ajax hívásunk. Kiolvassuk az űrlapmezők értékeit, majd egy hívást indítunk, mind success (siker), mind error (hiba) esetére megfelelő válaszokkal.

Modellünk nem változik viszont a controller-ünkbe elkél két új metódus. Nézzük a controllers/Apartments.php file-t.

        public function booking_ajax() {
                $data = array();

                $this->template->set('title', $this->lang->line('menu_booking'));
                $this->template->load('menu_layout', 'contents', 'booking_ajax', $data);

        }

        public function book_ajax() {
                $this->load->library('form_validation');
                $this->form_validation->set_rules('name', 'Name', 'required');
                $this->form_validation->set_rules('email','Email','trim|required|valid_email');
                $this->form_validation->set_rules('checkin', 'Check-in', 'required');
                $this->form_validation->set_rules('checkout', 'Check-out', 'required');

                if($this->form_validation->run() == FALSE) {
                        echo validation_errors();
                } else {
                        $this->load->model('reservations_model');
                        $this->reservations_model->insert_reservation();
                        echo "Thanks for booking!";
                }
        }

A booking_ajax metódus csak betölti a view-nkat.

A book_ajax metódus már összetettebb. Tartalmaz egy ellenőrzést, ami email címnél valid_email-lel is bővül, tehát megvizsgálja a formátumot is és egy trim-mel, ami az esetleges felesleges ún. “trailing space” karaktereket vágja le (üres karakterek az elején és a végén).

Látható, hogy validációs hibák esetén visszatér hibával, ez ki is lesz írva a view-nkban a megfelelő div-nél, illetve ha sikerült, akkor a “Köszönet a foglalásért!” üzenettel válaszol. Ennyi az egész :).

És akkor vessünk egy pillantást egy sikeres foglalásra!

Nézzük a http://localhost/apartman/index.php/apartments/booking_ajax oldalunkat.

Láthatjuk, hogy az űrlap (form) helyes kitöltése és elküldése után az adatbázis konzolban látható az adatbázisba felvett sor.

mysql> select * from reservations where id = 10;
+----+------+------------+-------+------------+------------+---------+----------+--------------+--------+---------------------+---------------------+
| id | name | email      | phone | checkin    | checkout   | message | approved | apartment_id | locale | created_at          | updated_at          |
+----+------+------------+-------+------------+------------+---------+----------+--------------+--------+---------------------+---------------------+
| 10 | aaa  | aaa@aaa.hu |       | 2020-07-29 | 2020-08-01 | aaa     |     NULL |            1 | NULL   | 2020-08-03 03:34:11 | 2020-08-03 03:34:11 |
+----+------+------------+-------+------------+------------+---------+----------+--------------+--------+---------------------+---------------------+
1 row in set (0.00 sec)

Egy egyszerű form elküldése, a HTTP POST metódus, DB INSERT, foglalás oldal

Bár a dolgok “belseje”, mégis nézzük csak meg, hogy a model rétegnek mit kell tudnia. A models/Reservations_model.php file tartalmazza az adatbázis beszúrást, azt a bizonyos DB INSERT-et a címből.

<?php
class Reservations_model extends CI_Model {

        public function insert_reservation() {    
                $date = date('Y-m-d H:i:s');
                $data = array(
                        'name' => $this->input->post('name'),
                        'email' => $this->input->post('email'),
                        'phone' => $this->input->post('phone'),
                        'message' => $this->input->post('message'),
                        'checkin' => $this->input->post('checkin'),
                        'checkout' => $this->input->post('checkout'),
                        'apartment_id' => 1,
                        'created_at' => $date,
                        'updated_at' => $date,
                        'locale' => $this->session->userdata('site_lang')
                );

                return $this->db->insert('reservations', $data);
        }

}

Az insert során vesszük a HTTP POST asszociatív tömbből a megfelelő értékeket, néhányat pedig “generálunk”, illetve “kiszámítunk”. Ilyen az apartment_id, a created_at, az updated_at és a locale (nyelv).

Ezt a model metódust a controller-ből fogjuk hívni. Picit megbonyolítottam ezt a controller-t, ahogy az látszani fog. Tettem bele egy viszonyag egyszerű validációt. A validáció vagyis ellenőrzés arra szolgál, hogy a formban – ahogy az példánkban látható – ne lehessen a név, email, foglalás tól-ig adatok megadása nélkül elküldeni a foglalást. 🙂

Nézzük a controllers/Apartments.php vezérlőnket! Kiegészítjük a booking() és a book() metódusokkal.

        public function booking()
        {
                $data = array();
                $data['validation_errors'] = '';
                if (!empty($this->session->flashdata('validation_errors'))) {
                        $data['validation_errors'] = $this->session->flashdata('validation_errors');
                }

                $this->template->set('title', $this->lang->line('menu_booking'));
                $this->template->load('menu_layout', 'contents', 'booking', $data);
        }

        public function book()
        {
                $this->load->library('form_validation');
                $this->form_validation->set_rules('name', 'Name', 'required');
                $this->form_validation->set_rules('email', 'Email', 'required');
                $this->form_validation->set_rules('checkin', 'Check-in', 'required');
                $this->form_validation->set_rules('checkout', 'Check-out', 'required');

                if ($this->form_validation->run() === FALSE) {
                        $this->session->set_flashdata('validation_errors', validation_errors());
                        redirect($_SERVER['HTTP_REFERER']);
                } else {
                        $this->load->model('reservations_model');
                        $this->reservations_model->insert_reservation();

                        $data = array();

                        $this->template->set('title', $this->lang->line('menu_booking'));
                        $this->template->load('menu_layout', 'contents', 'booking_accepted', $data);
                }
        }

Látható, hogy a book() metódusban hívjuk a modellünket, majd a booking_accepted oldalra irányítjuk a klienst. 🙂

Végül nézzük a két view-nkat. Előbb vegyük a formunkat tartalmazó views/booking.php állományt.

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li class="active"><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_booking'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-4 animate-box">
                                        <h3>Contact Information</h3>
                                        <ul class="contact-info">
                                                <li><i class="icon-location4"></i>1117 Budapest, Irinyi J. utca 42.</li>
                                                <li><i class="icon-phone3"></i>+ 1235 2355 98</li>
                                                <li><i class="icon-location3"></i><a href="#">info@yoursite.com</a></li>
                                                <li><i class="icon-globe2"></i><a href="#">www.yoursite.com</a></li>
                                        </ul>
                                </div>
                                <div class="col-md-8 animate-box">
                                        <div class="form-wrap">
                                                <div class="row">
                                                        <form action="book" method="POST">
                                                        <?php if ($validation_errors) { ?>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <h3><font color="red"><?php echo $validation_errors; ?></font></h3>
                                                                </div>
                                                        </div>
                                                        <?php } ?>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="name" class="form-control" placeholder="Name">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="email" class="form-control" placeholder="Email">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="phone" class="form-control" placeholder="Phone">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <textarea name="message" class="form-control" id="" cols="30" rows="15" placeholder="Message"></textarea>
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="checkin" class="form-control" placeholder="Check-in">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="text" name="checkout" class="form-control" placeholder="Check-out">
                                                                </div>
                                                        </div>
                                                        <div class="col-md-12">
                                                                <div class="form-group">
                                                                        <input type="submit" value="Book" class="btn btn-primary btn-modify">
                                                                </div>
                                                        </div>
                                                        </form>
                                                </div>
                                        </div>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Ebben a fontos talán a $validation_errors változó kiíratása, illetve maga a form. Azt, hogy mi az action-je, és mi a metódus, az alábbi sor írja le.

<form action="book" method="POST">

Érdemes még megnézni a form egy mezőjének definiálását is.

<input type="text" name="name" class="form-control" placeholder="Name">

Ez annyit jelent, hogy szöveg beviteli mező, name névvel, ahol a vakszöveg a “Name” felirat lesz.

Fontos továbbá az elküldő gomb megadása is, més a form tag-en belül. A tag amúgy, HTML tag, azaz egy két kacsacsőr közé rejtett literál (sztring), amiben nincs további kacsacsőr karakter. Példa nyitó és záró tag-ekre: <form></form>. 🙂

<input type="submit" value="Book" class="btn btn-primary btn-modify">

Ez egy submit button – elküldő gomb, “Book” felirattal.

Ezt a formot a submit gomb megnyomása után a book() metódus fogja “megkapni” a controller-ben egy HTTP POST metódushívás után. A form mezőit egy a name attribútumokban megadott nevekkel kulcsolt asszociatív tömb fogja tartalmazni. Ennyi az egész! 🙂

Látható az adatbázisunkban, hogy a megfelelő rekord bekerült a reservations táblába (SQL konzol hozzáférés mysql -u apartman -p apartman_devel parancs kiadásával).

mysql> select * from reservations;
+----+-----------------+------------+------------+------------+------------+-----------------------+----------+--------------+---------+---------------------+---------------------+
| id | name            | email      | phone      | checkin    | checkout   | message               | approved | apartment_id | locale  | created_at          | updated_at          |
+----+-----------------+------------+------------+------------+------------+-----------------------+----------+--------------+---------+---------------------+---------------------+
|  5 | Gergely Vámosi  | mail@to.me | 0123456789 | 2020-07-29 | 2020-08-01 | Szeretnék egy szobát! |     NULL |            1 | english | 2020-07-29 01:33:20 | 2020-07-29 01:33:20 |
+----+-----------------+------------+------------+------------+------------+-----------------------+----------+--------------+---------+---------------------+---------------------+
1 row in set (0.00 sec)

Nézzük meg még a views/booking_accepted.php oldalt. Ez arról ad tájékoztatást az apartmant lefoglalni szándékozó ügyfélnek, hogy sikeres a foglalása!

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li class="active"><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_booking'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-contact">
                        <div class="row">
                                <div class="col-md-4 animate-box">
                                        <h3>Thanks for booking!</h3>
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

Vegyük kicsit górcső alá a biztonságot! Hisz adatot közlünk a szerverrel, bármit beírhatunk a weblapon az űrlapba, amit pár szűrőn áteresztve adatbázisban tárolunk!

Először is érdemes megvizsgálni azt, hogy mit írhatunk be a mezőkbe: speciális karakterek, többek között a HTML formátum speciális jelei, a <>” és ‘ jelek. Aztán az ún. SQL injection veszélyei, amikor is az adatbáziselérésen keresztül speciális, például rosszakaratú SQL parancsokat tudunk kiadni, ami akár lehet egy ;DELETE FROM <TÁBLANÉV> pontosvessző után beszúrt parancs is akár. Szerencsés esetben ezeknek az eseteknek a kiszűrését a keretrendszerünk biztosítja. 🙂

Érdemes továbbá megvizsgálni az esetleges ún. CSRF – Cross-site request forgery veszélyét is. Bővebben a https://hu.wikipedia.org/wiki/Cross-site_request_forgery cím alatt olvashatunk róla. Röviden arról van szó, hogy a böngészőn keresztül nem kívánt parancsok hajthatók végre egy weblapon a felhasználó tudta nélkül. Ebbe a témakörbe tartozik egyébként még az XSS – Cross-site scripting is. A CSRF ellen egyébként többnyire egy minden formhoz (űrlapohoz) egyedileg generált azonosító, egy speciális kód véd, ami üzenetváltásonként újragenerált (töken). Ez véd többek között egy form újraküldése ellen, azaz adott esetben egy művelet (pl. fizetés) adott esetben rossz szándékú újbóli végrehajtása ellen. Az XSS csupán egy weblap funkcióinak más weblapbóli történő meghívása. 🙂 Játék. A baj, ha nem barátágos.

Aztán ott van az úgynevezett Captcha-teszt szükségessége is. Bővebben a https://hu.wikipedia.org/wiki/Captcha címen olvashatunk róla. Itt arról van szó, hogy weblapunk az emberi felhasználót megkülönböztesse egy generált robot, azaz gépi hozzáféréstől. Csak valós emberektől szeretnénk apartman foglalást elfogadni! Semmi esetre sem rossz szándékú hekkerek által készített programoktól. Ismerősök ugye az elhanyagolt facebook profilok mindenféle “fake” felhasználó általi “hello, ismerjük egymást” üzenetei? Főleg attraktív “csajoktól”? 🙂

És akkor lássuk a http://localhost/apartman/index.php/apartments/booking oldalt!

Egyszerű oldal létrehozása – képek oldal

Egy egyszerű oldalt az apartmanunkat bemutató képekkel három egyszerű lépésben hozhatunk létre. A demo képeket letöltöttük ingyenesen a https://www.pexels.com/ oldalról és előzőleg már előkészítettük.

Először is a controller-ünket kell megbűvölni. A controllers/Apartments.php file-hoz az alábbi sorokat fűzzük hozzá.

        public function photos()
        {
                $data = array();

                $this->template->set('title', $this->lang->line('menu_photos'));
                $this->template->load('menu_layout', 'contents', 'photos', $data);
        }

Másodjára létrehozzuk a views/layouts/menu_layout.php sablon-t, ami alapvetően annyival tud többet a default_layout.php file-unknál, hogy a menüt is meg lehet benne változtatni. Erre csupán azért van szükségünk, hogy az aktuális menüpont piros lehessen. 🙂

<?php
        $my_base_url = '/apartman/';
?>
<!DOCTYPE HTML>
<html>
        <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Apartman - <?php echo $title;?></title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="Apartman booking website" />
        <meta name="keywords" content="apartman, booking, website" />
        <meta name="author" content="Gergely Vámosi" />

        <!-- 
        //////////////////////////////////////////////////////

        FREE HTML5 TEMPLATE 
        DESIGNED & DEVELOPED by FreeHTML5.co
                
        Website:                http://freehtml5.co/
        Email:                  info@freehtml5.co
        Twitter:                http://twitter.com/fh5co
        Facebook:               https://www.facebook.com/fh5co

        //////////////////////////////////////////////////////
         -->

        <!-- Facebook and Twitter integration -->
        <meta property="og:title" content=""/>
        <meta property="og:image" content=""/>
        <meta property="og:url" content=""/>
        <meta property="og:site_name" content=""/>
        <meta property="og:description" content=""/>
        <meta name="twitter:title" content="" />
        <meta name="twitter:image" content="" />
        <meta name="twitter:url" content="" />
        <meta name="twitter:card" content="" />

        <link href="https://fonts.googleapis.com/css?family=Open+Sans|Playfair+Display" rel="stylesheet">
        
        <!-- Animate.css -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/animate.css">
        <!-- Icomoon Icon Fonts-->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/icomoon.css">
        <!-- Bootstrap  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/bootstrap.css">

        <!-- Flexslider  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/flexslider.css">

        <!-- Theme style  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/style.css">

        <!-- Modernizr JS -->
<script src="<?php echo $my_base_url?>assets/js/modernizr-2.6.2.min.js"></script>
        <!-- FOR IE9 below -->
        <!--[if lt IE 9]>
<script src="<?php echo $my_base_url?>assets/js/respond.min.js"></script>
        <![endif]-->

        </head>
        <body>
                
        <div class="fh5co-loader"></div>
        
        <div id="page">
        <nav class="fh5co-nav" role="navigation">
                <div class="container">
                        <div class="top-menu">
                                <div class="row">
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/magyar">Magyar</a></li>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/english">English</a></li>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/deutsch">Deutsch</a></li>
                                                </ul>
                                        </div>
                                </div>
                                <div class="row">
                                        &nbsp;
                                </div>

                <!-- PAGE CONTENT BEGINS -->
                        <?php echo $contents;?>
                <!-- PAGE CONTENT ENDS -->

        <div class="container">
                <footer id="fh5co-footer" role="contentinfo">
                        <div class="row">
                                <div class="col-md-3 fh5co-widget">
                                        <h4>Az oldalról</h4>
                                        <p>Jogi információ.</p>
                                </div>
                                <div class="col-md-3 col-md-push-1">
                                        <h4>Lorem Ipsum</h4>
                                        <ul class="fh5co-footer-links">
                                                <li><a href="#">12345</a></li>
                                                <li><a href="#">67890</a></li>
                                        </ul>
                                </div>

                                <div class="col-md-3 col-md-push-1">
                                        <h4>Linkek</h4>
                                        <ul class="fh5co-footer-links">
                                                <li><a href="#">Home</a></li>
                                                <li><a href="#">Képek</a></li>
                                                <li><a href="#">Foglalás</a></li>
                                                <li><a href="#">Kapcsolat</a></li>
                                        </ul>
                                </div>

                                <div class="col-md-3">
                                        <h4>Kapcsolat</h4>
                                        <ul class="fh5co-footer-links">
                                                <li>Kossuth utca 10,<br>1111 Budapest</li>
                                                <li><a href="tel://1234567920">+ 1235 2355 98</a></li>
                                                <li><a href="mailto:info@yoursite.com">info@yoursite.com</a></li>
                                                <li><a href="http://localhost/apartman">apartman</a></li>
                                        </ul>
                                </div>

                        </div>

                        <div class="row copyright">
                                <div class="col-md-12 text-center">
                                        <p>
                                                <small class="block">&copy; 2016 Free HTML5. All Rights Reserved.</small>
                                                <small class="block">Designed by <a href="http://freehtml5.co/" target="_blank">FreeHTML5.co</a> Demo Images: <a href="http://unsplash.co/" target="_blank">Unsplash</a></small>
                                        </p>
                                        <p>
                                                <ul class="fh5co-social-icons">
                                                        <li><a href="#"><i class="icon-twitter"></i></a></li>
                                                        <li><a href="#"><i class="icon-facebook"></i></a></li>
                                                        <li><a href="#"><i class="icon-linkedin"></i></a></li>
                                                        <li><a href="#"><i class="icon-dribbble"></i></a></li>
                                                </ul>
                                        </p>
                                </div>
                        </div>
                </footer>
        </div><!-- END container -->
        </div>

        <div class="gototop js-top">
                <a href="#" class="js-gotop"><i class="icon-arrow-up2"></i></a>
        </div>
        
        <!-- jQuery -->
<script src="<?php echo $my_base_url?>assets/js/jquery.min.js"></script>
        <!-- jQuery Easing -->
<script src="<?php echo $my_base_url?>assets/js/jquery.easing.1.3.js"></script>
        <!-- Bootstrap -->
<script src="<?php echo $my_base_url?>assets/js/bootstrap.min.js"></script>
        <!-- Waypoints -->
<script src="<?php echo $my_base_url?>assets/js/jquery.waypoints.min.js"></script>
        <!-- Flexslider -->
<script src="<?php echo $my_base_url?>assets/js/jquery.flexslider-min.js"></script>
        <!-- Sticky Kit -->
<script src="<?php echo $my_base_url?>assets/js/sticky-kit.min.js"></script>
        <!-- Main -->
<script src="<?php echo $my_base_url?>assets/js/main.js"></script>

        </body>
</html>

Harmadjára pedig hozzuk létre a sablonban a $contents helyére kerülő views/photos.php file-t.

<?php
        $my_base_url = '/apartman/';
?>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li class="active"><a href="photos"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="booking"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2><?php echo $this->lang->line('menu_photos'); ?></h2>
                                </div>
                        </div>
                </div>
                <div id="fh5co-portfolio">
                        <div class="row">

                                <div class="col-md-4 col-md-push-8 sticky-parent">
                                        <div class="detail" id="sticky_item">
                                                <div class="animate-box">
                                                        <h2>Lorem ipsum</h2>
                                                        <span>Lorem ipsum dolor sit amet</span>
                                                        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
                                                        <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
                                                        <p><a class="btn btn-primary btn-demo" href="#"></i> Lorem ipsum</a></p>
                                                </div>
                                        </div>
                                </div>

                                <div class="col-md-7 col-md-pull-4 image-content">
                                        <div class="image-item  animate-box">
                                                <img src="<?php echo $my_base_url?>assets/images/kitchen_480_.jpg" class="img-responsive" alt="Photo by Dmitry Zvolskiy from Pexels">
                                        </div>
                                        <div class="image-item  animate-box">
                                                <img src="<?php echo $my_base_url?>assets/images/interior_480.jpg" class="img-responsive" alt="Photo by Daria Shevtsova from Pexels">
                                        </div>
                                        <div class="image-item  animate-box">
                                                <img src="<?php echo $my_base_url?>assets/images/livingroom_480.jpg" class="img-responsive" alt="Photo by Daria Shevtsova from Pexels">
                                        </div>
                                        <div class="image-item  animate-box">
                                                <img src="<?php echo $my_base_url?>assets/images/bedroom_480.jpg" class="img-responsive" alt="https://www.pexels.com/">
                                        </div>
                                        <div class="image-item  animate-box">
                                                <img src="<?php echo $my_base_url?>assets/images/bathroom_480.jpg" class="img-responsive" alt="Photo by Jean van der Meulen from Pexels">
                                        </div>
                                </div>

                        </div>
                </div>
        </div><!-- END container-wrap -->

Ennyi az egész! Máris láthatjuk a http://localhost/apartman/index.php/apartments/photos cím alatt a szépséges “Képek” oldalunkat!

Többnyelvűség implementálása: Magyar, English, Deutsch

Szeretnénk, ha az oldalunk több nyelven is tudna, mivel lehetnek az apartmannak külföldi vendégei is.

A CodeIgniter ezt alapból jól megtámogatja úgynevezett nyelvi file-okkal, illetve a hook funkcióval, nézzünk a megvalósításra egy egyszerű utat. Az alábbi webhelyen elég jó útmutatást kapunk, csupán egy picit változtatunk az implementáción.

http://programmerblog.net/multilingual-website-in-codeigniter/

Először hozzunk létre nyelvi könyvtárakat. Nálunk az alapértelmezett nyelv a magyar lesz (angol, “english” ugye már alapból van).

gvamosi@gergo1:/var/www/html/apartman/application$ mkdir language/magyar
gvamosi@gergo1:/var/www/html/apartman/application$ mkdir language/deutsch

Az language/magyar/base_lang.php file tartalma a követező legyen.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$lang['menu_photos'] = 'Képek';
$lang['menu_booking'] = 'Foglalás';
$lang['menu_contact'] = 'Kapcsolat';
?>

Erre a mintára készüljön az angol nyelvű nyelvi file is: language/english/base_lang.php.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$lang['menu_photos'] = 'Photos';
$lang['menu_booking'] = 'Booking';
$lang['menu_contact'] = 'Contact';
?>

Majd a német is: language/deutsch/base_lang.php. 🙂

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$lang['menu_photos'] = 'Fotos';
$lang['menu_booking'] = 'Reservieren';
$lang['menu_contact'] = 'Kontakt';
?>

A config/config.php-ban engedélyeznünk kell a hook funkciót.

$config['enable_hooks'] = TRUE;

Meg kell írnunk a hook-unkat a config/hooks.php file-ban.

$hook['post_controller_constructor'] = array(
	'class' => 'LanguageLoader',
	'function' => 'initialize',
	'filename' => 'LanguageLoader.php',
	'filepath' => 'hooks'
);

Az application könyvtár alatt létre kell hozzuk a hooks/LanguageLoader.php osztályt.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class LanguageLoader
{
   function initialize() {
       $ci =& get_instance();
       $ci->load->helper('language');
       $siteLang = $ci->session->userdata('site_lang');
       if ($siteLang) {
           $ci->lang->load('base', $siteLang);
       } else {
           $ci->lang->load('base', 'magyar');
       }
   }
}
?>

Ezután létre kell hoznunk egy controller-t történetesen controllers/LanguageSwitcher.php néven.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class LanguageSwitcher extends CI_Controller {
  public function __construct(){
    parent::__construct();
  }
  public function switchLang($language = "") {
    $this->session->set_userdata('site_lang', $language);
    redirect($_SERVER['HTTP_REFERER']);
  }
}

Némi magyarázatot fűznék a fenti két kódblokkhoz. A “session” magyar fordítáa munkamenet szokott lenni. Ha itt beállítunk egy változó értéket, akkor kliens oldalon a browser-ben egy weblaphoz kötött változót, egy ún. cookie-t, magyarul sütit tárol el a szerver alkalmazás ilyenkor. A szerver gép pedig az adott süti által meghatározott böngésző munkamenethez egy session változót regisztrál, esetünkben az oldal nyelvét, vagyis hogy magyar, angol vagy német nyelven kívánjuk olvasni az weblapot. Nagyon szépen meg lehet ezt nézni pl. a Chrome böngészőben a Developer Tools-ban az Application / Storage / Cookies rész alatt. Ott találunk egy localhost-tól bejegyzett sütit, ci_session néven, egy egyedi azonosítóval, egy ID-vel. A webszerverünkön a session, vagyis a HTTP SESSION egy idő után, ha nem történik újabb kommunikáció a weboldalon a szerver és a kliens között, elévül és törlődik. Milyen elmés! 🙂

Magyarázzuk meg még a “HTTP_REFERER” HTTP header, magyarul fejléc változó használatát. A HTTP kérés és válasz tartalmaz egy fejlécet és egy törzset (body), mint minden normális IP üzenet. Ez a fejléc érték azt az url-t tartalmazza, ahonnan az adott url-t “hívtuk”. Ebben a megoldásban, mivel bármely oldalon állíthatjuk a nyelvet, a hívó oldalra visszairányítjuk automatikusan a klienst, miután a /LanguageSwitcher/switchLang/<NYELV> url segítségével a megfelelő controller-ben átállítottuk a nyelvet a session-ben. 🙂

Bővebben az előbbiekről a https://hu.wikipedia.org/wiki/HTTP-s%C3%BCti és a https://hu.wikipedia.org/wiki/Referer címeken olvashatunk.

Ezután nem marad más hátra, mint “bedrótozni” egy menüstruktúrát a sablonfile-unkban, illetve a $this->lang->line('message') hívással előszedni a megfelelő sztringeket a nyelvi file-okból. Nézzük az új navigációt.

        <nav class="fh5co-nav" role="navigation">
                <div class="container">
                        <div class="top-menu">
                                <div class="row">
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/magyar">Magyar</a></li>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/english">English</a></li>
                                                        <li><a style="font-size: 14px; padding: 5px 5px;" href="<?php echo $my_base_url?>index.php/LanguageSwitcher/switchLang/deutsch">Deutsch</a></li>
                                                </ul>
                                        </div>
                                </div>
                                <div class="row">
                                        &nbsp;
                                </div>
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li class="active"><a href="index.html"><?php echo $this->lang->line('menu_photos'); ?></a></li>
                                                        <li><a href="single.html"><?php echo $this->lang->line('menu_booking'); ?></a></li>
                                                        <li><a href="contact.html"><?php echo $this->lang->line('menu_contact'); ?></a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>

Kész a többnyelvű oldalunk! 🙂

Refactoring (a kód újra rendszerezése), templating (sablonok használata) és menü

A legutóbbi fejezetben megírtuk a Hello, Világ! oldalunkat. Most ezt egy kicsit újra rendszerezzük. Bár kétségkívűl jól mutat, most mégis eltávolítjuk a controller-ből a _controller utótagot. 🙂

Ezt néhány file-átnevezéssel, illetve pár sornyi kódmódosítással megtehetjük. A hivatkozások miatt (referenciák) ezt a műveletet nyilván körültekintéssel kell elvégeznünk. Így az oldalunkat az alábbi címen is elérhetjük.

http://localhost/apartman/index.php/apartments/index

Ahol az apartments a controller neve, az index pedig a megfelelő metódus. Ez egy ún. beszédes url, a RESTful architektúrának (https://hu.wikipedia.org/wiki/REST) megfelel.

Miután ezzel megvagyunk, keressünk egy ingyenes sablont az interneten. Az alábbi némi keresés után pont megfelelő. Ez egy ingyenes jQuery és Bootstrap alapokra épülő HTML5-ös sablon. A jQuery java script könyvtárnak a https://jquery.com/ oldalon, a Bootstrap front-end toolkit-nek pedig a https://getbootstrap.com/ oldalon lehet utánanézni. Fontos szempont egy modern weblapnál, hogy jól olvasható legyen okostelefonon is. Ez a gyakorlatban azt jelenti, hogy bizonyos szélesség alatt hamburgermenü jelenik meg az oldalon, illetve a több hasábos megjelenés összecsúszik egyetlen hasábba.

https://freehtml5.co/architect-free-html5-bootstrap-template-for-architects-and-portfolio-websites/

A sablont kibontjuk, majd a benne található css, fonts, images és js könyvtárakat az application gyökér könyvtárral egy szinten újonnan létrehozott assets könyvtárba másoljuk.

A sablon beillesztését az alábbi weboldalon leírt módon végezzük.

https://www.phpflow.com/php/creating-template-codeigniter-3-using-bootstrap-theme/

Az index.php eltűntetésével (mod_rewrite apache modul) nagyvonalúan nem foglalkozunk. Extrémsportolók beállíthatják önszorgalomból. 🙂

A libraries könyvtárban létrehozzuk a Template.php állományt az alábbi tartalommal.

<?php
class Template {
                //ci instance
                private $CI;
                //template Data
                var $template_data = array();
 
                public function __construct() 
                {
                                $this->CI =& get_instance();
                }
 
                function set($content_area, $value)
                {
                                $this->template_data[$content_area] = $value;
                }
 
                function load($template = '', $name ='', $view = '' , $view_data = array(), $return = FALSE)
                {
                                $this->set($name , $this->CI->load->view($view, $view_data, TRUE));
                               
                                $this->CI->load->view('layouts/'.$template, $this->template_data);
                }
                               
}
?>

Látható, hogy ez egy igen egyszerű implementáció, egy set és egy load függvénnyel. Többre azonban nincs szükségünk. 🙂

A views könyvtár alatt (az appplication gyökérben) hozzunk létre egy layouts könyvtárat. Ebbe fog kerülni a sablonunk, a default_layout.php file.

<?php
        $my_base_url = '/apartman/';
?>
<!DOCTYPE HTML>
<html>
        <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Apartman - <?php echo $title;?></title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="Apartman booking website" />
        <meta name="keywords" content="apartman, booking, website" />
        <meta name="author" content="Gergely Vámosi" />

        <!-- 
        //////////////////////////////////////////////////////

        FREE HTML5 TEMPLATE 
        DESIGNED & DEVELOPED by FreeHTML5.co
                
        Website:                http://freehtml5.co/
        Email:                  info@freehtml5.co
        Twitter:                http://twitter.com/fh5co
        Facebook:               https://www.facebook.com/fh5co

        //////////////////////////////////////////////////////
         -->

        <!-- Facebook and Twitter integration -->
        <meta property="og:title" content=""/>
        <meta property="og:image" content=""/>
        <meta property="og:url" content=""/>
        <meta property="og:site_name" content=""/>
        <meta property="og:description" content=""/>
        <meta name="twitter:title" content="" />
        <meta name="twitter:image" content="" />
        <meta name="twitter:url" content="" />
        <meta name="twitter:card" content="" />

        <link href="https://fonts.googleapis.com/css?family=Open+Sans|Playfair+Display" rel="stylesheet">
        
        <!-- Animate.css -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/animate.css">
        <!-- Icomoon Icon Fonts-->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/icomoon.css">
        <!-- Bootstrap  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/bootstrap.css">

        <!-- Flexslider  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/flexslider.css">

        <!-- Theme style  -->
        <link rel="stylesheet" href="<?php echo $my_base_url?>assets/css/style.css">

        <!-- Modernizr JS -->
<script src="<?php echo $my_base_url?>assets/js/modernizr-2.6.2.min.js"></script>
        <!-- FOR IE9 below -->
        <!--[if lt IE 9]>
<script src="<?php echo $my_base_url?>assets/js/respond.min.js"></script>
        <![endif]-->

        </head>
        <body>
                
        <div class="fh5co-loader"></div>
        
        <div id="page">
        <nav class="fh5co-nav" role="navigation">
                <div class="container">
                        <div class="top-menu">
                                <div class="row">
                                        <div class="col-sm-2">
                                                <div id="fh5co-logo"><a href="index.html">Apartman<span>.</span></a></div>
                                        </div>
                                        <div class="col-sm-10 text-right menu-1">
                                                <ul>
                                                        <li class="active"><a href="index.html">Képek</a></li>
                                                        <li><a href="single.html">Foglalás</a></li>
                                                        <li><a href="contact.html">Kapcsolat</a></li>
                                                </ul>
                                        </div>
                                </div>
                                
                        </div>
                </div>
        </nav>
        <div class="container">
                <div id="fh5co-intro">
                        <div class="row animate-box">
                                <div class="col-md-8 col-md-offset-2 col-md-pull-2">
                                        <h2>Apartman kiadó.</span></h2>
                <!-- PAGE CONTENT BEGINS -->
                        <?php echo $contents;?>
                <!-- PAGE CONTENT ENDS -->
                                </div>
                        </div>
                </div>
        </div><!-- END container -->

        <div class="container">
                <footer id="fh5co-footer" role="contentinfo">
                        <div class="row">
                                <div class="col-md-3 fh5co-widget">
                                        <h4>Az oldalról</h4>
                                        <p>Jogi információ.</p>
                                </div>
                                <div class="col-md-3 col-md-push-1">
                                        <h4>Lorem Ipsum</h4>
                                        <ul class="fh5co-footer-links">
                                                <li><a href="#">12345</a></li>
                                                <li><a href="#">67890</a></li>
                                        </ul>
                                </div>

                                <div class="col-md-3 col-md-push-1">
                                        <h4>Linkek</h4>
                                        <ul class="fh5co-footer-links">
                                                <li><a href="#">Home</a></li>
                                                <li><a href="#">Képek</a></li>
                                                <li><a href="#">Foglalás</a></li>
                                                <li><a href="#">Kapcsolat</a></li>
                                        </ul>
                                </div>

                                <div class="col-md-3">
                                        <h4>Kapcsolat</h4>
                                        <ul class="fh5co-footer-links">
                                                <li>Kossuth utca 10,<br>1111 Budapest</li>
                                                <li><a href="tel://1234567920">+ 1235 2355 98</a></li>
                                                <li><a href="mailto:info@yoursite.com">info@yoursite.com</a></li>
                                                <li><a href="http://localhost/apartman">apartman</a></li>
                                        </ul>
                                </div>

                        </div>

                        <div class="row copyright">
                                <div class="col-md-12 text-center">
                                        <p>
                                                <small class="block">&copy; 2016 Free HTML5. All Rights Reserved.</small>
                                                <small class="block">Designed by <a href="http://freehtml5.co/" target="_blank">FreeHTML5.co</a> Demo Images: <a href="http://unsplash.co/" target="_blank">Unsplash</a></small>
                                        </p>
                                        <p>
                                                <ul class="fh5co-social-icons">
                                                        <li><a href="#"><i class="icon-twitter"></i></a></li>
                                                        <li><a href="#"><i class="icon-facebook"></i></a></li>
                                                        <li><a href="#"><i class="icon-linkedin"></i></a></li>
                                                        <li><a href="#"><i class="icon-dribbble"></i></a></li>
                                                </ul>
                                        </p>
                                </div>
                        </div>
                </footer>
        </div><!-- END container -->
        </div>

        <div class="gototop js-top">
                <a href="#" class="js-gotop"><i class="icon-arrow-up2"></i></a>
        </div>
        
        <!-- jQuery -->
<script src="<?php echo $my_base_url?>assets/js/jquery.min.js"></script>
        <!-- jQuery Easing -->
<script src="<?php echo $my_base_url?>assets/js/jquery.easing.1.3.js"></script>
        <!-- Bootstrap -->
<script src="<?php echo $my_base_url?>assets/js/bootstrap.min.js"></script>
        <!-- Waypoints -->
<script src="<?php echo $my_base_url?>assets/js/jquery.waypoints.min.js"></script>
        <!-- Flexslider -->
<script src="<?php echo $my_base_url?>assets/js/jquery.flexslider-min.js"></script>
        <!-- Sticky Kit -->
<script src="<?php echo $my_base_url?>assets/js/sticky-kit.min.js"></script>
        <!-- Main -->
<script src="<?php echo $my_base_url?>assets/js/main.js"></script>

        </body>
</html>

A config/autoload.php file-ban az alábbi módosítástokat eszközöljük.

// templating added by me on 2020/07/23
$autoload['libraries'] = array('database','session','template');
// added by  me on 2020/07/23
$autoload['helper'] = array('url');

A controllers/Apartments.php controller-ünkbe pedig illesszük be a sablonkezelést.

//$this->load->view('apartments', $data);

$this->template->set('title', 'Home');
$this->template->load('default_layout', 'contents' , 'apartments', $data);

Tesztelhetjük az új oldalunkat! 🙂

http://localhost/apartman/index.php/apartments/index