Category Archive Laravel 5

laravel: install in subdirectory / subfolder / shre

laravel ออกแบบมาไม่เหมาะกับ server ที่เป็น share host หรือจำเป็นต้องวางไว้ใน subdirectory / subfolder ร่วมกับโปรเจคอื่นๆ เท่าไหร่เพราะว่าตัวที่ทำงานจะอยู่ที่ /public/index.php แต่ไฟล์ config จะอยู่ที่ /.env นี่ไม่รวมที่เก็บไฟล์ ที่อยู่ใน /storage แต่มันก็เหมือน php framework อื่น ๆ ทุกเจ้านั่นละ

สาเหตุที่มันไม่เหมาะเพราะว่า ใส่ไปใน document root ทั้ง project ( / ) แบบนี้เวลาเรียกใช้จะเป็นแบบ http://localhost/blog/public ก็ดูไม่มีปัญหาอะไร แต่ถ้าคนที่เป็น hacker มาเห็น มาดูว่าเว็บนี้เขียนมากับ laravel นี่หวามหมูเลยเพราะถ้าเรียก http://localhost/blog/public/.env นี่จะสามารถโหลด config file ออกไปได้เลย ซึ่งเป็นอะไรที่พลาดมาก

ถ้าแก้ไม่ได้ ก็ทำได้โดยการแก้ apache ให้เห็น folder นี้เป็น Alias Directive หรือที่ iis ใช้คำว่า Virtual Directory ( เป็นวิธีที่ตั้งให้เรียก folder ใน url ได้เหมือนกับว่ามี folder นั้นตาม path นั้น ๆ แต่จริงๆ แล้ว folder นั้นไม่มีอยู่จริงๆ อาจจะชื่ออื่น หรือ link ไป folder อื่น )

  1. ถ้าใช้ xampp (เรารู้ว่าคนเขียน PHP ชอบ) config ของ apache จะอยู่ที่ C:\apache\conf\extra\httpd-vhosts.conf ถ้าใช้ตัวอื่นก็หาไฟล์ .conf ใน apache\conf ดูครับ
  2. เพิ่มบรรทัด Alias “/blog” “C:\xampp\htdocs\blog\public”
    1. “/blog” คือ folder ปลอม ๆ ที่จะให้เห็นใน url
    2. “C:\xampp\htdocs\blog\public” คือ path ของ folder ที่เก็บไฟล์จริงๆ
    3. restart apache

ถ้ายังใช้ไม่ได้อาจจะเพราะว่า config จากส่วนมีผลทำให้ใช้ไม่ได้อาจจะเพิ่ม

<Directory C:\xampp\htdocs\blog\public>
    AllowOverride All
    Require all granted
</Directory>

จากนั้น restart อีกครั้ง ในส่วนนี้จะยังไม่สามารถส่ง query string ได้จะต้องแก้ /public/.htaccess โดยเพิ่ม RewriteBase /laravel-site เช่น RewriteBase /blog จากตัวอย่าง

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

แก้เป็น

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    RewriteBase /blog

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

ทดสอบดูโดย

  • เปิดเว็บ http://localhost/blog จะต้องเข้าเว็บได้ปกติ
  • เปิดเว็บ http://localhost/blog/robots.txt จะต้องเห็นไฟล์ robots.txt ที่อยู่ใน C:\xampp\htdocs\blog\public
  • เปิดเว็บ http://localhost/blog/.env ต้องไม่เห็น เนื้อหาของไฟล์เด็ดขาดจะเป็น error 404 หรืออะไรก็ว่าไป

ข้อมูลเพิ่มเติม

  1. Alias Directive

Laravel: mix

มันคือ webpack ที่อธิบายง่าย ๆ คือ การ pack รวมเอา css, js มาไว้เป็นไฟล์เดียว หรือแค่ไฟล์ 4 ไฟล์ แทนที่จะโหลด css โหลด javascript หลาย ๆ ไฟล์ทำให้เว็บเราโหลดเร็วขึ้นเยอะเลย

เพราะว่าต้องใช้ npm ในการทำงานแนะนำว่าให้ทำตาม npm: ‘cross-env’ Is Not Recognized as an Internal or External Command ก่อนเพื่อป้องกันปัญหาที่จะเกินขึ้น

เริ่มจากการเพิ่ม package ที่จะใช้ใน command line ก่อนเช่น

  • npm i @fortawesome/fontawesome-free
  • npm i datatables
  • npm i icheck-bootstrap
  • npm i jquery
  • npm i jquery-ui
  • npm i moment
  • npm i numeral
  • npm i overlayscrollbars
  • npm i sweetalert2

เพิ่มโค้ทในไฟล์ /resources/js/bootstrap.js และเพิ่มโค้ทในไฟล์ /resources/sass/app.scss ตามคู่มือ 6.9 Laravel Mix

run command
npm run production
จะมีไฟล์เพิ่มมาใน /public/css/app.css และ /public/js/app.js

แก้ config AdminLte ให้ใช้ mix โดยเปิดไฟล์ /config/adminlte.php เปลี่ยน ‘enabled_laravel_mix’ => false, เป็น ‘enabled_laravel_mix’ => true,

จากนั้นลองใช้งานเว็บและ view source ดูจะเห็นว่าส่วนที่โหลด css และ javascript จะหายไปเยอะเลย

Laravel: AdminLTE

AdminLTE เป็น Control Panel หรือหรือที่ฝรั่งเรียกว่า dashboard ทีี่นิยมใช้กันมานานเพราะสวย ฟรี แม้แต่ตอนนี้ที่ laravel จะแนะนำให้ใช้ dashboard ทางการคือ Laravel Horizon แต่มันจะต้องการ extension pcntl ในการทำงานซึ่งใน windows จะติดตั้งไม่ได้ง่าย ๆ ทางที่ดีคือ ทางที่ง่ายที่สุด ใช้เจ้าเพื่อนเก่าของเรานี่ละ

มีคนทำ package ให้สามารถใช้ AdminLTE ง่าย ๆ ใน laravel โดยไม่ต้องเขียน code ให้ยุ่งยากคือ jeroennoten/Laravel-AdminLTE การติดตั้งก็ทำได้ง่ายแค่

  1. composer require jeroennoten/laravel-adminlte
  2. php artisan adminlte:install
  3. จากนั้นก็เปิดไฟล์ /resources/views/welcome.blade.php ขึ้นมาแล้วเอาตัวอย่างในเว็บ Usage วางแทนที่ของเดิมแค่นี้ก็ได้ตัวสวย ๆ มาใช้แล้วเปิดเว็บ laravel ดูก็ต่างจากหน้าขาวๆ แต่เดิมคนละเรื่องเลย

ที่นี้เริ่มจะเห็นว่า themes ที่ได้มาจะต่างจากตัวอย่าง LIVE PREVIEW อยู่หลาย ๆ จุด เราก็สามารถเปลี่ยนให้เป็นแบบที่ต้องการเริ่มด้วยคำสั่ง php artisan adminlte:install –only=main_views จะเป็นการ copy Blade Templates ของธีมนี้ไปไว้ที่ resources/views/vendor/adminlte ให้เราจัดการแก้ได้ตามความต้องการ

npm: ‘cross-env’ Is Not Recognized as an Internal or External Command

ใช้ npm แล้วมี error ‘cross-env’ Is Not Recognized as an Internal or External Command ทุกครั้ง ทั้งๆ ที่ทำตามคู่มือทุกอย่าง

วิธีแก้

  1. ลบโพลเดอร์ node_modules
  2. ลบไฟล์ package-lock.json
  3. เปิด command prompt โดยใช้ Run as administrator
  4. ใช้คำสั่ง npm install
  5. ทดสอบโดยใช้คำสั่ง npm run dev

หลังจากนี้ สามารถใช้ npm ได้ตามปกติแล้ว

IIS: การตั้ง Virtual Directory

iis เดิมมีเว็บที่เป็น c# อยู่แล้วและไม่สะดวกที่จะเพิ่ม domain name เข้าไปใหม่ จะตั้งเป็น site ให้ใช้อีก port ก็ติด firewall ที่ยอมให้ใช้ port 80 เท่านั้น และเพื่อความปลอดภัย framework อย่าง laravel ไม่ควรวาง folder ให้สามารถเรียกใช้ php ไฟล์อื่นได้นอกจาก /public/index.php จึงเลือกที่ใช้วิธี Virtual Directory คือ การสร้าง folder ใน url ให้ชี้ไปอีก folder ที่อยู่นอก C:\inetpub\wwwroot

การตั้ง Virtual Directory

  1. เปิดโปรแกรม Internet Information Services (IIS) Manager
  2. คลิกขวาที่ site ที่ต้องการ เช่น Default Web Site
  3. Add Virtual Directory
    Alias
    คือ folder จำลอง เช่น punpun_uat
    Physical path:
    คือ path จริง ที่ทำ shortcut ชี้ไปหา เช่น C:\www\punpun_v1_uat
  4. (ไม่จำเป็น) คลิกที่ site หรือ server แล้ว restart
  5. ทดสอบโดยเรียก url เช่น http://localhost/punpun_uat

วิธีนี้จะมีข้อดีคือ

  1. สามารถติดตั้งหลายเว็บ โดยใช้ domain และ port เดียวกันได้
  2. สามารถควบคุมการเข้าถึงไฟล์ที่ไม่ต้องการได้เช่น ถ้าวาง file ของ larave ไว้ใน C:\inetpub\wwwroot ตามปกติ ผู้ไม่หวังดีสามารถเรียกใช้ไฟล์อื่นๆ นอกจากไฟล์ /public/index.php ได้โดยตรงเช่น ไฟล์ php ที่สามารถ upload ไฟล์ได้โดยไม่มีการตรวจสอบสิทธิทำให้ไม่ปลอดภัย
  3. สามารถรัน code เดียวกันโดยใช้ php หลาย version หรือมี config คนละแบบได้โดยใช้วิธี การติดตั้ง PHP หลายเวอร์ชั่น บน IIS
  4. ซ่อน หรือย้าย folder ที่เก็บงานไปไว้ไดร์อื่น

Laravel: Basic API Token Authentication อย่างง่าย

ทำระบบ api ส่งข้อมูลให้ฝั่ง mobile ดึงข้อมูล บางส่วนมันไม่ใช่ความลับ จะทำระบบ authentication โหดๆ ก็เปลือง จะไม่ตรวจอะไรเลยก็ดูมันอ่อนไป สุดท้ายมาจบที่คำว่า basic API token คือ ขอแค่ส่ง token มาให้ถูกก็พอละจะได้ไม่โหลด server มาก ไว้ใช้กับส่วนที่เป็นการดึงข้อมูล common ๆ ง่ายๆ ที่ user ใช้ร่วมกันได้ไม่มีความลับอะไร

เริ่มจากทำ middleware ชื่อ apitoken ง่ายๆ มาใช้เอง

  1. ใช้ command สร้างขึ้นมา [code language=”text” title=”Defining Middleware”]php artisan make:middleware ApiToken[/code] มันจะสร้างไฟล์ขึ้นมาใหม่ที่ \app\Http\Middleware[code language=”php” title=”\app\Http\Middleware\ApiToken.php”]<?php

    namespace App\Http\Middleware;

    use Closure;

    class ApiToken
    {
    /**
    * Handle an incoming request.
    *
    * @param \Illuminate\Http\Request $request
    * @param \Closure $next
    * @return mixed
    */
    public function handle($request, Closure $next)
    {
    return $next($request);
    }
    }[/code]

  2. แก้โดยให้อ่านค่ามาจาก Environment Configuration แล้วเทียบกับค่าที่ส่งมา ว่าตรงมั๋ย ตรงก็ปล่อยผ่อนไป ไม่ตรงก็อด[code language=”php” title=”\app\Http\Middleware\ApiToken.php”]<?php

    namespace App\Http\Middleware;

    use Closure;

    class ApiToken
    {
    /**
    * Handle an incoming request.
    *
    * @param \Illuminate\Http\Request $request
    * @param \Closure $next
    * @return mixed
    */
    public function handle($request, Closure $next)
    {

    if ($request->expectsJson()) {

    if (env(‘API_TOKEN’) != $request->header(‘token’)) {
    return response(‘Unauthorized.’, 401);
    }

    } else {
    return route(‘login’);
    }

    return $next($request);
    }
    }
    [/code]เพิ่มขึ้นมาไม่กี่บรรทัดเอง

  3. เปิดไฟล์ .env มาเพิ่ม config token ที่ใช้เข้าไป[code language=”text” title=”\.env”]…
    API_TOKEN=a6b042ae282d91ab2c25bc7ae515af68
    …[/code]
  4. กำหนด url ที่ใช้ basic token ง่ายๆของเราโดยการแก้ routing ตามแบบ[code language=”php” title=”\routes\api.php”]Route::group([
    ‘middleware’ => ‘api.token’,
    ‘prefix’ => ‘common’,
    ], function () {

    Route::get(‘cars’, ‘[email protected]’);

    });[/code]ทุก route ที่อยู่ใน block นี้จะได้รับการปกป้องด้วย api.token

  5. แต่ตอนนี้ laravel ยังไม่รู้จักกับ api.token เราจะต้องไปเปิดไฟล์ \app\Http\Kernel.php และเพิ่ม $routeMiddleware ตามตัวอย่าง[code language=”php” title=”\app\Http\Kernel.php”] protected $routeMiddleware = [

    ‘api.token’ => \App\Http\Middleware\ApiToken::class,

    ];[/code]

เทสโดยใช้ Postman เรียก url ตามเดิม แต่จะมี common เพิ่มเข้ามาเพราะเพิ่มไปใน route เช่น http://localhost/prototype_laravel/public/api/cars แก้เป็น http://localhost/prototype_laravel/public/api/common/cars และต้องส่ง header ไปโดยมี

  • Accept application/json
  • token a6b042ae282d91ab2c25bc7ae515af68c

มาพร้อมๆ กันถึงจะสามารถ call api ตัวนี้ได้สำเร็จ ไม่งั้นจะเจอกับ Unauthorized.

laravel ajax method delete

เขียน ui laravel 5.1 อยู่ แบบใช้ ajax update ข้อมูล โดยเดิมมันใช้ form ธรรมดาแต่ใช้ method เป็น DELETE ทดลองส่งคำสั่งผ่าน ajax อยู่นานก็ไม่ได้ผล แถมมันวิ่งไปที่อื่นอีกตะหาก ทดลองเขียน php ธรรมดามาลองดูก็ไม่เจออะไร

นั่งงงอยู่นาน ก็ pass ค่าไปถูก เขียน php ธรรมดาไป ก็ได้ค่าไปถูก จน search ไปเจอ Delete request Jquery Ajax doesn’t work ที่แท้ laravel ถ้าจะใช้ method delete ต้องใช้ “method”: “POST” กับตัวแปร “_method”: “delete”[code language=”javascript”]
$(‘.glyphicon-trash’).click(function(e) {
e.preventDefault();

var r = confirm(‘Are you sure?’);
if(r == true) {
$.ajax({
"data": {
"_method":"DELETE",
"_token": "{{ csrf_token() }}",
},
"success": function(result) {
location.reload();
alert(‘success’);
},
"type": "POST",
"url": "/admin/index",
});
}
});
[/code]ใช้ได้แล้ว แต่น่าจะเขียนเป็นคู่มือเอาไว้นะ