IT業界のすみっこ暮らし

ふと気がついたときの記録

Python:UnicodeEncodeError対策

日本語の文字列を出力しようとしたらUnicodeEncodeErrorエラー!

print('あははは')
--------
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

原因

調べてみるとPythonエンコード系のエラーはとてもよくあることらしい?

import sys
print (sys.getdefaultencoding()) #utf-8
print(sys.stdout.encoding) #US-ASCII <- これが問題
--------
utf-8
US-ASCII

対策1

qiita.com

import sys
import io

sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

print(sys.stdin.encoding) #UTF-8
print(sys.stdout.encoding) #utf-8
print(sys.stderr.encoding) #UTF-8
--------
UTF-8
utf-8
UTF-8

これで出力は出来たけど、腑に落ちない…ソースも長くなるし

対策2

#!/usr/bin/env PYTHONIOENCODING=UTF-8 python3
# -*- coding: utf-8 -*-
import sys

print(sys.stdin.encoding) #UTF-8
print(sys.stdout.encoding) #UTF-8
print(sys.stderr.encoding) #UTF-8
--------
UTF-8
UTF-8
UTF-8

環境変数を設定して実行

参考

Pythonの日本語処理

PythonのUnicodeEncodeErrorを知る - HDEラボ

taka110w.hateblo.jp

qiita.com

zashikiro.hateblo.jp

20171212ブクマ

Visual Studio 2017で_references.jsがない件 field-notes.sakura.ne.jp

qiita.com

www.kk3marketer.com

mizchi.hatenablog.com

employment.en-japan.com

support.google.com

www.itmedia.co.jp

C#によるWEBサイトへのログイン方法(ベーシック認証、クッキー認証) | 夏研ブログ

qiita.com

yaamaa-memo.hatenablog.com

d.hatena.ne.jp

stackoverflow.com

d.hatena.ne.jp

qiita.com

qiita.com

qiita.com

MvcSiteMapProviderのRouting関連 github.com

広告を非表示にする

SQLとJSONでエスケープ関連メモ

アプリ内でSQL直接実行の際にパラーメータにシングルクォーテーション(')が含まれている場合

stackoverflow.com

  • just replace ' with '' (that's two single quotes, not one double quote) in the string literals. That's it.

以下のようにエスケープしたものをパラメータに入れる

param.Replace("'", "''")

JSONの値の中にダブルクォーテーション(")が含まれている場合

stackoverflow.com

Replace("\"", "\\\"")


当たり前っちゃ当たり前だけどこれらで痛い目にあったのでメモ

SQL Server:データの暗号化・複合化についての諸々メモ

SQL Serverでのデータ暗号化・複合化について検証した内容のまとめ。

0、前提

  • 対象のSQL Serverのバージョンが最新ではない
  • DB単位での認証とか対称キーとかはなるべく使わずに、アプリ単位で暗号化・複合化したい
  • 開発ではEntity Frameworkを使う予定。でもSQL直接実行もOK
  • 暗号化対象は英語、日本語のほか、色んな国の言語が対象になる

1、検証用データベースの作成(localDB)

f:id:papamau:20171206172234p:plain

2、検証用テーブルの作成

f:id:papamau:20171206172350p:plain

USE [TESTDB01]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Table_1](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](500) NULL,
    [NameEnc] [varbinary](2000) NULL
) ON [PRIMARY]

GO
※暗号化したデータのdatatypeはvarbinary。

3、色んな言語でデータを作成

f:id:papamau:20171206172549p:plain

INSERT文には必ずNをつけてnvarcharとして登録する。

INSERT INTO [dbo].[Table_1]([Name]) VALUES (N'Name');
※datatypeをnvarcharで登録しないとCharとして登録され、"???"のように文字化けになる。

4、暗号化する

UPDATE [dbo].[Table_1] SET [NameEnc] = ENCRYPTBYPASSPHRASE('ENCRYPT',Name);

f:id:papamau:20171206173015p:plain

※Nameのdatatypeがnvarcharなので、ENCRYPTBYPASSPHRASEにはnvarcharのまま暗号化される。
文字列を直接入力して暗号化したい場合はN'...'のように設定する
UPDATE [dbo].[Table_1] SET [NameEnc] = ENCRYPTBYPASSPHRASE('ENCRYPT',N'暗号化したい内容');

5、複合化する

SELECT [ID], [Name], [NameEnc]
  , CAST(DECRYPTBYPASSPHRASE('ENCRYPT',NameEnc) AS nvarchar(2000)) AS NameDec
FROM [TESTDB01].[dbo].[Table_1]

f:id:papamau:20171206173245p:plain

※複合化した後、nvarcharに変換する処理を入れる。

以上


補足:MySQLの場合

暗号化
CAST(HEX(AES_ENCRYPT('暗号化するデータ', '暗号化key')) AS CHAR)
複合化
CAST(AES_DECRYPT(UNHEX('複合化するデータ'), '暗号化Key') AS CHAR)

20171205ブクマ

Using Always Encrypted with Entity Framework 6 | SQL Server Security Blog

stackoverflow.com

SQL Server Encryption | Microsoft Docs

stackoverflow.com

stackoverflow.com

dba.stackexchange.com

stackoverflow.com

stackoverflow.com

Cryptographic Functions (Transact-SQL) | Microsoft Docs

ENCRYPTBYPASSPHRASE (TRANSACT-SQL) | Microsoft Docs

広告を非表示にする

Visual Studio 2017&Entity Framework:クラスダイアグラムが表示されない件(edmxファイル)

経緯

Visual Studio 2017でedmxツールを開いてDB内容を更新しようとしたが、そもそもedmxファイルの中身が表示されない。

原因

Visual Studio 2017にデフォルトとして設置されていないので、別途入れる必要があるらしい。

対策

クラスデザイナーをインストールする。

f:id:papamau:20171204182145p:plain

f:id:papamau:20171204182202p:plain

参考

www.helixoft.com

MSSQL LocalDBなど関連ブクマ

qiita.com

blog.clock-up.jp

zero0nine.com

SQL ServerUnicode 文字列定数を処理するときは、すべての Unicode 文字列の前に N プレフィックスを付ける必要がある https://support.microsoft.com/ja-jp/help/239530/you-must-precede-all-unicode-strings-with-a-prefix-n-when-you-deal-wit

nchar and nvarchar (Transact-SQL) nchar and nvarchar (Transact-SQL) | Microsoft Docs

stackoverflow.com

ASP.NET MVC:ユーザー設定による多言語対応について諸々メモ

前提

デフォルト言語は日本語だけど、海外のユーザーは英語で見せたい。

ユーザーの設定情報から使用言語の情報を取得可能。

実装

1、リソースファイルを用意する

  • デフォルト言語:Localize.resx
  • 日本語:Localize.ja-JP.resx
  • 英語:Localize.en-US.resx

※リソースファイルのAccess Modifierは「Public」に設定する。

※リソースの格納場所は任意でok(ex)Lang > Localize.resx とか)

2、ユーザー認証直後の処理に以下の内容を追加

var key = "cultureInfo";
var value = string.Empty;
//cType = DBからユーザーのカルチャー情報を取得
switch (cType)
{
    case 1:
        value = "ja-JP";
        break;
    case 2:
        value = "en-US";
        break;
    default:
        value = "ja-JP";
        break;
}

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(value);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(value);

var cookie = new HttpCookie(key);
cookie.Value = value;
Response.Cookies.Add(cookie);

3、アクションの度にカルチャーの設定を行う

Thread.CurrentThread.CurrentCultureで設定できる範囲は1リクエストのみなので、クッキーなどで保持しておいてアクションが発生するタイミングで設定し直す必要がある。

InternationalizationAttribute.cs
using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.Mvc;

public class InternationalizationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var cultureInfo = "ja-JP";
        HttpCookie cookie = filterContext.RequestContext.HttpContext.Request.Cookies["cultureInfo"];
        if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
        {
            cultureInfo = cookie.Value;
        }

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(cultureInfo);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureInfo);
    }
}

4、多言語化したいところにリソースに設定した値を使う

xx.cshtml
<p>@Localize.GettingStartedTitle</p>

<!--  改行あり -->
<p>@Html.Raw(Localize.AboutAspNetMvcDesc.Replace("\r\n","<br>"))</p>

<!--  string format使用(エラーメッセージなど) [ex)Please enter an amount greater than {0}. ]-->
<p>@string.Format(Localize.ErrorMessage1, "0")</p>

5、リソースのキーから値を取得したい場合

public string GetResourceValueByName(string name)
{
    var value = string.Empty;
    System.Resources.ResourceManager rm = new System.Resources.ResourceManager("base name", this.GetType().Assembly);
    value = rm.GetString(name).ToString();

    if (!string.IsNullOrEmpty(value))
    {
        return value;
    }
    else
    {
        return name;
    }
}

普通に「Localize.ErrorMessage1」みたいに直で設定するのが一番だけど、もしそれが出来ない場合、もしくはリソースから任意のキーで値があるか確認したり取得する必要がある場合はこういう方法もある。

base nameも引数で受け取って、キーから値取得用の汎用的なモジュールにするのもあり

6、用途によってリソースファイルを分けたい場合

分け方によるけど、個人的にはこんな感じで分けてる

[Lang]
 ┗ Localize.resx
 ┗ Localize.ja-JP.resx
 ┗ [Contract] // 契約書の多言語リソース
   ┗ Localize.resx
   ┗ Localize.ja-JP.resx
 ┗ [Invoice] // 請求書の多言語リソース
   ┗ Localize.resx
   ┗ Localize.ja-JP.resx

#例
  • Lang.Localize.Name → 名前
  • Lang.Contract.Localize.Name → 氏名
  • Lang.Invoice.Localize.Name → 利用者名

参考

ASP.NET MVC におけるテキストの多言語対応 再考 : @jsakamoto