2024年12月29日日曜日

VisualStudio Installer プロジェクトでコードサイン証明書を適用する

pfx形式が使えなくなった

製品のインストーラ(exe形式ファイル)を作成するために、これまで頑なに Install Shield 2015 の無料版を使用していましたが。
コードサイン証明書が変更になってしまい、pfx形式だとうまくビルドできなくなってしまいました。
そこで、VisualStudio 2022 の Installer プロジェクトを新たに作成することにしました。

ビルドしたインストーラファイル(msi形式ファイル)にコードサイン証明書を適用する必要があるのですが、その手順を自動化したので紹介します。

USBドングルでの証明書

これまでは、コードサイン証明書は .csr 形式のファイルで提供されていて、そいつを元に .pfx 形式ファイルを作成していました。
インストーラプロジェクトでは、sign タブの部分で pfx ファイルとパスワードを設定さえすればビルドできてたんですよね・・・
Visual Studio 2015の Install Shield では、ストアに登録した新しいコードサイン証明書を指定しても、エラーになってビルドできませんでした。

Installer Project を作成する

VisualStudio 2022 の Installer プロジェクトを作ります。
プロジェクトのプロパティで必要事項を設定するのですが、設定項目が Install Shield とほぼ同じのため、さほど混乱はしませんでした。
重要場部分としては、次のような点でしょうか。

  1. ProductCode はバージョン番号を変えたら必ず新しいものに変更する。
  2. UpgradeCode は変更してはならない。(そうしないとインストール時に以前のバージョンをアンインストールしてくれなくなります)
  3. ProductName 部分はインストール先のフォルダ名に利用される点に注意
  4. Version は##.##.####形式でなければならない
これまでバージョン番号には ##.##.##.## の形式だったのが使えなくなりました。
後述のアンインストールしてくれない問題は、ここが原因なのかもしれません。

signtool.exe を使ってコードサイン証明書を適用

無事インストーラが出来上がったら、コードサイン証明書を適用します。
signtool.exe の GUI で使用するのですが、入力項目が多く、とっても面倒でした。
ということで、インストーラプロジェクトの PostBuildEvent に次の行を追加して自動化しました。

signtool sign /a /n "証明書のトークン名" /t "タイムスタンプサーバのURL" /d "製品記述" /du "製品のURL" $(BuiltOuputPath)

途中でトークンパスワードを入力する手間が発生するけど。GUIでごにょごにょ入力するよりは、はるかにマシになりました。

以前のバージョンをアンインストールしてくれません。

UpgradeCode は正しく設定しているにもかかわらず、インストーラが以前のバージョンを事前にアンインストールしてくれなくなりました。
いろいろ試したり調べたりしたけど、どうしてもだめでした・・・。
バージョンの表現形式が変わってしまったからなのかもしれません・・・
あるいは、exe形式から msi形式に変わったからなのか?

もし情報をお持ちの方いらっしゃいましたら、教えてくださいませ。

まとめ

ついに Install Shield を脱却しましたw
めでたしめでたし。

2024年11月17日日曜日

スタイルシートに指定している色で表示されない

Color picker で異なる色が表示される

WEBページの設計では、色にこだわるケースが多いですね。
顧客から指定された色でデザインをしていたんですが、おかしな現象がでました。
スタイルシートに指定している色で、表示されないのです。

コードでは次のように指定しています。

--color-main-bg: rgb(3, 180, 198);
.top-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    max-width: 100%;
    padding: 1rem;
    margin: 0 auto;
    background-color: var(--color-main-bg);
}

Chrome color picker で別の色が表示される

Chrome で表示させて、開発者ツールを開くと、図のようにちゃんとコーディングした内容が反映されています。

ところが、Chromeの拡張機能の Color Picker で表示されている部分を調べると

おいおい、どーして色が違うんだよ・・・
おれさまのコードのどこに問題があるって言うんだよ~・・・
使ってる bootstrap とか normalize とか milligram なんかが悪さしてるのかな~・・・
と、必死にデバッグするも、問題点が見つからない・・・・

マルチディスプレイ

ディスプレイを2つ並べて開発してるんですが、表示してるページをもう一方のディスプレイにスライドすると・・・
あら不思議。ちゃんと指定された色で表示されちゃいます。

いったい、どういうことヨ?
どうやら、ディスプレイがおかしいのだということで、調べてみたよ。

画面の色調整

コントロールパネルに「色の管理」というのがありまして。
「詳細設定」-「ディスプレイの調整」というボタンがありました。
ぽちっ!

なんだかわからないけど、とりあえず、「次へ」ボタンで進めていきます

まとめ

するってえと、見た目も Color Picker でもちゃんと表示されるようになりましたよ!

いやあ、てっきり自分のプログラムが悪いんだろうと、とっても長い時間悩みましたよ
ほんと、こーゆーの勘弁してほしいですわ。
ま、なおってくれたので良しとしましょう。
めでたしめでたし。

c.f.
https://support.hp.com/jp-ja/document/c04249810

SQLiteを使ったプログラムで Out of memory 例外が発生する

メモリいっぱいあるのに、Out of memory

C# で開発したファイル処理プログラム。
SQLite を使ってインデックスを貼り高速検索するようにしてます。
SQLite の便利な機能に、データベースをメモリ内で処理させるってのがあります。

   SqlConnectionSb = new SQLiteConnectionStringBuilder { DataSource = ":memory:" };
   SqlConnection = new SQLiteConnection(SqlConnectionSb.ToString());
  
こうすることで、オンメモリ処理になり、さくさく動くようになります。
DataSource をハードディスク上のファイルに置き換えることもできますが、それだと遅くて使い物にならないような機能のプログラムなんです。
このプログラムにちょっとばかり大きなファイルを処理させると、途中で Out of memory 例外でエラーになって落ちてしまう問題が出ました。
どーして?
タスクマネージャで見ててもメモリの空き容量は十分にあるのに。
そんな、ばなな。

キャッシュを大きくしてみたり

SQLite out of memory で検索しても、どういうわけかなにもヒットするページがありません。
しかたなく接続時のパラメータを変更してみたり。

SqlConnectionSb = new SQLiteConnectionStringBuilder { DataSource = ":memory:", CacheSize = 10000 };
PageSize とか MaxPageCount といったパラメータも変更してみたけど、効果なし・・・困りました。

32ビットを選ぶ?

Visual Studio のプロジェクトは「AnyCPU」としていて、32bitでも64bitでも動作するようにしてるつもりだったけど。
プロジェクトプロパティ「ビルド」の項目に、「✅32ビットを選ぶ」ってのがありました。

なんじゃ、こりゃあ?ってなくらい、知りませんでしたよ。(笑)
このオプションのせいで、AnyCPU が 32bit プロセスとしてビルドされてしまうわけです。
これまでリリースしてたプロダクト、全部再確認が必要になりましたよw

上記チェックボックスをOFFにして、64bitOSで動作させたら、Out of memory例外は出なくなりました。
あ、プロジェクトプロパティは Debug と Release の両方の構成を変えなきゃならないから、注意してくださいまし。

今回の問題は、問題を再現するのにもトライアンドエラーするのにも1時間以上かかるので、大変でした。

ま、解決できてよかった。
めでたしめでたし。

2024年11月10日日曜日

bootstrap(v5) でブレークポイントが正しく表示されない


スマホサイズで改行されてしまう!

bootstrapでデザイン中に、スマホサイズでrow の col が12以内なのに改行されてしまう問題に遭遇しました。


<div class="container-fluid">
    <div class="row">
        <div class="col-6 col-sm-4 col-lg-2">
          ll
        </div>
        <div class="d-none d-sm-block col-sm-4 col-lg-4">
          lr
        </div>
        <div class="d-none d-lg-block col-lg-4">
          rl
        </div>
        <div class="col-6 col-sm-4 col-lg-2">
          rr
        </div>
    </div>
</div>

これ実行すると、スマホサイズの時、ll と rr 部分が改行されて出力されてしまいます。
なぜじゃあ?

解決方法

row の部分を次のように変更することで、無事行内に収まるようになりました。


<div class="container-fluid">
    <div class="d-inline-flex w-100 justify-content-between">
        <div class="col-6 col-sm-4 col-lg-2">
          ll
        </div>
        <div class="d-none d-sm-block col-sm-4 col-lg-4">
          lr
        </div>
        <div class="d-none d-lg-block col-lg-4">
          rl
        </div>
        <div class="col-6 col-sm-4 col-lg-2">
          rr
        </div>
    </div>
</div>

まとめ

けっこう格闘してしまった
動いたから、よし!
めでたしめでたし。

2024年10月28日月曜日

deprecated: str_replace(): passing null to parameter #2 ($replace) of type array|string is deprecated

大量の str_replace のエラー

CentOS もサポート終了してしまったので、数ある Linux プロジェクトの多くを Ubuntu に変更してます。
当然、CakePHP3 のような古いバージョンで構築されているプロジェクトも移植の対象になります。
とあるプロジェクトを Virtual Machine 上に構築した Ubuntu 22.04 LTE 上で動作させようとして、最初に CakePHP home を表示したら、こんなエラーがたくさん出てきまして。

PHP8.1 あたりで仕様が変わったことによる問題なんですけどね。
CakePHP のソースも変更しなきゃならないの?とビビってしまいました。

動作環境

OS:Ubuntu 22.04.01 LTE
MySQL: MariaDB 15.xxx
PHP 7.4.33
phpMyAdmin: 5.2.1
CakePHP 3.10

ということで。
CakePHP3 を動作させるための環境なので、PHP 7.4 で動かそうとしてるんだけど、Cake の homeページを開こうとするときに、PHP 8.x が動いちゃってる、という状況なんですね。

PHP の動作バージョンを変更する

この方法は、あちこちに書いてありますが、alternatives で定義しておき、バージョンを変更します。
sudo update-alternatives --install /usr/bin/php php /usr/bin/php7.3 100
sudo update-alternatives --install /usr/bin/php php /usr/bin/php7.4 110
sudo update-alternatives --install /usr/bin/php php /usr/bin/php8.0 120

sudo update-alternatives --config php
There are 3 choices for the alternative php (providing /usr/bin/php).

Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/php8.1 130 auto mode
* 1 /usr/bin/php7.4 110 manual mode
2 /usr/bin/php8.1 130 manual mode
3 /usr/bin/php8.2 82 manual mode

Press to keep the current choice[*], or type selection number:
ここで、対象となる PHP をセットしておけばいいわけです。

apache2 の mod を変更する

ちゃんとPHPを7.4に変更したのに、ブラウザで表示させたときのエラーは消えません・・・PHP8 で動いてしまいます
原因は apache2 でした。
# ll mods-enabled/php*
lrwxrwxrwx 1 root root 29 Oct 28 11:06 mods-enabled/php8.1.conf -> ../mods-available/php8.1.conf
lrwxrwxrwx 1 root root 29 Oct 28 11:06 mods-enabled/php8.1.load -> ../mods-available/php8.1.load

# a2dismod php8.1
# a2enmod php7.4
# service apache2 restart

home を開いてみると、無事エラーが消えているのを確認できます。

まとめ

「環境構築」って、なんか、しょっちゅうやってる気がします。
え?コンテナを使えって?w知ってるw

ま、こういった悩みを持ってしまう人も、少なからずいるだろうから、書き留めておきますよっと。
c.f.
https://qiita.com/murakami77/items/a9945f2a8e51ca3791de

2024年6月14日金曜日

Hyper-Vで終了できなくなったOSを削除する。

仮想マシン上のOSが落ちてしまった

Hyper-Vで作成した仮想マシン、何らかの問題で固まってしまうことがあります
OSは動きっぱなしなのでメモリとかリソースを使ったまま。
動作中の仮想マシンは Hyper-V に削除メニューがありません。
そうなってしまった場合の対処方法についてまとめます。

OSをインストールしたら固まってしまった

今回は、CentOS 6.5 という古いバージョンのしかも32bit版の環境を作る、という目的でした
インストールの手順は省くとして。
最終的に起動後は、こんな状態になってしまい、「停止」とか「シャットダウン」も機能しなくなってしまいました!

Hyper-V では「実行中」と表示されていてメモリを消費しています。
「削除」メニューもありません・・・
このまま放置するとメモリの無駄遣いですね・・・

エクスプローラで、Hyper-V の仮想マシン用フォルダを削除しようとしても、「使用中」で削除できません。

そんなときの対処方法

Hyper-V を停止して、その間にフォルダを削除してから Hyper-V を再開すればいいってことです。

Windows の「サービス」を起動して、「Hyper-V Virtual Machine Management」を見つけましょう

「スタートアップの種類」を「手動」に変更して「適用」を押します。
「停止」ボタンを押してサービスを停止します。
必要ないのかもしれませんが、なんとなく、この時点で Windows を再起動させています。

Windows を再起動させたら、まず、不要な仮想マシンフォルダをエクスプローラで削除します。

削除できました!

サービスを起動して、「Hyper-V Virtual Machine Management」を「自動」にして「開始」します。

Hyper-V を起動してみると、無駄に動作していたOSがなくなっていることがわかります。

まとめ

これ、よくあるんですよねー。
同じように困ってしまったら、上記方法を(自己責任の範囲でw)お試しください。
めでたしめでたし。

2024年5月5日日曜日

PHP の日本語ファイル名処理で文字化け

電子情報保存法に対応

請求書をサーバに保存して電子情報保存法に対応しましょ、という仕組み作りがあちこちで行われているかと思います。
過去の経験から、サーバー上に文書ファイルを保存しようとする場合、日本語のファイル名では保存しない方がいいと思いますよ。
たとえば、濁点、半濁点付きのファイル名「ぱぴぷぺぽ.pdf」ファイルをそのままサーバに保存しておいて、ブラウザでダウンロードできるようにしようとすると
Windows クライアントでは正しく表示できるけど、MacOS では正しく処理できない、といった問題が発生してしまいます。

そこで、サーバに保存するときには、ファイル名を半角英数字のみにして保存するようにしてみました。
ファイル名を拡張子と分離するには、PHP の pathinfo() 関数を使います。
半角英数ファイル名の構造には、BASE64 エンコードと使えない文字を置き換える base64UrlEncode() 関数を使って処理します。

BASE64を使ったエンコード処理

function base64UrlEncode($data) 
{ 
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 
} 

ファイル名の拡張子以外の部分を base64UrlEncode で構築する処理を用意してみました。
入力フィールドで拡張子を指定しなかった場合は、.pdf ファイルだという処理も入れてみています。

function buildFileName($filename, $def_ext = 'pdf')
{
    $file_parts = pathinfo($filename);
    $filenode = $file_parts['filename'];
    $ext = $file_parts['extension'];
    if(strlen($ext) == 0)
    {
        $ext = $def_ext;
    }
    $name = $this->AsCommon->base64UrlEncode($filenode) . '.' . $ext;
    return $name;
}

日本語ファイル名が正しく処理されない

$filename = uildFileName("ぱぴぷぺぽ.pdf");
を実行すると、".pdf" という文字列が返ってきてしまいました・・・
またもや日本語処理に別の対応が必要になってしまいます・・・こまったもんだ・・・
調べると、ロケールの設定に依存しているため、というのがわかりまして。
setlocale(LC_ALL, 'ja_JP.UTF-8');
を実行してやると、上手くいくようになりました。

cakePHP での対応

pathinfo() やそのたぐいの関数を使うソースプログラムに、毎回 setlocale を記述するのは無駄を感じますね。
ましてや、プログラムを国際化対応しようとすると、あちこち変更しなければならなくなってしまいます。

cakePHP の config/app.php を見ると、次の記述があります。

'App' => [
    'encoding' => env('APP_ENCODING', 'UTF-8'),
    'defaultLocale' => env('APP_DEFAULT_LOCALE', 'ja_JP'),

これを利用して、config/bootstrap.php の 112 行目あたりに以下を追加しました。

setlocale(LC_ALL, Configure::read('App.defaultLocale') . '.' . Configure::read('App.encoding'));

まとめ

毎度のことながら、日本語対応は問題が多く発生しやすいですね。
国際化対応時に、上記対策でうまくいくのかどうかまでは試しておりません。あしからず。
今回も苦しめられましたが、なんとか事なきを得ました。

めでたしめでたし。

参考になったサイト
https://qiita.com/REAS07/items/3f86a0834d612edaecd6

2024年4月18日木曜日

cakePHP3でメールの受信

XSERVER でも使えるように

cakePHP3を使ったプロジェクトでメールを受信して添付ファイルを保存しようとしましたら。
まず、POP3用のライブラリをインストールしなきゃいけないことがわかりました。
で、VM上の Linux にインストールしてみました。

# pear channel-update pear.php.net
/usr/share/pear/Net POP3.php, Socket.php がインストールされました。
# pear install Mail_mimeDecode
/usr/share/pear/Mail にインストールされました。

でも、本番環境の XSERVER では root 権限でインストールなんてできないよね。
と、いうことで。 /usr/share/pear/のファイルを CAKEPHP_DIR /appendix/pear に無理やりコピーして使うことにしました。

require が動かない

 require('Net/POP3.php');
require('Mail/mimeDecode.php');
としなきゃいけないのに、パスが効いてないから読み込めない。
PHP で get_include_path() を呼び出すと、次のようなインクルードパスが設定されていました。
".:/usr/share/pear:/usr/share/php"
そこで、
set_include_path(get_include_path() . PATH_SEPARATOR . CAKEPHP_DIR . '/appendix/pear/');
を呼び出すことで require がうまくいってくれました。

ポート番号995(POP3S)での受信設定

アカウント情報は、とりあえず MailServers データベースにでも置いといて、次のように取り込むようにしました。

  $account = $this->MailServers->find()
    ->select(['pop3_server', 'pop3_port', 'pop3_account', 'pop3_psw'])
    ->first();
実際に POP3サーバに接続してログインする部分のコードは、こんな感じ
  $pop3 = new Net_POP3();
  $pop3->connect($account->pop3_server, $account->pop3_port);
  $pop3->login($account->pop3_account, $account->pop3_psw);
  $message_count = $pop3->numMsg();
$account->pop3_port を 995 にすると、接続ができずに悩みました。
pop3_server にプロトコルヘッダ ssl:// を付けてあげることで接続できました(^^)v

メール受信処理

実際には、message-id をDBに保存しておいて、すでに処理済みのメールかどうかをチェックしたりするのですが
メールの取り込みは次のような感じです

    for($mail_no = 1; $mail_no <= $message_count; $mail_no++)
    {
        $msg = $pop3->getMsg($mail_no);
        $decoder = new Mail_mimeDecode($msg);
        $mime = $decoder->decode([
            'include_bodies' => true,
            'decode_bodies' => true,
            'decode_headers' => true,
        ]);
        $messageid = $mime->headers['message-id'];
        $subject = $mime->headers['subject'];
        $sender = $mime->headers['from'];
        $date = $mime->headers['date'];
        // メール解析
        [$body, $attachments] = $this->analyze($mime);
        // 必要な処理
    }

今回は本文と添付ファイル情報を必要としたので、メールの mime 解析部分は、こんな感じです。

function analyze($mime)
{
    $body = "";
    $attachments = [];

    if(!isset($mime->parts))
    {
        // シングルパート(テキストのみ)
        $body = trim(mb_convert_encoding( $mime->body, "UTF-8", 'ASCII, JIS, UTF-8, SJIS' ));
    }
    else
    {
        // マルチパート
        foreach($mime->parts as $part)
        {
            if((strtolower($part->ctype_primary) == 'text') && (strtolower($part->ctype_secondary) == 'plain'))
            {
                $body .= trim(mb_convert_encoding( $part->body, "UTF-8", 'ASCII, JIS, UTF-8, SJIS' )) . "\n";
            }
            else if((strtolower($part->ctype_primary) == 'application')) 
            {
                $filename = $part->ctype_parameters['name'];
                if(empty($filename))
                {
                    $filename - $part->d_parameters['filename'];
                }
                if(0 < strlen($filename))
                {
                    if(isset($part->body))
                    {
                        $attachment = [];
                        $attachment['filename'] = $filename;
                        $attachment['body'] = $part->body;
                        $attachments[] = $attachment;
                    }
                }
            }
            else if(strtolower($part->ctype_primary) == 'multipart')
            {
                foreach($part->parts as $part2)
                {
                    if(strtolower($part2->ctype_primary) == "text") 
                    {
                        $charset = $part2->ctype_parameters['charset'];
                        $body = mb_convert_encoding($part2->body, 'UTF-8', $charset);
                        break;
                    }
                }
            }
        }
    }  
    return [$body, $attachments];
}

pear の修正

いろいろエラーが出たので、pear 側のソースも変更しました。

Net/POP3.php 変更点
/* 第3パラメータが非推奨になっていたので削除
define('NET_POP3_STATE_DISCONNECTED',  1, true);
define('NET_POP3_STATE_AUTHORISATION', 2, true);
define('NET_POP3_STATE_TRANSACTION',   4, true);
*/
define('NET_POP3_STATE_DISCONNECTED',  1);
define('NET_POP3_STATE_AUTHORISATION', 2);
define('NET_POP3_STATE_TRANSACTION',   4);

// クラス名と同名のコンストラクタが非推奨なので変更
// function Net_POP3()
function __construct()

Mail/mimeDecode.php 変更点
// ISO-2022-JPのメールヘッダを正しく解析してくれない。
function _decodeHeader($input, $default_charset=false)
{
    if (!$this->_decode_headers) {
        return $input;
    }
    // iconv_mime_decode を使うように変更。
    $input = iconv_mime_decode($input, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
    // Remove white space between encoded-words 以下を削除。
    return $input;
}

// はだかのHTMLテキストが渡されてエラーでまくりなので変更
function _quotedPrintableDecode($input)
{
    // Remove soft line breaks
    $input = preg_replace("/=\r?\n/", '', $input);
    $input = quoted_printable_decode($input);
    // Replace encoded characters 以下を削除
    return $input;
}

まとめ

XSERVERにインストールできないとなると、AWS EC2 あたりにサーバー移動しなきゃならないかな?と悩んでいたので、受信できるようになって助かりました。

めでたしめでたし。

2024年3月11日月曜日

Excelから変換したPDFが携帯電話で表示されない

管理してるWEBサイトに Excel で作成されたファイルを表示するために、PDFに変換してアップします。よね?
うちもそうしてます。
日本語のファイル名にならないように英数名のファイルにしてアップロード
よし。これで完了、っと。

携帯(iPhone)で見えないとのご連絡!

いや、いつもやってることなのに。
どれどれ、と自分の iPhone で開いてみると・・・

 ほんとだ!
左上1/4くらいしか表示されません!
で、しばらくすると全体が表示されます・・・・
いや、これじゃ、あかんでしょ・・・

PDF に変換する!

Excel でPDFファイルとして保存するには、2つの方法があります。

ひとつは、「ファイル」メニューから「Adobe PDF として保存」を選ぶ方法です。
今回は、こちらの機能を使ってPDFに変換しました。

PCではちゃんと表示されるのにな・・・

別の方法を試してみる

もう一つ。
「ファイル」「名前を付けて保存」で、ファイル名の下のコンボボックスで「PDF(*.pdf)」を選ぶ方法です。

今回のファイルの場合、こちらを使うと、PDFのファイルサイズが少し小さくなりました。

まとめ

2番目の方法で出力したファイルをWEBサイトに公開したところ、iPhone でもサクッと表示されるようになりました。
同じ悩みを経験した場合は試してみてくださいまし。

めでたしめでたし。

2024年3月10日日曜日

WEBアプリ[Enter]キーでフォーカス移動の問題点

HTMLの[Enter]でフォーカス移動

むかしはねぇ。業務系アプリのほとんどで、入力枠で[Enter]押されたら、次の入力枠にフォーカスを移すのって、当たり前でしたよね。
ところがどっこい。HTMLでの[Enter]は submit() がデフォルトになってる。
業務系WEBアプリとしては、[Enter]キーでフォーカス移動は、ユーザーからのご要望も強くありますね。
と、いうことで。
[Enter]キーでのsubmit()をフォーカス移動にしてたのが、次のコードです。

$(function(){
  $("input").on("keydown", function(e) {
    if ((e.which && e.which !== 13) && (e.keyCode && e.keyCode !== 13)) 
    {
      return true;
    }
    else
    {
      var count = $('input').length;
      var current_index = $('input').index(this);
      for(let index = current_index; index < count; index++)
      {
        var next_input = $('input')[index + 1];
        var is_hidden = $(next_input).is(':hidden');
        var is_readonly = $(next_input).prop('readonly');
        var is_button = $(next_input).is(':button');
        if(is_hidden || is_readonly || is_button)
        {
          continue;
        }
        $(next_input).focus();
        return false;
      }
      $('input')[current_index].blur(); 
      return false;
    }
  });
}(this));
textarea に移動しない!と思った人は変更してくださいw

MacOSの[かな]キーでフォーカス移動してしまう!

Mac 使いのお客様から、こんなクレームが来ました!
フォーカスが移動する、ってのなら上記コードが原因のわけです。
と、いうことで。
MacOS 機を入手して動きを調べてみました。

「かな」キーの keyCode が 13 !!!

なんでこんなことしてんですかねーw
数字(と記号の)郵便番号入力から、住所欄の入力に移動して「かな」キーを押すと、住所欄すっ飛ばして「名前」のところにジャンプしてしまうわけですw
『使えねぇ』と思われても仕方ありません。ええ。

keydown を keypress に

  $("input").on("keydown", function(e) {
この部分を

  $("input").on("keypress", function(e) {
に変更することで、対応できました。

まとめ

ちなみに、「かな」キーのkeydownでのkeyCode は 13 でしたが、 keypress での keyCode は 229 が入ってきます。

HTMLって日本語のことちっとも考えてくれてないよね。
IE にあった、IME の制御機能、入れてほしいよね・・・

とりあえず動いた。
めでたしめでたし。


参照
Enterキーを無効にする方法
日本語入力時のキーイベントの仕様変更と対策

2024年2月8日木曜日

CakePHP でアソシエーションを含めたレコードの読込み

containを使え

あちこちのサイトを見ると、contain を使った方法がたくさん書いてありますね。
たとえば、products テーブルに取引先のIDである partner_id が含まれているとき
$product_id で示されるレコードを取得するには、次のように書きます。

  // コントローラの initialize() で
  $this->loadModel('Products');
  // レコードの取り込み処理で
  $record = $this->Products->get($product_id, ['contain' => ['Partners']]);

cakePHP を書きなれている人なら、同じみでしょう。
QueryBuilder を使った find() などでもアソシエーションとともに読み込みできますね。

  $record = $this->Products->find()
    contain(['Partners'])
    ->first();

どんだけ書くねん!

『こう書いておけば動く』から、なんでしょうか・・・
たぶん、世界中の人が、さまざまなプロダクトのテーブル参照を『とっても便利な』QueryBuilder を使って読み込んでいるのでしょうね。

おおきなプロダクトになってくると、それぞれのテーブルごとにレコード参照のコントローラ.phpファイルが増えて、手に負えなくなってしまいますねぇ

簡単にしちゃいましょう

レコードが _id で示されるインデックス指定のフィールドを持っているとき、contain でアソシエーションを『含めずに』読み込む、なんてことは逆に少ないはずです。
少なくとも、私の担当するプロダクトではレコード読込でアソシエーション不要、なんてことは皆無に近いですね。
そこで、こんなコードを共通コンポーネントに書き加えました。

/**
 * 指定テーブルのアソシエーション(BelongsTo/BelongsToMany)を含めて
 * レコードを取得する
 */
function LoadRecordWithBelongs($table, $id)
{
  $record = false;
  $contains = [];
  $associations = $table->associations();
  $items = $associations->getByType(['BelongsTo', 'BelongsToMany']);
  foreach($items as $item)
  {
    $name = $item->getName();
    $contains[] = $name;
  }
  $record = $table->get($id, ['contain' => $contains]);
  return $record;
}
ようするに、belongsTo, belongsToMany のアソシエーション定義されているテーブルなら、そいつをまとめて読み込んでくれよ、というコードです。

まとめ

共通化することで、たくさんのソースを削除することができるようになりますが。
それは、これからやり始めようとしてるところです・・・w

めでたしめでたし。

2024年2月3日土曜日

Visual Studio Code でCentOS7のリモートデバッグができなくなった!

突然使えなくなった VS Code + Remote SSH

昨日まで、普通に使えていた VS Code と Hyper-V 上の CentOS 7.9 上でのリモート開発
今朝、突然、使えなくなりましたよ。
どうやってもつながらない!
今日は土曜日だから、月曜あたりは日本中でこの問題、世界中で騒がれるんじゃないでしょうかね・・・
ったく・・・

パスワード入力してログインしようとすると、エラーになって繋がりません。

glibcとlibstdc++のバージョンが古い?

OSの中身を見てみると、確かに古いようです。
で、それならバージョンアップしてやろうということで、やってみました。
バージョンアップでやってみたことは、次の通り。
・gcc のバージョンアップ 13.2.0 をインストール。2度失敗。長かった・・・
・ここで、libstdc++を入れ替えできました。
・次に glibc のバージョンをあげる件ですが、結論から言いますと失敗しました。
・python 3 のインストール
・yum が動かなくなるので yum 編集
・gmake が古いと怒られます。で、4.2あたりをインストールしようとすると、エラーで止まっちゃう!
と、いうことで、CentOS7 側での対応はできませんでした。
(6時間・・・返してくださいよ・・・(´;ω;`))

解決方法

要するに、Visual Studio Code のアップデートが原因なんですよ
January 2024 (version 1.86)
拡張機能の Remote SSH がアップデートされてました。
で、このアップデートを古いバージョンにして、CentOS 側の /home/ユーザー ディレクトリ上の .vscode-server ディレクトリを削除。
・・・問題は変わりませんでした。
納期すぎていて、とっても焦っているのに、丸一日潰れかかってます・・・どーしてくれるんだ!

対応策

VS Code のバージョンをダウングレードしてしまいます!
まず、現在の VS Code をアンインストールする前に、次を実行しておきます。
・VS Code の自動アップデートを停止しておく。(設定:update あたり)
・拡張機能の自動アップデートを停止しておき。
VS Code をアンインストール。
このページの Downloads ってとこから該当バージョンをダウンロード
インストールしましょう!
CentOS 側の /home/ユーザー ディレクトリ上の .vscode-server ディレクトリを削除もわすれずに。

動いた!

昨日まで使っていたワークスペースを開いてみると、無事パスワード入力後に編集できるようになりました。
めでたしめでたし。

2024年1月28日日曜日

Hyper-V に Ubuntu 22.04.03 をインストールしようとして・・・

なんども失敗したので、記録しとく。

いつものとおり、Ubuntuサイトから .iso ファイルをダウンロードして
いろいろと失敗したので。

cloud-init で停止してしまう

上段に[Install Complete!]がでたんで[Reboot]を選択したら、真っ黒画面になってしまって、一晩放置してもNGだった。
再度、インストールを試みてみると、ログで reached cloud-init のところで止まったまま。(これも一晩放置したけどダメ)
cloud-init を無効にする方法はネット上にあるけど、そもそもログインする前に死ぬので、どーしようもない
※このVM、Hyper-Vでは起動中のままになってしまって、削除することもできなかったよ。
Hyper-Vサービスを停止⇒PC再起動⇒VMファイルを削除⇒Hyper-Vサービス起動で削除できました。

そこで。ネットワークにつながない状態でインストールすればいいんだ!ということに気づいたわけです。 Hyper-V のネットワークアダプタを接続せずに新しい Ubuntu をインストールすることで、ようやくログイン画面にたどり着きました!

インストール後の注意点

Ubuntu の説明サイトを見ると、sudo コマンド経由の説明ばっかりで、めんどくさいですよね・・・
あちきは、もっぱら $ sudo su - を実行して root 権限に移動してから処理してます。

まだネットワークアダプタがない状態で、次をやっておきます。
cloud-init を無効化

  # touch /etc/cloud/cloud-init.disabled
  
これでネットワークつないで起動しても cloud-init で止まることはない(はず)

ついでに、起動高速化のため、あちこちに書いてある grub timeout を変更しておきます。

  # sudo gedit /etc/default/grub
  # GRUB_TIMEOUT=2
  # sudo update-grub
  

ネットワークを設定します。
# ip link でネットワークアダプタ名を取得します (ここでは、eth0)
で、ネットワーク設定の yaml ファイルを編集します。(IPアドレスは、ご自分の環境に合わせてくださいまし)

  # mv /etc/netplan/00-installer-config.yaml  /etc/netplan/00-installer-config.yaml.disable
  # vi /etc/netplan/01-installer-config.yaml
  network:
    version: 2
    renderer: networkd
    ethernets:
      eth0:
        dhcp4: false
        addresses: [192.168.0.90/24]
        routes:
          - to: default
            via: 192.168.0.1
        nameservers:
          addresses: [192.168.0.1]
  

ここで一度シャットダウン。Hyper-V の設定でネットワークアダプタを接続して起動します!
・・・真っ黒画面になってしまうかもしれません(実際、大汗でしたw
2分ほど待つと、boot シーケンスが動作し始めますので、我慢してください(笑)
ネットワークに繋がれば、TeraTerm でSSHログインできます。

真っ黒画面対策として、パッケージ関係のアップデートを行います。

  # apt update
  # apt dist-upgrade
  # apt autoremove
  

再起動してみましょう!

  # reboot
  
さくっと起動するようになりました。

blk_update_request: I/O error

Hyper-V コンソールを表示させると、しょっちゅう blk_update_request: I/O error が出力されます。
これは、フロッピーディスクがないってエラーのようです。 よそのサイトを参考に、以下の方法でエラーをなくすことができました。

   blacklist に登録
  # echo "blacklist floppy" >> /lib/modprobe.d/dist-blacklist.conf
   カーネルから floppy を削除
  # rmmod floppy
   dracut がなかったのでインストール
  # apt install dracut-core
  initramfs の再構築をする
  # cd /boot/
  # dracut -f -v
  ▼再起動
  # reboot
  


次からは、失敗しないぞ!w
めでたしめでたし。

参考にしたサイト
https://x.momo86.net/article/154
https://qiita.com/n_mikuni/items/bf94289eaff93b82ac27

2024年1月27日土曜日

仮想マシンサービスは利用できません

Hyper-V マネージャでサービスを停止してしまった

どうしても止められなくなったVM(Ubuntu)を再構築しちゃおうと思ったんだけど、できなくて
いろいろやってるうちに、「サービスの停止」を選んでしもうた!(笑)
サービスを停止させた Hyper-V マネージャを復活させる方法について。

Hyper-Vのサービスを停止させてしまうと

こんな画面になっちゃって、仮想マシンが表示されなくなってしまいます。

Hyper-V サービスを復活させるには

PowerShell を「管理者モード」で起動します!

サービスを自動起動に設定します。

PS C:\WINDOWS\system32> sc.exe config vmms start=auto

[SC] ChangeServiceConfig SUCCESS

次に、サービスを開始します。

PS C:\WINDOWS\system32> sc.exe start vmms

SERVICE_NAME: vmms
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 39080
        FLAGS              :

Hyper-V の仮想マシンが復活してくれます


めでたしめでたし。