tohokuaikiのチラシの裏

技術的ネタとか。

PhpStormでXdebugがつながってるのにブレークポイントで止まってくれない時

./artisan serveだと止まってくれるのにApacheだとブレークポイントで止まってくれないなぜだ!!!???

とずっと思ってました。

色々と困ってる人がいました。
Googleで「file path is not mapped to any file path on server」とか検索すると

Debug problems: "remote file path ... is not mapped to any file path in project" – IDEs Support (IntelliJ Platform) | JetBrains
PHP(xdebug)+IntelliJでブレークポイント置いてるのに、そこで止まってくれないとき - カイワレの大冒険 Third
PhpStorm throws an error "Remote file path ... is not mapped to any file path in project" in the client-to-API context – IDEs Support (IntelliJ Platform) | JetBrains

で、ようやくわかりました。

ファイルのマッピングがうまくいってないんです。

artisan serveの場合は、相対パスで上手く決めてくれるっぽいんですが、Apacheだとそうはいきませんよね。

なので、ネットワークドライブに割り当てた後、こういう感じでProjectFilesにバーチャルパスをマッピングするとうまくいきました。

f:id:tohokuaiki:20200916152151p:plain

あー。こんなことで…

MySQLのUNIQUE制約のキー長制限に引っかかった

LaravelのユーザーテーブルのEmailのUNIQUEが掛けられなかった。

Server version: 5.5.65-MariaDB MariaDB Server

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

maxで767Byteなんだけど、…ってことは、UTF8が1文字4byteで計算されてるのかな?

767÷4=191.75なので…191文字までなら大丈夫なのかな?

ということで実験

VARCHAR(192)にしてみる

MariaDB [foodb]> alter table users change email email varchar(192) not null;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [foodb]> alter table `users` add unique `users_email_unique`(`email`);
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

ダメだって…

VARCHAR(191)にしてみる

MariaDB [foodb]> alter table users change email email varchar(191) not null;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [foodb]> alter table `users` add unique `users_email_unique`(`email`);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

計画通り(夜神ライトAA略

理由

show create table users;

してみると、

CREATE TABLE `users` (
...略...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

ってなってて、utf8mb4だった。ので4byteなのね。

Vue + Laravelでサブディレクトリに展開する際にやったこと。

Laravel

Apachehttpd.confにてバーチャルホスト設定にAliasを書く

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName www.example.com
        DocumentRoot /home/vagrant/htdocs

        Alias /baccarat_campaign_form "/home/vagrant/laravelapp/public"

        <Directory "/home/vagrant/laravelapp/public">
        Options FollowSymLinks
        AllowOverride All
        Require all granted
        </Directory>

こんな感じでAlias

Laravelのpublic/.htaccessRewriteを書き直す。

    RewriteEngine On
    RewriteBase /subdirectory_name #追加

...
    # RewriteRule ^ %1 [L,R=301] # コメントアウト
    RewriteRule ^(.*)/$ /subdirectory_name/$1 [L,R=301] #追加

bladeテンプレートの{{ mix(/js/foo.js) }} を描き直す

{{ mix(/js/foo.js) }}

{{ asset(mix(/js/foo.js)) }}

に変更。cssも。

Vuejsの変更

routerにbaseを入れる

export default new Router({
    mode: 'history',
    base: '/subdirectory_name/',
    routes: [
        {

axiosのbaseUrlを変更する。

これ、なんかいい方法ないのかな?とは思うけど、とりあえず。

import Vue from 'vue';
import "es6-promise/auto";
import VueRouter from 'vue-router';
import router from './router.js';
axios.defaults.baseURL = '/subdirectory_name';
window.Vue = require('vue');
Vue.use(VueRouter);

って感じで、axios.defaults.baseURL を設定する。

SSOをLaravel+Saml2で行ったところプロキシを挟んだらログインできなくなった。

プロキシだとhttpでアクセスするのでその周りだろうなってことで

このあたりでエラーが出ている。 vendor/aacotroneo/laravel-saml2/src/Aacotroneo/Saml2/Http/Controllers/Saml2Controller.php

<?php
    public function acs(Saml2Auth $saml2Auth, $idpName)
    {
        $errors = $saml2Auth->acs();

の所のエラーが

array(2) {
  ["error"]=>
  array(1) {
    [0]=>
    string(16) "invalid_response"
  }
  ["last_error_reason"]=>
  string(130) "The response was received at http://example.com/saml2/******/acs instead of https://example.com/saml2/******/acs"
}

という感じ。

たどっていって

vendor/aacotroneo/laravel-saml2/src/Aacotroneo/Saml2/Saml2Auth.php

<?php
    function acs()
    {

        /** @var $auth OneLogin_Saml2_Auth */
        $auth = $this->auth;

        $auth->processResponse();

        $errors = $auth->getErrors();

でエラーを拾っているので vendor/onelogin/php-saml/src/Saml2/Auth.php->processResponse()
vendor/onelogin/php-saml/src/Saml2/Response.php->isValid()
と進んでいくと、isValid()の

<?php
                $currentURL = Utils::getSelfRoutedURLNoQuery();
...zip...
                       $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL);
                        if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) {
                            $currentURLNoRouted = Utils::getSelfURLNoQuery();
                            $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted);
                            if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) {
                                throw new ValidationError(
                                    "The response was received at $currentURL instead of $destination",
                                    ValidationError::WRONG_DESTINATION
                                );
                            }
                        }

のところで、$currentURLが http://example.com/saml2//asc で、$destinationhttps://example.com/saml2//asc だから strncmp($destination, $currentURL, $urlComparisonLength) !== 0 ではないですよっていうエラー。

対処法を考えると

vendor/onelogin/php-saml/src/Saml2/Utils.php の所を読んでると、なんかやっぱりProxyを配慮してるっぽい。

<?php
    public static function getSelfProtocol()
    {
        $protocol = 'http';
        if (self::$_protocol) {
            $protocol = self::$_protocol;
        } elseif (self::getSelfPort() == 443) {
            $protocol = 'https';
        } elseif (self::getProxyVars() && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
            $protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'];
        } elseif (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
            $protocol = 'https';
        }
        return $protocol;
    }

self::getProxyVars() がtrueで、$_SERVER['HTTP_X_FORWARDED_PROTO']が存在してればそれになるっぽい。

HTTP_X_FORWARDED_PROTOは当然存在してるので、じゃあ getProxyVars()はというと単純にreturn self::$_proxyVarsしてて、

<?php
    /**
     * @param bool $proxyVars Whether to use `X-Forwarded-*` headers to determine port/domain/protocol
     */
    public static function setProxyVars($proxyVars)
    {
        self::$_proxyVars = (bool)$proxyVars;
    }

なんだけど、当然これもX-Forwarded-ForとかX-Forwarded-Protoとか存在してるわけで…あれー。

なんかProviderまで遡りそう

vendor/aacotroneo/laravel-saml2/src/Aacotroneo/Saml2/Saml2ServiceProvider.php で OneLogin_Saml2_Utils::setProxyVars(true); しているところがあった。

<?php
        if (config('saml2_settings.proxyVars', false)) {
            OneLogin_Saml2_Utils::setProxyVars(true);
        }

おぉー。

ということで、 config/saml2_settings.php

   'proxyVars' => false,

をtrueにして完了

Laravelのファイルアップロードのルートパス

config/filesystems.php に入っているので、

<?php
 config('filesystems.disks.public.root');

で取れる。

ちなみに、

<?php
 config('filesystems.disks.local.root');

はファイルアップロードではないstorageの場所。

ファイルをアップロードすると、というか$request->file('foo')->store()する際には、 config('filesystems.disks.public.root'); のpublicが付いてるっぽいので、後で取るといは、 config('filesystems.disks.local.root');から実ファイルパスを取ると良いのかな?

…ということは、この二つを後で返ると地獄が待っている。。。

まぁ、privateメソッドで外だししておくかな。