あるまげどーーーん

某ITベンチャー会社に所属する技術者たちの自習室

VPS上にNextclowd構築(Let's Encryptの証明書自動更新)

きりんです。

以下の記事の残作業を片付けていきます。 まずはLet's Encryptの証明書を自動的に更新する設定を行います。

armageddooon.hatenablog.com

Let's Encryptの証明書自動更新

Let's Encryptの証明書の有効期限は90日間となっており、その期限が切れる前に証明書の更新を行う必要があります。 手動での更新も可能ですが、面倒くさいし忘れる可能性もあるので、定期的に自動実行されるように設定します。

証明書の有効期限の確認

念のため現在の証明書の有効期限を確認してみます。

# certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: (ドメイン名)
    Domains: (ドメイン名)
    Expiry Date: 2019-11-02 04:06:00+00:00 (VALID: 66 days)
    Certificate Path: /etc/letsencrypt/live/(ドメイン名)/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/(ドメイン名)/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

まだまだ有効期限は残っているようです。

更新のテスト

自動更新が正しく行われるか、事前に確認をします。この作業では証明書は更新されません。

# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/(ドメイン名).conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Renewing an existing certificate

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/(ドメイン名)/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/(ドメイン名)/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

問題なさそうです。

更新の自動実行設定

--dry-runオプションを外せばそのまま更新のコマンドになりますので、それをcronに登録します。 証明書の更新後にhttpdの再起動が必要になるので、そのオプションを追加します。

0 3 * * sun /usr/bin/certbot renew --post-hook "systemctl restart httpd"

コマンドの実行間隔については毎日というサイトもあれば月イチというサイトもあるので、間をとって週イチで様子を見ることにします。

(追記)証明書の更新確認

書きかけの記事をしばらく放置してしまっていたのですが、逆にいい感じに時間が経過したので証明書の更新状況を確認してみました。

# certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: (ドメイン名)
    Domains: (ドメイン名)
    Expiry Date: 2020-01-03 17:01:43+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/(ドメイン名)/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/(ドメイン名)/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ちゃんと更新されているようです。

(参考サイト) Linux CentOS7でLet's Encryptを自動更新にする | のるぼるのるの

残りの作業

一気に片付けようと思うとなかなか進まないので、少しずつやっていくことにしました。 残りの作業は以下の通り。

  • DB、データのバックアップ
  • ログローテートの設定
  • セキュリティ設定

VsCodeとPlantUMLでMarkdown+UML

きりんです。

今までMarkdown+PlantUMLでドキュメントを書くために、Boostnoteを使ってました。

armageddooon.hatenablog.com

Boostnoteはインストールが簡単、ドキュメントの保存(先)を意識しなくて良い、と言うメリットがあるのですが、エディタとプレビューのスクロールが同期しない、ファイル単位での取り扱いができないというデメリットも感じていました。

ファイル単位での取り扱いができるとgitでの管理が可能になる、新旧ファイルのdiffが取れる、ドキュメントとソースを一緒に管理できる、といったメリットがあるので何か方法がないかと探していると、会社の同僚がVsCodeとPantUMLでドキュメントを書いていて、非常に快適そうだったのでさっそく真似してみました。

使用するソフト

MarkdownUMLをプレビューするためのVsCodeのExtensionはいくつかあるようですが、ドキュメントを外部に提出する場合などにPDFなどでのエクスポートができたほうが良いと考え、いろいろ試した結果以下の組み合わせに落ち着きました。

VsCode

Atomと比べて圧倒的に動作が軽いので、今はメインのエディタとして使用しています。 機能も豊富でMarkdownのプレビューも標準で可能ですが、UMLの描画はできません。 しかしAtomと同様、拡張性が高いので必要に応じてExtensionをインストールしカスタマイズが可能です。

Markdown Preview Enhanced

VsCodeのExtention。これを使用することでMarkdownのプレビュー上にUMLを描画することが可能になります。 さらにこのExtensionではMarkdownドキュメントをUML込みでHTMLや画像、PDFへエクスポートすることができます。 名前からするとAtomのものと同じExtensionなのでしょうか。

GraphViz

UMLから画像を描画するためのツール。 PlantUML絡みで何かとお世話になります。

Chrome

Markdown Preview EnhancedからPDF等でエクスポートする際にPuppeteer(=Chrome)が必要なのでこれもインストールします。 (自宅ではFirefox使っているのでChromeはインストールされておらず、PDF出力できなくて右往左往してしまいました)

インストール

VsCodeGraphVizChromeはそれぞれダウンロードしてインストールします。

次にVsCodeにExtensionのMarkdown Preview Enhancedをインストールします。

f:id:nkhr22r:20190825213120p:plain

とりあえず以上でMarkdownでのUML描画が可能になります。

使い方

まずはVsCodeを起動し、Markdownを使用してUMLを記述します。

プレビューの表示

プレビューの表示はエディタ上でCtrl+Kを押した後にVを押すか、編集画面上で右クリックしてMarkdown Preview Enhanced: Open Preview to the Sideを選択すると、右ペインにMarkdownのプレビューが表示されます。

f:id:nkhr22r:20190825221852p:plain

f:id:nkhr22r:20190825213126p:plain

問題なくプレビューできました。

PDFエクスポート

プレビュー上で右クリックするとエクスポートのメニューが表示されます。

f:id:nkhr22r:20190825213134p:plain

メニューからChrome (Puppeteer) > PDFを選択すると、元の.mdファイルと同じディレクトリにPDFが出力されます。

f:id:nkhr22r:20190825213142p:plain

とりあえずPDFは生成されるんですが、漢字が微妙に中国語っぽくなっちゃいました。

フォントの指定

想像ですが、プレビューとエクスポートで使用されるデフォルトのフォントが違うのかもしれません。 そこで、Markdown Preview Enhancedのスタイルでフォントを指定します。

まず、Ctrl+Shift+PをクリックしてMarkdown Preview Enhanced: Customize CSSを検索します。

f:id:nkhr22r:20190825213153p:plain

スタイルを記述します。

f:id:nkhr22r:20190825213204p:plain

とりあえず今回はこんな感じにしてみました。

/* Please visit the URL below for more information: */
/*   https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */ 

.markdown-preview.markdown-preview {
  // modify your style here
  // eg: background-color: blue;  

+  * {
+    font-family: Meiryo, sans-serif;
+    overflow: visible;
+  }
+  @media print {
+    font-family: Meiryo, sans-serif;
+   overflow: visible;
+  }
 }

今度はちゃんと日本語っぽいフォントでエクスポートできました。

f:id:nkhr22r:20190825213226p:plain

最後に

VsCodeではエディタとプレビューのスクロールが同期するので、作業がとてもしやすくなりました。 また、プロジェクトのソースと一緒にドキュメントを管理できるので、「あれ、このプロジェクトのドキュメントどれ(どこ)だっけ?」ってことが無くなるかと思います。

一方でBoostnoteもその手軽さから、メモや下書きと言ったとりあえずテキストを書き留めておきたいときに向いていると思うので、用途に応じて使い分けてみたいと思います。

VPS上にNextclowd構築

きりんです。前の投稿からだいぶ空いてしまいました...

自分専用のオンラインストレージ・CalDAVサーバ・CardDAVサーバが欲しくてレンタルサーバーにNextcloudをインストールして利用してきましたが、数年使って動きが悪くなってきたので心機一転VPS上に新しい環境を用意し、最新バージョンのNextcloud(16.0.3)を構築することにしました。

また、個人情報満載なのでhttps運用必須なのですが、今までは有料のサーバ証明書を購入してました。これも環境を変えるついでに無料で使えるLet's Encryptのサーバ証明書を試してみることにしました。

事前準備

VPSにOSをインストールしてsshでアクセスできるようにしておきます。今回はCentOS7のテンプレートを利用しました。

また、ドメインの取得やDNSの設定なども先に済ませておくとよいでしょう。今まではレンタルサーバと一緒にドメイン名も取得していましたが、利用するサーバ(業者)を変えたときにレジストラの移転をしなくて済むよう、別途ドメイン販売会社から購入することにしました。 (DNSサーバをタダで使わせてくれるところだと色々使いまわせて便利です)

設定項目等

インストール前に決めておいた方がいい内容を書き出してみました。ここに書き出したもの以外にも各種パスワードなどを決めてインストール中に入力する必要があります。 環境や好みに合わせて内容は変えてください。

項目 内容
ドメイン 公開するサイトのドメイン名(例:example.com
サイトのURL https://(ドメイン名)
Nextcloudインストール先 /var/nextcloud
Nextcloudデータディレクト /var/nextcloud-data
RDBMS MariaDB
データベース名 nextcloud_db
DBユーザー名 nc_admin

PHPインストール

NextcloudはPHPで動作するため、必要なモジュールとともにインストールします。

 # yum install epel-release
 # yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
 # yum install --enablerepo=remi,remi-php72 php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-mysql php-pecl-zip php-intl php-process php-imagick php-gmp php-curl php-apcu

 # vi /etc/php.ini
 ...
-memory_limit = 128M
+memory_limit = 512M
 ...
-date.timezone = 
+date.timezone = "Asia/Tokyo"
 ...
-;mbstring.language = Japanese
+mbstring.language = Japanese

httpdのインストール

Let's Encryptではhttp経由(ドキュメントルートディレクトリ経由)で証明書を取得するので、まずは外部からWebサーバにアクセスできるようにします。

 # yum install httpd
 # vi /etc/httpd/conf/httpd.conf
 ...
+ServerName (ドメイン名):80
 ...

 # chown -R apache:apache /var/www/html
 # systemctl enable httpd
 # systemctl start httpd

firewalldの設定

httpとhttpssshでアクセスできるようにします。

 # firewall-cmd --get-default-zone
 public

 # firewall-cmd --set-default-zone=drop
 # firewall-cmd --add-service=http --permanent
 # firewall-cmd --add-service=https --permanent
 # firewall-cmd --add-service=ssh --permanent
 # firewall-cmd --reload

Let's Encrypt(certbot)のインストール

certbotをインストールして実行することで、http経由でサーバ証明書が取得できます。

 # yum install certbot python-certbot-apache
 # certbot certonly --webroot -w /var/www/html -d (ドメイン名) -m (メールアドレス) --agree-tos -n

取得したサーバ証明書は以下に保存されます。

種類 保存先
証明書 /etc/letsencrypt/live/(ドメイン名)/cert.pem
秘密鍵 /etc/letsencrypt/live/(ドメイン名)/privkey.pem
中間CA証明書 /etc/letsencrypt/live/(ドメイン名)/chain.pem

MariaDBのインストール

今回はDBにMariaDBを選択しました。

 # yum install mariadb mariadb-server
 # vi /etc/my.cnf.d/server.cnf
 ...
 [mysqld]
+character-set-server = utf8
+innodb_large_prefix = on
+innodb_file_format = barracuda
+innodb_file_per_table = true
 
 # systemctl start mariadb
 # systemctl enable mariadb

インストールが完了したらDBの初期化を行います。

 # mysql_secure_installation

 Enter current password for root (enter for none): y

 Set root password? [Y/n] y
 New password: (ルート権限のパスワード)
 Re-enter new password: (確認のためもう一度入力)

 Remove anonymous users? [Y/n] y

 Disallow root login remotely? [Y/n] y

 Remove test database and access to it? [Y/n] y

 Reload privilege tables now? [Y/n] y

 # mysql -u root -p
 > CREATE DATABASE nextcloud_db;
 > GRANT ALL PRIVILEGES ON nextcloud_db.* TO nc_admin@localhost IDENFIFIED BY '(DBユーザーのパスワード)';
 > FLUSh PRIVILEGES;
 > quit

Nextcloudのインストール

Nextcloudをダウンロードしチェックサムを確認、問題がなければ解凍しディレクトリを移動します。

 # yum install wget bzip2

 # wget https://download.nextcloud.com/server/releases/nextcloud-16.0.3.tar.bz2
 # wget https://download.nextcloud.com/server/releases/nextcloud-16.0.3.tar.bz2.md5
 # wget https://download.nextcloud.com/server/releases/nextcloud-16.0.3.tar.bz2.asc
 # md5sum -c nextcloud-16.0.3.tar.bz2.md5 < nextcloud-16.0.3.tar.bz2
 # gpg --import nextcloud.asc
 # gpg --verify nextcloud-16.0.3.tar.bz2.asc nextcloud-16.0.3.tar.bz2
 # tar -xvjf nextcloud-16.0.3.tar.bz2
 # mv nextcloud /var
 # chown -R apache:apache /var/nextcloud
 # mkdir /var/nextcloud-data
 # chown apache:apache /var/nextcloud-data

httpsでサーバを公開するための設定を行います。

 # vi /etc/httpd/conf.d/nextcloud.conf
+<VirtualHost *:443>
+  ServerName (ドメイン名)
+  DocumentRoot /var/nextcloud/
+  SSLEngine on
+  SSLCertificateFile /etc/letsencrypt/live/(ドメイン名)/cert.pem
+  SSLCertificateKeyFile /etc/letsencrypt/live/(ドメイン名)/privkey.pem
+  SSLCertificateChainFile /etc/letsencrypt/live/(ドメイン名)/chain.pem
+  <Directory /var/nextcloud/>
+    Options +FollowSymLinks -Indexes
+    AllowOverride all
+    Require all granted
+  </Directory>
+</VirtualHost>
 
 # vi /etc/httpd/conf.d/security.conf
+ServerTokens Prod
+Header unset "X-Powerd-By"
+RequestHeader unset Prox
+Header append X-Frame-Options SAMEORIGIN
+Header set X-XSS-Protection "1; mode=block"
+Header set x_Content-Type-Options nosniff
+TraceEnable Off

 # vi /etc/httpd/conf.d/ssl.conf
 ...
 <VirtualHost _default_:443>
 ...
-SSLProtocol all -SSLv2 -SSLv3
-SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA:!RC4
 ...
 </VirtualHost>
 ...
+SSLProtocol all -SSLv2 -SSLv3
+SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA:!RC4
+SSLHonorCipherOrder On
+Header set Strict-Transport-Security "max-age=31536000"

 # cat /dev/null > /etc/httpd/conf.d/autoindex.conf ;
 # cat /dev/null > /etc/httpd/conf.d/welcome.conf ;

ここまで来たらブラウザでhttps://(ドメイン名)を開き、表示された設定画面に必要な情報を入力すれば初期設定が開始され、Nextcloudが利用可能になります。

入力する情報は、

  • 管理者アカウント名
  • 管理者アカウントパスワード
  • Nextcloudのデータディレクトリ(/var/nextclod-data)
  • 利用するDBの選択(MySQL/MariaDB
  • DBユーザー名(nc_admin)
  • DBユーザーパスワード
  • データベース名(nextcloud_db)
  • ホスト名、ポート番号(localhost:3306)

となります。

残作業

ここまでの作業でNextcloudを利用することができるようになりますが、以下の設定を追加で行う予定です。

  • 証明書の自動チェック・取得
  • DB、データのバックアップ
  • ログローテートの設定
  • セキュリティ設定

それから、Header append X-Frame-Options SAMEORIGINの設定が有効になってない気がするので、後で見直します。

初めてのVue.js

初めてのVue.js

majirouです。社内でVue.jsを広めるために記事を投下します。

  • jQuery!と共に、最近のフロントエンドJSフレームワークに慣れ親しむ記事です。
  • 本稿では、Vue(ビュー)を用いたページ作りを記述します。
    ※ すいませんが、majirouは Vueしか触っていません。
  • 歴史とか、技術的な背景はいったんすっとばし、「慣れる」に重きを置きます。

フロントエンドJSフレームワーク御三家

  • Angular
  • React
  • Vue

この3形体…色見や特色から、ヒトカゲ・ゼニガメ・フシギダネって話もありますね…。

なんとなく、親しみがわいたと思いますので、 今回は「フシギダネ」もとい「Vue.js!君に決めた!!」

公式の説明は以下参照ですが、感覚的にVueがどんなものかを理解してから読んだ方が良いと思います。 ※ Vueは公式ドキュメントに日本語が充実してるから~とか言われますが、初学者には不慣れな言葉が飛び交うためオススメしません。

はじめにVue.js とは? https://jp.vuejs.org/v2/guide/index.html

インストール

CDNで簡単に扱うことにします。

<html>
<head>
<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
</body>
</html>

以上です

Hello Vue!

VueはJavaScriptなので、scriptタグで呼び出していきます。 ポイントは、 * vueを適用させるトップDOM要素に任意のidをつける * そのidに対して、vueをインスタンス化する * データの呼び出しは {{データ名}}で行う

<html>
<head>
<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">
  {{ message }}
</div>

</body>
<script>
var app = new Vue({
  el: '#app', // vueを適用させるトップDOM要素のidを指定します
  data: { // #app配下で呼び出すデータなどを定義します。
    message: 'Hello Vue!'
  }
})
</script>
</html>

このHTMLファイルを開くと下図のようになります。 f:id:majirou:20181217140427p:plain

バインディング

jQueryより楽!と最初に思ったのがこの機能でした。 例として、inputタグの値を処理していくスクリプトを組み込んでいきます。

<html>
<head>
<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

<div id="app">
  {{ message }}
<br>
  <input v-model="message">
</div>

</body>
<script>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})
</script>
</html>

以下のような画面になり、入力フォーム内にも{{message}}の内容が表示されました。

f:id:majirou:20181217140709p:plain

この入力フォームに「こんにちはビュー!」と入力してみます。

f:id:majirou:20181217140726p:plain

入力内容に連動して、messageが書き換えられました。

jQueryで考える

仮にこの操作をjQueryで行うとどうでしょうか。 (だいぶ久しぶりにjQueryを書いたのでもっと楽な書き方があるかもしれませんが…)

<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
</head>
<body>
<div id="app">
  <span></span><br>
  <input>
</div>

</body>
<script>
$(document).ready( function(){
  var message = 'Hello Vue!' ;
  
  $("#app input").on("change", function( event ){
    message = event.target.value ;
    $("#app span").text( message ) ;
  } ) ;
  
  $("#app span").text( message ) ;
  $("#app input").val( message ) ;
  
} ) ;
</script>
</html>

実際やろうとすると結構手間です。

  • 都度都度どこそこのDOM要素に対して何をするという記述
  • 常にDOMを意識する必要がある
  • デザイン変更で順番やID名、クラス名が変わるとロジック部までに影響する可能性あり。

もう私はこの記述に戻ることはできません。 これだけでも、jQueryの面倒くささが、大分Vueで軽減されることが実感できると思います。

まとめ

  • Vueをとりあえず始めるならCDN
  • 式日本語ドキュメントが充実とあるが、それは慣れてる人向け
  • jQueryで時が止まった人もVueからなら時が流れだすかも…(私は流れ始めました)

CSVをExcelで開いたときに数値の先頭の"0"を表示させるには

きりんです。

プログラムでデータをCSVに出力、それをExcelで開くことって結構あると思いますが、「先頭が"0"の数字列は、Excelで開くと先頭の"0”が表示されない」って問題に前から悩まされていました。

社内で使用するプログラムやデータであればExcelの「外部データの取り込み」で列の形式を「文字列」にして読み込んでくれ、で済ませてしまうところですが、今回はお客様からご要望なので何とかするしかありません。

値をシングルクォートやダブルクォートで括ってみましたが、やはりダメ。 majirou君の記事を参考に、Excelで出力するしかない?

PHP-XLSXWriterの導入とはじめの一歩 - あるまげどーーーん

でも、お客様の使用しているレンタルサーバー上で動作するかどうか確認している時間もないし...。 半ば諦めつつネットでいろいろ検索したところ、以下のページに行き当たりました。

www.webimpact.co.jp

通常のCSVファイルは以下の様な形式ですね?

地区名,市外局番
東京,03
大阪,06

これを読み込んでも、Excelでは「03」は【数値】として扱ってしまい「3」になります。
これが0が消える原因です。
一方で、Excelでは【数値】ではなく【文字列】なら先頭の0が消えること無く扱えます。
そこで、次のようにCSVファイルを作ってみましょう。

地区名,市外局番
東京,=”03″
大阪,=”06″

=で始まる項目はExcelの方言で【数式】を表します。

CSVに記述された数式はExcelで開いた際にちゃんと解釈されるんですね。CSVデータをExcelで開くと、どんなデータであれテキストデータとして解釈される(数式、関数は実行されない)と思い込んでいました。

追加情報

これにて一件落着なのですが、他人の記事を紹介しただけでは何の学習にもつながらないので、ちょっとだけ追加で実験してみました。

使用したExcelは2016になります。

実験1

まず、出力したデータをExcelで取り込み、そこで集計等を行うとどうなるか試してみました。

f:id:nkhr22r:20181210111136p:plain

セルA1とA2がCSVの出力データです。="001"="002"ですね。ちゃんと先頭に0が表示されています。

CSVファイルをダブルクリックしてExcelで開き、そこに集計等を追加していきます。 A3で=SUM(A1:A2)、A4で=A1+A2、A5で=A1&A2の演算を行ってみました。

  • A3のSUM関数は引数に数値しかとらない、あるいは数値以外は無視する(あるいは0として扱う)ため、合計が0となる
  • 演算子を使用した場合、セルの値に応じて書式(型)が変換される
    • A4の数値を対象とした演算子(+)の場合、セルの値が計算可能な内容なら数値型に変換し計算が行われる
    • A5の文字列を対象とした演算子(&)の場合は文字列型に変換し処理が行われる

元データがどんな形式であれExcel上で開いているので、当然ですがExcel本来の挙動となります。

実験2

次に、CSV生成時点で上記の数式・関数を出力し、それをExcelで開いたときにどうなるかを試してみました。

こちらがCSVデータ。

="001"
="002"
=SUM(A1:A2)
=A1+A2
=A1&A2

それをExcelで開いた結果。

f:id:nkhr22r:20181210111920p:plain

実験1と同じ結果となりました。 CSVに数式や関数を書いても、それをExcelで開けばちゃんと動くんですね。

実験3

これは確認するまでもありませんが、実験1、2においてExcelで開いたCSVファイルを、Excel上でそのままCSVで保存したらどうなるかを確認しました。

保存前

="001"
="002"
=SUM(A1:A2)
=A1+A2
=A1&A2

保存後

001
002
0
3
001002

Excel上で関数や演算が実行された結果のみがCSVに出力されました。

以上、CSVに関する小ネタでした。

BoostnoteとMarkdownでUML

きりんです。

Markdownでドキュメントを書きたい、できれば図表もテキストベースで書きたい、という事でMarkdownUMLの編集環境を模索してきました。 そんな中、最近知った「Boostnote」の使い勝手が良かったので、今まで試した環境と合わせてメモを残しておきたいと思います。

今まで試したもの

Atomエディタ + markdown-preview-enhanced

数年前に試したこの組み合わせ、プラグインのほかにPCにGraphvizのインストールも必要だったかもしれません。Atomエディタが重く感じられたので、だんだん使わなくなりました。

Nextclowd + Markdown Editorアプリ

サーバーにNextcloudをインストール、そこにMarkdown Editorアプリを追加することでブラウザ上でMarkdownUMLが書けるようになります。 Nextcloudは編集履歴が保存されるので簡単なバージョン管理もできます。難点としてはインストール先のレンタルサーバーが非力なせいかNextcloud自体の動きが時々怪しい事です。

Crowi + PlantUML

Crowiは会社のmajirou君が社内の情報共有のために用意してくれたサーバーで、Nextcloud同様ブラウザ上でMarkdownの編集を行います。別途用意したPlantUMLにUML図の画像を描画させそれをCrowi上(というかブラウザ上)に表示する、といった感じだったと思います。こちらもバージョン管理がされるので、どこを変更したか一目瞭然で使いやすいです。

Boostnote

Boostnote | Boost Happiness, Productivity, and Creativity.

上記環境や他のMarkdownエディタと比べた時のBoostnoteの(私にとっての)優位点は以下になります。

環境構築が簡単

やはりサーバーの設定などが必要になるとハードルがぐっと上がります。その点Boostnoteはダウンロードしてインストールすればすぐに使えるので導入がとても簡単です。

早い・軽い

Boostnoteと同様にローカルにインストールするAtomエディタと比較すると、起動も動作も早く軽く、最近よくフリーズする会社のPCでも快適に動作します。また、サーバーにインストールした環境と違いログイン不要ですぐに使えます。

UMLが書ける

UMLが書けるMarkdownエディタが少ない中、Boostnoteはmermaid.jsでもPlantUMLでもどちらの形式でもUMLが書けます。

イマイチなところ

一番下の行を編集中にその行が画面の外にはみ出してしまうことがあり、編集しづらくて困ることがあります。また、オンラインでの同期や編集履歴(バージョン管理)の機能はないので、別途自分で工夫する必要があります。いずれも致命的なデメリットではありませんが、ここが解消されるとさらに使い勝手がよくなると思います。

記述例

Markdown、PlantUMLの記述例です。

チェックリスト

f:id:nkhr22r:20181206235120p:plain

- [x] 予算申請
- [x] ハードウェア購入
- [ ] OSインストール
- [ ] 開発作業
- [ ] テスト
- [ ] 公開
シーケンス図

f:id:nkhr22r:20181206230816p:plain

@startuml
autonumber
skinparam {
  defaultFontName Migu 1P
  activityFontSize 14
}

actor ユーザー
participant Webアプリ
box "外部システム"
    participant WebAPI
    participant DB
end box

activate ユーザー
ユーザー->Webアプリ:リクエスト
activate Webアプリ
Webアプリ->WebAPI:リクエスト
activate WebAPI
WebAPI->DB:検索
activate DB
DB-->WebAPI:結果
deactivate DB
WebAPI-->Webアプリ:JSONデータ
deactivate WebAPI
Webアプリ-->ユーザー:HTMLデータ
deactivate Webアプリ
note over ユーザー:画面表示
deactivate ユーザー
@enduml
ガントチャート

f:id:nkhr22r:20181209215847p:plain

@startuml
project starts the 2018/11/19
saturday are closed
sunday are closed

[機能A実装] starts at 2018/11/19 and ends at 2018/11/23
[機能B実装] starts at 2018/11/22 and ends at 2018/11/28
[機能C実装] lasts 3 days
[機能A実装] -> [機能C実装]
[機能B実装] -> [機能C実装]
[統合テスト] happens at [機能C実装]'s end
@enduml
ワイヤーフレーム

f:id:nkhr22r:20181206234628p:plain

@startuml
salt
{+
ログイン
会員ID|"abc          "
パスワード|"********     "
[    送信    ]|[   リセット   ]
}
@enduml
その他

このほかにもPlantUMLではユースケース図やクラス図などの記述も可能です。詳しくは本家サイトをご参照ください。

Open-source tool that uses simple textual descriptions to draw beautiful UML diagrams.

業務での活用方法(模索中)

アイディアを練ってる段階や、下書きレベルではBoostnoteでサクサク文書を作成していきます。

作成した文書を社内で共有したい場合はBoostnoteからPDFで印刷してメール添付、記述形式に比較的互換性のあるCrowiに張り付け、あとは印刷して渡す、のどれかになるかと思います。

すでにやり取りがある業者ならPDFで渡しても問題ないと思いますが、お客様にはやはりOffice文書で渡す方が無難なので今は手動で転記しています。

今後の目標としてはRedmineUMLが使えるようにプラグインの導入を検討することと、編集データのオンラインストレージとの同期、バージョン管理方法の検討があげられます。


(2018.12.11追記) 公式のブログにMarkdown記法の記事がありました。ご参考まで。

仕事効率、学習効率を加速させるMarkdown記法の紹介 - Boostnote


(2019.8.26追記) VsCodeでPlantUMLを扱うための環境も作ってみました。 armageddooon.hatenablog.com

PHP-XLSXWriterの導入とはじめの一歩

majirou です!今回が初投稿となります。

社内システムではPHP-Excelでエクセル帳票をゴリゴリ作成していましたが、 ふと気づいてみると、PHP-Excelは非推奨となり、PHP-Spreadsheet なるものがあるとか。

さっそく、導入して試しに4,000行×120カラムぐらいの一覧データを作成してみたところ…

Allowed memory size of 8388608 bytes exhausted

Oh...

PHP-Excelの時も同じようなエラーが出たので、断念してCSVで運用を任せていたので、 「後継機なら、後継機ならメモリーエラーとか吐かずにやってくれるはず!」という思いは打ち砕かれました。

そんな矢先、調べれば出てくるものですね。

PHP_XLSXWriter

READMEには強気なフレーズが!!

Never run out of memory with PHPExcel again.

もう一度、書きます。

Never run out of memory with PHPExcel again.

…すばらしい!

ということで早速導入してみました。

導入

composer でインストールします。

# composer require mk-j/PHP_XLSXWriter

Using version ^0.37.0 for mk-j/php_xlsxwriter
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
Writing lock file
Generating autoload files

実装

公式サンプルをそのまま実施します。

include_once( VENDORPATH . "/mk-j/php_xlsxwriter/xlsxwriter.class.php" ) ;

$header = array(
    'c1-text'=>'string',//text
    'c2-text'=>'@',//text
    'c3-integer'=>'integer',
    'c4-integer'=>'0',
    'c5-price'=>'price',
    'c6-price'=>'#,##0.00',//custom
    'c7-date'=>'date',
    'c8-date'=>'YYYY-MM-DD',
);
$rows = array(
  array('x101',102,103,104,105,106,'2018-01-07','2018-01-08'),
  array('x201',202,203,204,205,206,'2018-02-07','2018-02-08'),
  array('x301',302,303,304,305,306,'2018-03-07','2018-03-08'),
  array('x401',402,403,404,405,406,'2018-04-07','2018-04-08'),
  array('x501',502,503,504,505,506,'2018-05-07','2018-05-08'),
  array('x601',602,603,604,605,606,'2018-06-07','2018-06-08'),
  array('x701',702,703,704,705,706,'2018-07-07','2018-07-08'),
);
$writer = new XLSXWriter();
$writer->writeSheetHeader('Sheet1', $header);
foreach($rows as $row){
    $writer->writeSheetRow('Sheet1', $row);
}

$writer->writeToFile( '/tmp/php_xlsxwriter_test.xlsx' ) ;

ポイント

ヘッダーで予め型を指定して流し込むようです。

$header = array(
    'c1-text'=>'string',//text
    'c2-text'=>'@',//text
    'c3-integer'=>'integer',
    'c4-integer'=>'0',
    'c5-price'=>'price',
    'c6-price'=>'#,##0.00',//custom
    'c7-date'=>'date',
    'c8-date'=>'YYYY-MM-DD',
);

結果

先ほどの4,000行×120カラムぐらいの一覧データですが、 Php-Excelで生成すると1分ほど経過したあたりで、メモリーオーバーとなっていたのですが、 Php-xlsxwriterでは、なんとたったの10秒!!

これで1分待った挙句の「何も生成できませんでした!」という絶望を味わうことのないサービスを社内に還元できそうです。