Tag Archive laravel

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 ให้เราจัดการแก้ได้ตามความต้องการ

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 / PHP error 500

เจอ error 500 หลังจาก upload งานที่เขียนโดยใช้ laravel ทั้งๆที่เทสในเครื่องแล้ว หาสาเหตุอยู่นานก็ไม่เจอ

การตรวจสอบขั้นต้นที่เจอในเว็บทั่วๆไปคือ ให้ตั้ง permission ใหม่โดย

  • folder ให้เซ็ตเป็น 755 โดย[code type=”text” title=”chmod”]find . -type d -exec chmod 755 {} \;[/code]
  • และตั้งไฟล์เป็น 644[code type=”text” title=”chmod”]find . -type f -exec chmod 644 {} \;[/code]
  • ถ้าไม่หาย อาจะเพราะ user ที่ run apache กับ ftp หรือ เจ้าของไฟล์เป็นคนละ user กัน ทำให้การทำงานทำได้ไม่สมบูรณ์ แก้ได้โดยคำสั่ง chmod -R o+w โดยถ้าเก็บงานไว้ที่ /colume1/web/CMS_linux ก็ใช้[code type=”text” title=”chmod”]chmod -R o+w /colume1/web/CMS_linux[/code]

    ถ้าไม่เข้าใจอ่าน การเปลี่ยนสิทธิอนุญาตในไฟล์หรือไดเร็กทอรี

สร้าง muti site ใน laravel

ต้องการสร้างเว็บรองรับหลายๆ บริษัท โดยที่ใช้ code ชุดเดียวกันและให้ฝ่ายที่ดูแลสามารถเพิ่มข้อมูลและเว็บไซต์ ได้เองโดยที่ไม่ต้องใช้ความรู้ทางด้านการเขียนโปรแกรมเลย

เจอ package ชื่อ delatbabel/site-config แต่เพราะว่าเค้ารองรับแค่ laravel 5.1 เลยต้องสร้าง project ใหม่ตั้งแต่ต้นเลย

  1. พิมพ์ command[code language=”text” title=”installation 1=5.1″]composer create-project laravel/laravel sites "5.1.*"[/code]
  2. แก้ config ในไฟล์ .env ให้ติดต่อ databse ได้[code language=”text” title=”.env”]…
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_DATABASE=sites
    DB_USERNAME=root
    DB_PASSWORD=xxx
    …[/code]
  3. เพิ่ม package ในไฟล์ composer.json[code language=”php” title=”composer.json”]…
    "require": {
    "php": ">=5.5.9",
    "laravel/framework": "5.1.*",

    "delatbabel/site-config": "~1.0"
    },
    …[/code]
  4. run command[code language=”text” title=”command”]
    composer update
    [/code]
  5. เปิดไฟล์ config\app.php เพิ่ม[code language=”php” title=”configpp.php”]

    ‘providers’ => [

    Delatbabel\SiteConfig\SiteConfigServiceProvider::class,

    ],

    ‘aliases’ => [

    ‘SiteConfigSaver’ => Delatbabel\SiteConfig\Facades\SiteConfigSaver::class,

    ],
    …[/code]

  6. เพิ่ม Boostrap the Config Loader ใน 2 ไฟล์ คือ \app\Console\Kernel.php และ \app\Http\Kernel.php ต้องครบ 2 ไฟล์นะครับ ผมใส่ไม่ครบงงอยู่นานมากทำไม่มันมันใช้ไม่ได้[code language=”php” title=”\app\Http\Kernel.php”]

    protected function bootstrappers()
    {
    $bootstrappers = parent::bootstrappers();

    // Add the SiteConfig bootstrapper to the end.
    $bootstrappers[] = ‘Delatbabel\SiteConfig\Bootstrap\LoadConfiguration’;

    return $bootstrappers;
    }
    …[/code]

  7. Incorporate and Run the Migrations โดย run command[code language=”text” title=”command”]
    php artisan vendor:publish –tag=migrations –force
    php artisan migrate[/code]

การติดตั้งเสร็จแล้ว ที่นี้จะทดลองใช้งาน

  1. สร้างไฟล์ \app\Http\Controllers\HomeController.php[code language=”php” title=”\app\Http\Controllers\HomeController.php”]
    <?php

    namespace App\Http\Controllers;

    use App\User;
    use App\Http\Controllers\Controller;

    class HomeController extends Controller {

    /**
    * Show the profile for the given user.
    */
    public function index()
    {

    return ‘title = ‘.config(‘config.title’);

    $config = config()->all();

    return ‘<pre>’. print_r($config ,true).'</pre>’;
    }

    }
    [/code]

  2. เพิ่ม route ในไฟล์ \app\Http\routes.php [code language=”php”]

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

    [/code]
  3. ทดลอง set domain ขึ้นมาเทส เปิดไฟล์ C:\Windows\System32\drivers\etc\hosts [code language=”php” title=”host”]

    127.0.0.1 phunsanit.com
    127.0.0.1 pitt.com

    [/code]
  4. เพิ่มข้อมูลทกสอบโดยใช้ [code language=”sql” title=”sql”]
    INSERT INTO `configs` (`id`, `website_id`, `environment`, `group`, `key`, `value`, `type`, `created_at`, `updated_at`) VALUES
    (1, 1, NULL, ‘config’, ‘title’, ‘localhost’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’),
    (2, 1, ‘prod’, ‘config’, ‘title’, ‘localhost ON production’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’),
    (3, 1, ‘test’, ‘config’, ‘title’, ‘localhost IN TEST SERVER’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’),
    (4, 2, NULL, ‘config’, ‘title’, ‘pitt.com’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’),
    (5, 2, ‘prod’, ‘config’, ‘title’, ‘pitt.com ON production’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’),
    (6, 2, ‘test’, ‘config’, ‘title’, ‘pitt.com IN TEST SERVER’, ”, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’);

    INSERT INTO `websites` (`id`, `name`, `http_host`, `environment`, `created_by`, `updated_by`, `created_at`, `updated_at`, `deleted_at`) VALUES
    (1, ‘prototype’, ‘localhost’, ‘test’, NULL, NULL, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’, NULL),
    (2, ‘prototype’, ‘pitt.com’, ‘test’, NULL, NULL, ‘0000-00-00 00:00:00’, ‘0000-00-00 00:00:00’, NULL);
    [/code]

  5. ทดสอบโดยเปิด http://localhost/mcms/public/ และ http://pitt.com/mcms/public/

นำไปดัดแปลงให้เหมาะกับงานที่ทำครับ