結果だけでなく過程も見てください

日々の奮闘を綴る日記です。

Raspberry Pi 3で64GB以上のmicroSDカードを使う方法

Raspberry Pi始めました!
…んが、開始初日から躓いてしまいました。

64GBのmicro SDカードを購入したのですが、Raspberry Pi 3ではFAT32でフォーマットしたカードしか
認識できないようで、32GB以上のカードの場合は有名なSD card Formatter 5.0(現時点の最新版)を使っても、
自動でexFATフォーマットになってしまいRaspberry Piで正しく認識してくれないのでした。

どーするか。

解決法

SD card Formatter 4.0を使ってください。公式からは見つからず、ダウンロードはこのあたりから…。
https://sd-card-formatter.jp.uptodown.com/windows

で、起動したら[フォーマットオプション]から、[論理サイズ調整]をONにしてからフォーマットを
開始してください。これだけでRaspberry PimicroSDカードを正しく認識し、OSのインストールを進めることができます。

余談

この解決法に辿りつくまでBuffalo製のDisk Formatter Ver.2.08やHP USB Disk Storage Format Tool 2.2.3を
試したのですが、前者はmicroSDカードのライトプロテクトを外してくださいといった意味不明なこと
microSDカードにはWriteProtectはない)を言ってきたり、後者はFAT32でフォーマット出来たにも関わらず
Raspberry PiのOSインストール中にエラーが起こったりと、なかなかうまくいきませんでした。

ここは素直にSD Card Formatter 4.0を使用するのが良いようです。

ドラゴンクエストXI用 ドラクエ2最強ステータスのふっかつのじゅもん

明日(もう今日か)発売のドラクエ11では過去(ドラクエ2?)のふっかつのじゅもんが使えるようです!たぶん。

家の押入れを漁ったところ、小学生時代自分が書いたであろうドラクエ2の最強ステータスの
ふっかつのじゅもんがありましたので記念に投稿しておきます(使えなかったらごめんね)

最早ドラクエ少年の通過儀礼となっているふっかつのじゅもん写し間違えがよほど怖かったのか、
同じステータスのじゅもんを3つ残してます…やるな!小学生の頃のオレw

いちおう3つとも載せときます。ステータスは一緒です。

その1

やぼた ちけれ ろれきか
えせみ かさえ ぷねなず
わぽつ はげぼ ぴぴすて
ぼびす めてれ わたじぴ
かばる すもめ はむおぽ い

その2

いねわ わもう うあぴぜ
ざざう りわゆ ほばじち
くひわ じぷの ほぺまら
れぷふ かげり てずかぬ
ぱぽび ごうせ がるわほ ぼふ

その3

えひげ ごるこ さこらは
ねらぶ まやほ ねざぐせ
かはわ ずぽふ めえゆぎ
ざきよ ちぱぜ むうにり
せてし かのゆ おいかぶ ぬぶ

なつかしいですねぇ。
もょもとでおなじみの以下も使えるそうです。
いや〜楽しみだ。

ゆうて いみや おうきむ
こうほ りいゆ うじとり
やまあ きらぺ ぺぺぺぺ
ぺぺぺ ぺぺぺ ぺぺぺぺ
ぺぺぺ ぺぺぺ ぺぺぺぺ ぺぺ

小学校自体のメモはこれ。意外に綺麗ですね。

スキルポイント自動振り分け for DQX オンラインマニュアル (ver 1.4.1)

アプリの概要

スキルポイント自動振り分け for DQXは、
「どのスキルに、何ポイント振り分けたいか」を入力するだけで
各職業のスキルに何ポイント振ればよいかを自動計算してくれるiOSアプリ
です(もちろん無料)。

ダウンロードはこちらから。
https://itunes.apple.com/jp/app/%E3%82%B9%E3%82%AD%E3%83%AB%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E8%87%AA%E5%8B%95%E6%8C%AF%E3%82%8A%E5%88%86%E3%81%91-for-dqx/id1261399639?mt=8

このツールは大きく分けて3つの画面から構成されています。
以下、各画面について説明します。

最新(1.4.1)の更新内容 (2019/07/02にリリース)

  • 公式Web(広場)からスキルポイント自動取得機能において、レベル110まで取得出来るようにしました
  • スキル選択機能にて、スキルポイント190, 200を使用するスキルに対応しました
  • 遊び人のスキルテーブルに誤りがあったため修正しました。

前回(1.4.0)の更新内容(2019/04/30にリリース)

  • 職業「遊び人」および、スキル「あそび」を追加
  • 公式Web(広場)からスキルポイント自動取得機能において、レベル108まで取得出来るようにしました
  • 広場からの情報取得アルゴリズム改善

職業画面

各職業がどれくらいスキルポイントを所持しているかを入力する画面です。
レベルと特訓ポイントで決まります。

スクリーンショットの(1)をタップすることで、この画面が表示されます。

職業の持つスキルポイントの入力

(2)のテキストボックスをタップしてスキルポイントを手動で入力できます。
手動入力が面倒な方は、(4)をタップして自動で読み込むこともできます。

(4)の[公式Webから自動読み込み]をタップすると、アプリ内のブラウザが起動し、公式サイトが表示されます。
ログイン後、つよさ→スキルポイントのページを表示し[読み込む]ボタンを押すことで全職業まとめて自動で読み込むことが可能です。

職業の優先順位を設定する

職業の優先順位を(3)で調整します。
アイコンを長押しして上下にドラッグすることにより優先順位を変えることができます。
一番上にある職業が、最優先にスキルが割り振られるようになっています。
スクリーンショットの例では、武闘家が一番優先され、盗賊が二番目に優先・・・となります。

その他の機能

(5)は入力した数値のセーブとロード行う機能です。
職業の持つスキルポイント、後述するどのスキルに何ポイント降るのか、所持しているマスタースキルポイントのセーブ/ロードが可能です。

(6)はスキル計算を開始し、結果画面に移動します。


スキル画面

どのスキルに、何ポイント振りたいのかを入力する画面です。
所持しているマスタースキルポイントもこの画面で入力します。

スクリーンショットの(1)をタップすることで、この画面が表示されます。

振り分けたいスキルポイントの入力

(2)のテキストボックスをタップすると、ポイント入力用の画面が表示されます。
この画面については「スキル選択画面」の項目をご参照ください。


(4)をタップすることで、所持しているマスタースキルポイントを入力することができます。

優先的に振り分けたいスキルの順番

また職業と同じように、(3)で優先的に振り分けたいスキルの順番を調整できます。
アイコンを長押しして上下にドラッグすることにより優先順位を変えることができます。
一番上にあるスキルが、最も優先するスキルとなります。

パッシブスキル設定機能

「P」と書かれた(7)のボタンを押すと、パッシブスキル設定画面が表示されます。
この画面については「パッシブスキル設定画面」の項目をご参照ください。

その他の機能

(5)(6)は職業画面の(5)(6)とまったく同じ機能です。

スキル選択画面

取りたいスキルのポイントを入力する画面です。
ポイントの数値を直接入力するか、取りたいスキルを選択することで
スキルに対応するポイントを自動で入力することができます。

(1)から直接数値を入力して、スキルポイントを入力できます。
(2)のスキル一覧から取りたいスキルをタップすることで、対応するスキルポイントが自動で入力できます。
(戻る)が書かれているオレンジ色の部分をタップすると、入力キャンセルして元の画面に戻ります。

パッシブスキル設定画面

選んだパッシブスキルを一括して設定する画面です。
主にフルパッシブを設定する際に使用します。

(1)取りたいパッシブスキルにチェックを入れます。デフォルトでフルパッシブが取れるよう、すべての項目にチェックが入っています。
(2)ボタンを押すことで選択したパッシブスキルのポイントが入力されます。
(3)設定せずに前の画面に戻ります。

結果画面

どの職業のどのスキルに何ポイント振ればいいか(結果)を表示する画面です。

また割り当てられなかったスキルもここで表示します。
割り当て不可は、マスタースキルポイントを使わなかった場合と、使った場合それぞれを表示します。

スクリーンショットの魔法使いの例(スワイプすれば全職業がありますが)では、以下の結果になります。

  • 魔法使いのもっているスキルポイント213はすべて使い切っている(残り0で、0/213表記)
  • 魔法使いのときのマスタースキルポイント26はすべて使い切っている(残り0で、0/26表記)
  • 短剣には、この職業ではポイントを振らない(0ポイント)。全職業の割り振り状況としては、180ポイント取りたいところ、180振ることができている。
  • ムチには、この職業ではポイントを振らない(0ポイント)。全職業の割り振り状況としては、スキルを取らないので0/0表記になっている。
  • 両手杖には、この職業ではスキルポイント125ポイント、マスタースキルポイント26を割り当てる

 全職業の割り振り状況としては、180ポイント取りたいところ、150振ることができている(マスタースキルポイント込では150 + 26の数値)

  • 盾には、この職業ではポイントを振らない(0ポイント)。全職業の割り振り状況としては、180ポイント取りたいところ、180振ることができている。
  • まほうには、この職業では88ポイント振る。全職業の割り振り状況としては、88ポイント取りたいところ、88振ることができている。
  • マスタースキルポイントを使わない場合は、両手杖が30ポイント不足していて、割り当てられなかった
  • マスタースキルポイントを使っても、ツメが4ポイント不足していて、割り当てられなかった
注意:マスタースキルポイントの使用有無で表記を分けている理由

マスタースキルポイント込みでスキルの割り振りを考えると、
転職するたびにマスタースキルポイントの調整が必要になる可能性があり、面倒です。
この面倒がイヤな方(自分もそうです)向けに、マスタースキルポイントを使用せずに
割り当てられるかも別途表記しています。

今後の予定

すべて実装するかはわかりませんが、できる限り対応します。

  • アルゴリズムの改善(適宜)
  • 高速化(適宜)
  • バグ修正(適宜)
  • 新職業/新スキル追加(適宜)
  • 結果画面のわかりやすさ改善(適宜)

Private Policy

taiyakisun built the スキルポイント自動振り分け for DQX app as a Free app. This SERVICE is provided by taiyakisun at no cost and is intended for use as is.

This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.

If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.

The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at スキルポイント自動振り分け for DQX unless otherwise defined in this Privacy Policy.

Information Collection and Use

For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information. The information that I request will be retained on your device and is not collected by me in any way.

The app does use third party services that may collect information used to identify you.

Link to privacy policy of third party service providers used by the app

Log Data

I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.

Cookies

Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.

This Service does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.

Service Providers

I may employ third-party companies and individuals due to the following reasons:

To facilitate our Service;
To provide the Service on our behalf;
To perform Service-related services; or
To assist us in analyzing how our Service is used.
I want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.

Security

I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.

Links to Other Sites

This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.

Children’s Privacy

These Services do not address anyone under the age of 13. I do not knowingly collect personally identifiable information from children under 13. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do necessary actions.

Changes to This Privacy Policy

I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.

Contact Us

If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at ichimonji.factory@gmail.com.

This privacy policy page was created at privacypolicytemplate.net and modified/generated by App Privacy Policy Generator

ちょっとしたTCP/IP, UDP/IP通信でいろいろテストしたいときのコードテンプレ(Windows/Linux両方コピペだけでビルド可能!)

はじめに

ノード間でTCP/IPおよびUDP/IP通信が通るかどうかをチェックするツールです。

  • 1つの実行ファイルにサーバー/クライアント両方の機能が入っているので、双方向の確認が可能です。
  • WindowsLinux両方でビルドできるので、プラットフォームを越えてのチェックが可能です。

注意事項はこちらです。

  • 個人的なテスト用に作られたモノです
  • コピって適当に改造して使いましょう
  • エラー処理は無いに等しいです
  • アドレスはIPv4しか使えません
  • 一部機能が未実装です
  • 2時間くらいでとりあえず上げたものです。徐々に修正していきます(これいつもの放置するやつや!)。

ビルド

Windows
  • Visual Studio Community 2015以降で動作確認済みです。
  • 追加のライブラリとして「ws2_32.lib」を追加しといてください。(プロジェクトのプロパティ→リンカー→入力→追加の依存ファイル)
  • 「WIN32」というマクロを定義しておいてください。(プロジェクトのプロパティ→C/C++プリプロセッサプリプロセッサの定義) ※昔はデフォルトで定義されてたのに、最近のはないんですね…
  • SDLが有効な場合は、無効にしてください。(プロジェクトのプロパティ→C/C++→全般→SDLチェックを「いいえ」にする)

あとは普通にビルド一発です。

Linux

gcc 4.8.5, 8.3.1(Redhat系), 9.3.0(Ubuntu)で動作確認済みです。
まぁ何でも適当で大丈夫だと思います。以下を実行してください。

gcc ./main.cpp -o main -lstdc++ -lpthread

以下のようなエラーが出た場合は、追加パッケージをインストールしてください。

  • Redhat系の場合は「gcc-c++」パッケージ (yum install gcc-c++)
  • Ubuntuの場合は「g++」パッケージ (sudo apt-get install g++) ※gccとg++のバージョンは合わせる必要があるようです。
gcc: error trying to exec 'cc1plus': execvp: そのようなファイルやディレクトリはありません

使用方法

サーバー
実行ファイル server <プロトコル種別> <リッスンするIPアドレス> <リッスンするポート>

■例
./main server tcp 192.168.1.10 19876
クライアント
実行ファイル client <プロトコル種別> <接続先IPアドレス> <接続先ポート> <接続元IPアドレス> <接続元ポート> <サーバーに送るメッセージ>

■例
./main client tcp 192.168.1.10 19876 0 0 ahanufun

※接続元のIPアドレスやポート番号に0を指定すると、OS(プロトコルスタック)が自動で選んだIPアドレス/ポート番号が選ばれます。

ソースコード (ここをコピペすべし!)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

#ifdef WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <process.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#endif


#ifdef WIN32
#define HERROR                          WSAGetLastError()
#define SAFE_SOCK_CLOSE(sock)           if((sock) != INVALID_SOCKET){ closesocket((sock)); (sock)=INVALID_SOCKET; }
#define SOCK_TYPE                       SOCKET
#define SOCKLEN_TYPE                    int
#define SLEEP_SEC(sec)                  Sleep((sec) * 1000)
#define SET_SOCKADDR_IPV4(addr, value)  (addr).sin_addr.S_un.S_addr = (value)
#else
#define HERROR                          h_errno
#define INVALID_SOCKET                  (-1)
#define SAFE_SOCK_CLOSE(sock)           if((sock) != INVALID_SOCKET){ close((sock)); (sock)=INVALID_SOCKET; }
#define SOCK_TYPE                       int
#define SOCKLEN_TYPE                    socklen_t
#define SLEEP_SEC(sec)                  sleep((sec))
#define SET_SOCKADDR_IPV4(addr, value)  (addr).sin_addr.s_addr = (value)
#endif

#define SAFE_DELETE(p)  if(p){ delete(p); (p)=NULL; }


const char* errno_str()
{
    switch (errno)
    {
    case 1:   return "EPERM";
    case 2:   return "ENOENT";
    case 3:   return "ESRCH";
    case 4:   return "EINTR";
    case 5:   return "EIO";
    case 6:   return "ENXIO";
    case 7:   return "E2BIG";
    case 8:   return "ENOEXEC";
    case 9:   return "EBADF";
    case 10:  return "ECHILD";
    case 11:  return "EAGAIN or EWOULDBLOCK";
    case 12:  return "ENOMEM";
    case 13:  return "EACCES";
    case 14:  return "EFAULT";
    case 15:  return "ENOTBLK";
    case 16:  return "EBUSY";
    case 17:  return "EEXIST";
    case 18:  return "EXDEV";
    case 19:  return "ENODEV";
    case 20:  return "ENOTDIR";
    case 21:  return "EISDIR";
    case 22:  return "EINVAL";
    case 23:  return "ENFILE";
    case 24:  return "EMFILE";
    case 25:  return "ENOTTY";
    case 26:  return "ETXTBSY";
    case 27:  return "EFBIG";
    case 28:  return "ENOSPC";
    case 29:  return "ESPIPE";
    case 30:  return "EROFS";
    case 31:  return "EMLINK";
    case 32:  return "EPIPE";
    case 33:  return "EDOM";
    case 34:  return "ERANGE";
    case 35:  return "EDEADLK or EDEADLOCK";
    case 36:  return "ENAMETOOLONG";
    case 37:  return "ENOLCK";
    case 38:  return "ENOSYS";
    case 39:  return "ENOTEMPTY";
    case 40:  return "ELOOP";
    case 42:  return "ENOMSG";
    case 43:  return "EIDRM";
    case 44:  return "ECHRNG";
    case 45:  return "EL2NSYNC";
    case 46:  return "EL3HLT";
    case 47:  return "EL3RST";
    case 49:  return "EUNATCH";
    case 51:  return "EL2HLT";
    case 52:  return "EBADE";
    case 53:  return "EBADR";
    case 54:  return "EXFULL";
    case 56:  return "EBADRQC";
    case 57:  return "EBADSLT";
    case 60:  return "ENOSTR";
    case 61:  return "ENODATA";
    case 62:  return "ETIME";
    case 63:  return "ENOSR";
    case 64:  return "ENONET";
    case 65:  return "ENOPKG";
    case 66:  return "EREMOTE";
    case 67:  return "ENOLINK";
    case 70:  return "ECOMM";
    case 71:  return "EPROTO";
    case 72:  return "EMULTIHOP";
    case 74:  return "EBADMSG";
    case 75:  return "EOVERFLOW";
    case 76:  return "ENOTUNIQ";
    case 77:  return "EBADFD";
    case 78:  return "EREMCHG";
    case 79:  return "ELIBACC";
    case 80:  return "ELIBBAD";
    case 81:  return "ELIBSCN";
    case 82:  return "ELIBMAX";
    case 83:  return "ELIBEXEC";
    case 84:  return "EILSEQ";
    case 85:  return "ERESTART";
    case 86:  return "ESTRPIPE";
    case 87:  return "EUSERS";
    case 88:  return "ENOTSOCK";
    case 89:  return "EDESTADDRREQ";
    case 90:  return "EMSGSIZE";
    case 91:  return "EPROTOTYPE";
    case 92:  return "ENOPROTOOPT";
    case 93:  return "EPROTONOSUPPORT";
    case 94:  return "ESOCKTNOSUPPORT";
    case 95:  return "ENOTSUP or EOPNOTSUPP";
    case 96:  return "EPFNOSUPPORT";
    case 97:  return "EAFNOSUPPORT";
    case 98:  return "EADDRINUSE";
    case 99:  return "EADDRNOTAVAIL";
    case 100: return "ENETDOWN";
    case 101: return "ENETUNREACH";
    case 102: return "ENETRESET";
    case 103: return "ECONNABORTED";
    case 104: return "ECONNRESET";
    case 105: return "ENOBUFS";
    case 106: return "EISCONN";
    case 107: return "ENOTCONN";
    case 108: return "ESHUTDOWN";
    case 110: return "ETIMEDOUT";
    case 111: return "ECONNREFUSED";
    case 112: return "EHOSTDOWN";
    case 113: return "EHOSTUNREACH";
    case 114: return "EALREADY";
    case 115: return "EINPROGRESS";
    case 116: return "ESTALE";
    case 117: return "EUCLEAN";
    case 120: return "EISNAM";
    case 121: return "EREMOTEIO";
    case 122: return "EDQUOT";
    case 123: return "ENOMEDIUM";
    case 124: return "EMEDIUMTYPE";
    case 125: return "ECANCELED";
    case 126: return "ENOKEY";
    case 127: return "EKEYEXPIRED";
    case 128: return "EKEYREVOKED";
    case 129: return "EKEYREJECTED";
    default:  return "UNKNOWN";
    }
}


const char* getLocalTimeStr(time_t curTime, char* pszResultTime)
{
    struct tm* pt = localtime(&curTime);

    sprintf(pszResultTime, "%02d/%02d/%02d %02d:%02d:%02d", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec);

    return pszResultTime;
}


class NetworkInfo
{
public:

    ~NetworkInfo()
    {

#ifdef WIN32
        if (bWSASetup)
        {
            WSACleanup();
            bWSASetup = false;
        }
#endif

        SAFE_SOCK_CLOSE(sock0);
    }

#ifdef WIN32
    WSADATA             wsaData;
    bool                bWSASetup;
#endif

    /* listening socket */
    SOCK_TYPE           sock0;

    /* サーバーならリッスンするアドレス情報     */
    /* クライアントなら送信先アドレス情報とする */
    struct sockaddr_in  addr;

    /* オプション。クライアントのときだけ使われる。クライアント側アドレスとポート。 */
    struct sockaddr_in  client_addr_forsend;


    NetworkInfo() :
#ifdef WIN32
        wsaData(),
        bWSASetup(false),
#endif
        sock0(INVALID_SOCKET),
        addr(),
        client_addr_forsend()
    {
    }

};


/* サーバーかクライアントの種別列挙子 */
enum NodeType
{
    eNodeTypeUnknown = 0,
    eServer,
    eClient
};

static const char* NODE_SERVER = "server";
static const char* NODE_CLIENT = "client";

/* TCPかUDPの種別列挙子 */
enum ProtocolType
{
    eProtocolTypeUnknown = 0,
    eProtocolTCP,
    eProtocolUDP
};

static const char* PROTOCOL_TCP = "tcp";
static const char* PROTOCOL_UDP = "udp";


/* 受信関数で必要な情報 */
struct RecvInfo_t
{
    /* 受信処理で使用するソケット */
    SOCK_TYPE  recvSock_;

    RecvInfo_t(SOCK_TYPE recvSock) :
        recvSock_(recvSock)
    {
    }
};


/* 受信関数。TCPの場合だけ使われます。 */
#ifdef WIN32
unsigned __stdcall recvThread(void *p)
#else
void* recvThread(void *p)
#endif
{
    RecvInfo_t* pRecvInfo = (RecvInfo_t *)p;

    char  inbuf[2048];   /* 受信バッファ     */
    char  atimeWk[64];   /* 時刻表示ワーク用 */

    memset(inbuf, 0, sizeof(inbuf));
    memset(atimeWk, 0, sizeof(atimeWk));

    /* 情報を取得してメモリ解放しておく */
    SOCK_TYPE sock = pRecvInfo->recvSock_;
    SAFE_DELETE(pRecvInfo);

    /* 受信処理。同期とする。出力結果が混ざって表示されるが気にしない */
    recv(sock, inbuf, sizeof(inbuf), 0);
    printf("%s Received Message:%s\n", getLocalTimeStr(time(NULL), atimeWk), inbuf);

    SAFE_SOCK_CLOSE(sock);

#ifdef WIN32
    return 0;
#else
    pthread_exit(NULL);
#endif
}


void printUsage()
{
    printf("Usage:\n");
    printf("   server {tcp|udp} listening_addr listening_port\n");
    printf("   or\n");
    printf("   client {tcp|udp} dest_addr dest_port src_addr src_port message\n");
    printf("\n");
    printf("Example:\n");
    printf("   1. server tcp 192.168.1.5 12345\n");
    printf("      client tcp 192.168.1.5 12345 0 0 sample_to_12345\n");
    printf("\n");
    printf("   2. server udp 192.168.1.5 12345\n");
    printf("      client udp 192.168.1.5 12345 192.168.1.2 5000 sample_from_5000_to_12345\n");
}


/*
* me.exe <NodeType> <ProtocolType> <listening addr> <listening port>
*      or
* me.exe <NodeType> <ProtocolType> <dest addr> <dest port> <src addr> <src port> <msg>
*
* <NodeType> "server" or "client"
* <ProtocolType> "tcp" or "udp"
*
* Only IPv4.
*/
int main(int argc, char* argv[])
{
    if (argc <= 1)
    {
        fprintf(stderr, "Error: Bad args num.\n");
        printUsage();
        return 1;
    }

    NodeType eNodeType = eNodeTypeUnknown;

    if (strcmp(argv[1], NODE_SERVER) == 0)
    {
        eNodeType = eServer;

        if (argc != 5)
        {
            fprintf(stderr, "Error: Bad args num(Server)(%d).\n", argc);
            printUsage();
            return 1;
        }
    }
    else if (strcmp(argv[1], NODE_CLIENT) == 0)
    {
        eNodeType = eClient;

        if (argc != 8)
        {
            fprintf(stderr, "Error: Bad args num(Client)(%d).\n", argc);
            printUsage();
            return 1;
        }
    }
    else
    {
        fprintf(stderr, "Error: Input correct NodeType(server or client).\n");
        printUsage();
        return 2;
    }


    ProtocolType eProtocolType = eProtocolTypeUnknown;

    if (strcmp(argv[2], PROTOCOL_TCP) == 0)
    {
        eProtocolType = eProtocolTCP;
    }
    else if (strcmp(argv[2], PROTOCOL_UDP) == 0)
    {
        eProtocolType = eProtocolUDP;
    }
    else
    {
        fprintf(stderr, "Error: Input correct ProtocolType(tcp or udp).\n");
        printUsage();
        return 2;
    }


    int          nFuncRet = 0;   /* Function return code */
    NetworkInfo  netInfo;
    char         atimeWk[64];

    memset(atimeWk, 0, sizeof(atimeWk));


#ifdef WIN32
    nFuncRet = WSAStartup(MAKEWORD(2, 0), &(netInfo.wsaData));
    netInfo.bWSASetup = true;
    if (nFuncRet != 0)
    {
        fprintf(stderr, "%s WSAStartup error(%d)(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), nFuncRet, HERROR, errno, errno_str());
        return 3;
    }
#endif


    if (eNodeType == eServer)
    {
        /* argv */
        /* [1]:ノード種別       */
        /* [2]:プロトコル種別   */
        /* [3]:リッスンアドレス */
        /* [4]:リッスンポート   */

        const char* pszAddr     = argv[3];
        const char* pszPortNum  = argv[4];


        /* リッスンソケットの作成 */
        netInfo.sock0 = socket(AF_INET, (eProtocolType == eProtocolTCP) ? SOCK_STREAM : SOCK_DGRAM, 0);
        if (netInfo.sock0 == INVALID_SOCKET)
        {
            fprintf(stderr, "%s listen socket error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());
            return 4;
        }

        /* バインドリッスンするアドレスとポート設定 */
        netInfo.addr.sin_family = AF_INET;
        netInfo.addr.sin_port = htons(atoi(pszPortNum));    /* リッスンポート TODO:引数を信じろ! */
        SET_SOCKADDR_IPV4(netInfo.addr, inet_addr(pszAddr));  /* バインドアドレス TODO:引数を信じろ! */


        /* サーバーの場合はポート再利用可能としておく */
        {
            int nYes = 1;
            setsockopt(netInfo.sock0, SOL_SOCKET, SO_REUSEADDR, (const char *)&nYes, sizeof(nYes));
        }


        nFuncRet = bind(netInfo.sock0, (struct sockaddr *)&(netInfo.addr), sizeof(netInfo.addr));
        if (nFuncRet == -1)
        {
            fprintf(stderr, "%s bind(recv) error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());
            return 8;
        }


        /** TCPの場合だけリッスンする */
        if (eProtocolType == eProtocolTCP)
        {
            nFuncRet = listen(netInfo.sock0, 5);  /* backlogは5 */
            if (nFuncRet == -1)
            {
                fprintf(stderr, "%s listen error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());
                return 9;
            }
        }


        /* recv loop */
        while (1)
        {
            struct sockaddr_in  client = { 0 };
            SOCKLEN_TYPE        nClientLen = sizeof(client);
            
            if (eProtocolType == eProtocolTCP)
            {
                int sock = INVALID_SOCKET;

                /** TCPの場合だけacceptで待ち受けする */
                sock = accept(netInfo.sock0, (struct sockaddr *)&client, &nClientLen);
                if (sock == INVALID_SOCKET)
                {
                    fprintf(stderr, "%s accept error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());
                    continue;
                }

                /* TCPの場合、acceptと受信処理は分離したいため、受信用スレッドを立ち上げる */
                RecvInfo_t* pRecvInfo = NULL;
                try
                {
                    pRecvInfo = new RecvInfo_t(sock);
                }
                catch (...)
                {
                    /* bad memory alloc */
                    SAFE_SOCK_CLOSE(sock);
                    continue;
                }

#ifdef WIN32
                unsigned int thID = 0;

                HANDLE hThread = (HANDLE)_beginthreadex(NULL,
                    0,
                    recvThread,
                    pRecvInfo,
                    0  /*CREATE_SUSPENDED*/,
                    &thID);
                if (hThread == 0)
                {
                    fprintf(stderr, "%s _beginthreadex error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());

                    SAFE_SOCK_CLOSE(sock);
                    continue;
                }

                /* Windowsではデフォルトでpthread_detach相当の設定になっている(たぶん) */
#else
                pthread_t th = 0;

                nFuncRet = pthread_create(&th, NULL, recvThread, (void *)pRecvInfo);
                if (nFuncRet != 0)
                {
                    fprintf(stderr, "%s pthread_create error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());

                    SAFE_SOCK_CLOSE(sock);
                    continue;
                }

                (void)pthread_detach(th);
#endif
            }
            else
            {
                /** UDPの場合、acceptがないため、recvでブロッキングするような処理にする */
                char  inbuf[2048];   /* 受信バッファ     */
                char  atimeWk[64];   /* 時刻表示ワーク用 */

                memset(inbuf, 0, sizeof(inbuf));
                memset(atimeWk, 0, sizeof(atimeWk));

                /* 受信処理。同期とする。出力結果が混ざって表示されるが気にしない */
                recv(netInfo.sock0, inbuf, sizeof(inbuf), 0);
                printf("%s Received Message:%s\n", getLocalTimeStr(time(NULL), atimeWk), inbuf);
            }
        }

    }
    else
    {
        /* argv */
        /* [1]:ノード種別       */
        /* [2]:プロトコル種別   */
        /* [3]:接続先アドレス   */
        /* [4]:接続先ポート     */
        /* [5]:接続元アドレス   */
        /* [6]:接続元ポート     */
        /* [7]:メッセージ       */

        const char* pszDestAddr = argv[3];
        const char* pszDestPortNum = argv[4];
        const char* pszSrcAddr = argv[5];
        const char* pszSrcPortNum = argv[6];
        const char* pszMessage = argv[7];


        int   sock = 0;
        char  sendmsg[256];

        memset(sendmsg, 0, sizeof(sendmsg));

        /* 接続先アドレス情報 */
        netInfo.addr.sin_family = AF_INET;
        netInfo.addr.sin_port = htons(atoi(pszDestPortNum));       /* TODO:引数を信じて! */
        SET_SOCKADDR_IPV4(netInfo.addr, inet_addr(pszDestAddr));   /* TODO:引数を信じて! */


        /* 接続元アドレス情報 */
        netInfo.client_addr_forsend.sin_family = AF_INET;
        netInfo.client_addr_forsend.sin_port = htons(atoi(pszSrcPortNum));    /* TODO:引数を信じて! */
        SET_SOCKADDR_IPV4(netInfo.client_addr_forsend, inet_addr(pszSrcAddr));  /* TODO:引数を信じて! */


        sock = socket(AF_INET, (eProtocolType == eProtocolTCP) ? SOCK_STREAM : SOCK_DGRAM, 0);
        if (sock == INVALID_SOCKET)
        {
            fprintf(stderr, "%s socket(send) h_errno:%d errno:%d(%s)\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());

            return 10;
        }


        /* TODO:将来的にクライアントの場合のポート再利用可能は設定するかしないか設定できるようにしたい */
        {
            int nYes = 1;
            setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&nYes, sizeof(nYes));
        }


        /* TODO:将来的に接続元アドレスを必ずbindするかどうかはオプション化したい */
        nFuncRet = bind(sock, (struct sockaddr *)&(netInfo.client_addr_forsend), sizeof(netInfo.client_addr_forsend));
        if (nFuncRet == -1)
        {
            fprintf(stderr, "%s bind(send) error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());

            return 11;
        }


        memset(sendmsg, 0, sizeof(sendmsg));
        strncpy(sendmsg, pszMessage, sizeof(sendmsg) - 1);


        if (eProtocolType == eProtocolTCP)
        {
            /** TCPの場合だけ、コネクションを確立させる */
            nFuncRet = connect(sock, (struct sockaddr *)&(netInfo.addr), sizeof(netInfo.addr));
            if (nFuncRet == -1)
            {
                fprintf(stderr, "%s connect error(h_errno:%d)(errno:%d(%s))\n", getLocalTimeStr(time(NULL), atimeWk), HERROR, errno, errno_str());

                return 12;
            }

            (void)send(sock, sendmsg, (int)strlen(sendmsg), 0);
        }
        else
        {
            /** UDPの場合はsendtoするだけ */
            (void)sendto(sock, sendmsg, (int)strlen(sendmsg), 0, (struct sockaddr *)&netInfo.addr, sizeof(netInfo.addr));
        }

        SAFE_SOCK_CLOSE(sock);
    }


    return 0;
}

CentOS(バージョン7以降)の新規インストール時に行う作業をスクリプト化したもの

新しいバージョンのCentOS/RedHat(バージョン7以降)がリリースされた場合などに使用するスクリプトです。
基本的にセキュリティはゆるゆるなので状況に応じて設定を変更してください。

やっていることはざっと以下の通りです。

  • rootで実行しているかチェック
  • umaskを0022に設定
  • 変更を行うファイルのバックアップをコピーするためのディレクトリ作成
  • SELinux無効化
  • perlのインストール
  • gccのインストール (コメントアウトしてます)
  • gdbのインストール (コメントアウトしてます)
  • Sambaサーバーのインストール (IPフィルタは127.と192.168.1.になってます)
  • firewalldの無効化
  • wgetのインストール
  • SSHでrootログイン不可化 (コメントアウトしてます)
  • umaskを元に戻す
#!/bin/sh


BK_DIR=~/init_backup


function file_backup() {
  srcfile=$1
  dstfile=$2

  i=0
  while [ $i -le 100000 ]
  do
    if [ ! -e ${dstfile}.${i} ]
    then
      cp -p ${srcfile} ${dstfile}.${i}

      if [ $? -eq 0 ]
      then
        echo "[Info ] Copying file succeeded(${dstfile}.${i})."
        break
      else
        echo "[Error] Copying file failed(${dstfile}.${i})."
      fi
    fi
    i=`expr $i + 1`
  done
}


# --------------------------------------------------------------------
# Check Superuser

if [ ${EUID:-${UID}} != 0 ]
then
  echo "[Error] You must run this script with Superuser."
  exit -1
fi


# --------------------------------------------------------------------
# Set umask

OLD_MASK=`umask`
umask 0022


# --------------------------------------------------------------------
# Create backup

echo "################## Create backup directory ##################"

if [ ! -e ${BK_DIR} ]
then
  mkdir -p ${BK_DIR}
  chmod 0755 ${BK_DIR}

  echo "[Info ] backup dir(${BK_DIR}) has created."
else
  echo "[Info ] backup dir(${BK_DIR}) has been already created. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Disable SELinux

echo "################## Disable SELinux ##################"

cat /etc/selinux/config | grep "SELINUX=disabled" > /dev/null
if [ $? -ne 0 ]
then
  mkdir -p ${BK_DIR}/etc/selinux
  file_backup /etc/selinux/config ${BK_DIR}/etc/selinux/config

  sed -i -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

  # Disable current shell SELinux either.
  setenforce 0

  echo "[Info ] Disable SELinux has done."
else
  echo "[Info ] Disable SELinux has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Install perl

echo "################## Install perl ##################"

rpm -q perl
if [ $? -ne 0 ]
then
  # perl is not installed.
  yum -y install perl

  sleep 1
fi


# --------------------------------------------------------------------
# Install gcc

#echo "################## Install gcc ##################"
#
#rpm -q gcc
#if [ $? -ne 0 ]
#then
#  # gcc is not installed.
#  yum -y install gcc
#
#  sleep 1
#fi


# --------------------------------------------------------------------
# Install gdb

#echo "################## Install gdb ##################"
#
#rpm -q gdb
#if [ $? -ne 0 ]
#then
#  # gdb is not installed.
#  yum -y install gdb
#
#  sleep 1
#fi


# --------------------------------------------------------------------
# Install & Setup Samba Server

echo "################## Install & Setup Samba Server ##################"

systemctl status smb | grep "Loaded: not-found"
if [ $? -ne 0 ]
then
  # smbd is not installed.
  yum -y install samba

  sleep 1

  # Backup original smb.conf
  mkdir -p ${BK_DIR}/etc/samba
  file_backup /etc/samba/smb.conf ${BK_DIR}/etc/samba/smb.conf

  # Create empty smb.conf, 
  echo "[global]" > /etc/samba/smb.conf
  echo "encrypt passwords = yes" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "dos charset = CP932" >> /etc/samba/smb.conf
  echo "unix charset = UTF-8" >> /etc/samba/smb.conf
  # echo "display charset = UTF-8" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "workgroup = WORKGROUP" >> /etc/samba/smb.conf
  echo "hosts allow = 127. 192.168.1." >> /etc/samba/smb.conf
  echo "server string = Samba Server Version %v" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "security = user" >> /etc/samba/smb.conf
  echo "passdb backend = tdbsam" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "log file = /var/log/samba/log.%m" >> /etc/samba/smb.conf
  echo "max log size = 50" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf
  echo "[shareall]" >> /etc/samba/smb.conf
  echo "path = /" >> /etc/samba/smb.conf
  echo "writable = yes" >> /etc/samba/smb.conf
  echo "printable = no" >> /etc/samba/smb.conf
  echo "public = yes" >> /etc/samba/smb.conf
  echo "create mode = 755" >> /etc/samba/smb.conf
  echo "directory mode = 755" >> /etc/samba/smb.conf
  echo "socket options = TCP_NODELAY SO_RCVBUF=16384 SO_SNDBUF=16384" >> /etc/samba/smb.conf
  echo "" >> /etc/samba/smb.conf

  echo "[Info ] Create Samba user."
  pdbedit -a -u root

  # Start samba service.
  systemctl start smb
  systemctl start nmb

  # Enable to boot samba service automatically.
  systemctl enable smb
  systemctl enable nmb

  firewall-cmd --add-service=samba
  firewall-cmd --add-service=samba --permanent

  echo "[Info] Install & Setup Samba Server has done."
else
  echo "[Info] Install & Setup Samba Server has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Disable firewalld

echo "################## Disable firewalld ##################"

systemctl is-enabled firewalld | grep enabled
if [ $? -eq 0 ]
then
  # firewalld is now running.
  systemctl stop firewalld
  systemctl disable firewalld

  echo "[Info] Disable firewalld has done."
else
  echo "[Info] Disable firewalld has already done. Skipped."
fi

echo ""


# --------------------------------------------------------------------
# Install wget

echo "################## Install wget ##################"

yum list installed | grep wget
if [ $? -eq 1 ]
then
  yum -y install wget

  sleep 1
fi

echo ""


# --------------------------------------------------------------------
# Disable SSH root Login

#echo "################## Disable SSH root Login ##################"

#cat /etc/ssh/sshd_config | grep -x "PermitRootLogin no"
#if [ $? -ne 0 ]
#then
#  mkdir -p ${BK_DIR}/etc/ssh
#  file_backup /etc/ssh/sshd_config ${BK_DIR}/etc/ssh/sshd_config
#
#  cat /etc/ssh/sshd_config | grep -x "#PermitRootLogin .*"
#  if [ $? -eq 0 ]
#  then
#    sed -i -e "s/#PermitRootLogin .*/PermitRootLogin no/g" /etc/ssh/sshd_config
#  fi
#
#  echo "[Info ] Disable SSH root Login has done. SSH service will be restarted..."
#
#  systemctl restart sshd
#else
#  echo "[Info ] Disable SSH root Login has already done. Skipped."
#fi

echo ""


# --------------------------------------------------------------------
# Set umask back

umask ${OLD_MASK}


echo ""
echo "[Info] All processes has done."

iPhoneアプリにGoogle AdSense, AdMob, Firebaseを使って広告を出す方法まとめ

色々試行錯誤してなんとか広告を表示できたのですが、思ったこと。

なんかWebサービスいっぱいあるし、
なんちゃらIDみたいのいっぱい出てくるし、混乱するよおお!!!

ということで、とりあえず関連図を一枚の画像にしてみました(コーディングまですべて書いてあるよ!)
まずは見易さ度外視でとりあえず全登場人物とその関係を書いてみました。
これさえ見れば、あなたも必ず広告が出せるようになるはず!

かなりデカイ画像なので、ダウンロードして拡大してみてくださいね!
ちなみにIDは適当なので、ご自分のものに置き換えてください。


コーディング

コピペできるように書いておきます。

Podfileはこちら。プロジェクト名はご自分のものに置き換えてください。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'MySkillTrain1' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for MySkillTrain1
  pod 'Firebase/Core'
  pod 'Firebase/AdMob'
  pod 'Google-Mobile-Ads-SDK'
end

AppDelegate.swiftに書くコードはこちら。IDは適当です。ご自分のものに置き換えてください。

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Use Firebase library to configure APIs
        FIRApp.configure()

        // Initialize Google Mobile Ads SDK, application IDを設定
        GADMobileAds.configure(withApplicationID: "ca-app-pub-2356785678063803~2746526570")

        return true
    }

広告を置くView Controllerのコードはこちら。IDは適当です。ご自分のものに置き換えてください。

import GoogleMobileAds

class ViewController: UIViewController {
    @IBOutlet weak var bannerView: GADBannerView!

    override func viewDidLoad() {
        print("Google Mobile Ads SDK version: \(GADRequest.sdkVersion())")
        bannerView.adUnitID = "ca-app-pub-1245659001912343/1337795797"
        bannerView.rootViewController = self
        bannerView.load(GADRequest())
    }
}

各要素の解説

やる気があれば書きます。
とりあえず各Webサービスへのリンクを書いときます。
IDを取得する順番とか、必要ですかねー?

Google AdSense

AdMob

Firebase console

その他の設定

テストでうっかり忘れがちなのが、ATS(App Transport Security)です。
これで外部との通信を許可しておかないと、広告が表示されません。

Zenphotoを超簡単にインストールする方法 (Linux(CentOS))

はじめに

世の中にはGoogleフォト等の便利な写真用ストレージサービスがありますが、
以下の理由から自宅サーバーにzenphotoを導入することにしました。

  • 長年使用していると何かしら情報が洩れそうで心配
  • 家族全員の携帯で取りだめてる写真や動画や時には写真以外のファイルを容量無制限でまとめてぶっこみたい

今回は自作のスクリプトを使って一発でインストールしています。
スムーズに行けば5分程度で完了し、すぐ使えるようになります。

環境:CentOS 7 (64-bit)

インストール手順

(1)必要なパッケージのインストールと設定

以下の自分が自作したスクリプトをrootで実行します。
setup_zenphoto.sh 直

WebサーバーやDBサーバーの設定を色々と変更するので、怖かったらスクリプトの中身をコピペして手動で実行してってください。本スクリプトを使用して不利益が生じても責任は負いませんのでご注意を…。あと、スクリプトのエラー処理や複数回実行等の処理は適当です。

スクリプトをダウンロードして、中身をテキストエディタで開き、
最初の方にある以下のパラメーターを好きな値に変更してからスクリプトを実行してください。

パラメーター 意味
PHOTO_DBNAME 写真用のデータベース名
PHOTO_DBUSERNAME 写真用のデータベース用ユーザー名
PHOTO_DIRNAME Webサーバーにzenphotoを展開する際のディレクトリ名(そのままURLになります)
SSL_CRT_BASENAME SSL用証明書と秘密鍵のファイル名

実行するコマンドはこちら。
./setup_zenphoto.sh

コマンド中は対話でいくつか入力を求められます。

Enter current password for root (enter for none):

インストール直後はパスワードがないので、そのままEnterキーを押してください。
mariadbをこのスクリプト内でインストールした場合に実行する
 mysql_secure_installationで入力を求められるものです。

Set root password? [Y/n]

「Y」を入力して、パスワードを設定してください。
ここで入力するパスワードは、このスクリプトの第二引数に指定したものと同じものにしてください。

Remove anonymous users? [Y/n]

「Y」を入力してDBのanonymousユーザーは削除しておきましょう。

Disallow root login remotely? [Y/n]

「Y」を入力してDBのリモートアクセスを無効にしましょう。

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

「Y」を入力してtestDBを削除しておきましょう。

Reload privilege tables now? [Y/n]

「Y」を入力して情報をリロードしておきましょう。

Enter pass phrase for <変数SSL_CRT_BASENAMEの値>.key:

SSL通信のための秘密鍵パスフレーズです。
任意の文字列を入力してください。

Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:

Country Nameには「JP」、Stateには「Tokyo」や「Kanagawa」など都道府県を、
Locality Nameには「Yokohama」など市や区を入力してください。

Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:

何も入力せずEnterしてください。

Common Name (eg, your name or your server's hostname) []:

実際にhttpsでサーバーにアクセスするアドレスを記載します。
IPアドレスでアクセスするなら、IPアドレスを、
ドメイン名でアクセスするならドメイン名を入力します。

Email Address []:
A challenge password []:
An optional company name []:

何も入力せずEnterしてください。

Please provide the prefix of Imagemagick installation [autodetect] :

何も入力せずEnterしてください。

スクリプトが最後まで実行されると以下が表示されるはずです。
ブラウザでアクセスしてください。(e.g. http://192.168.1.2/myphoto/)

Please contact http://<yoursever>/<変数PHOTO_DIRNAMEの値>/ and setup.
(2)ブラウザで初期設定する

(1)で最後に表示されたURLにアクセスしましょう(の部分は適宜置き換えてください)

まずは以下の画像を参考にして、DBの情報を入力した後、[保存]ボタンを押してください。

データベースエンジン MySQL
データベースユーザ スクリプトの変数PHOTO_DBUSERNAMEで指定したもの
データベースパスワード スクリプトの第二引数に指定したもの
データベース名 スクリプトの変数PHOTO_DBNAMEで指定したもの

次に以下の警告が出ている場合は、「適用」を押下して文字コードUTF-8に変更します。

上の適用ボタンを押すと以下が表示されることがあります。
その場合は「実行してください」の部分のリンクをクリックしてください。

URLオプションUTF8画像URIを有効にすべきです。 実行してください

また、以下の警告が出ることもあるのですがおそらく無視しても大丈夫だと思いますので、
ここまできたら画面下部の[実行]ボタンを押下して、zenphotoのセットアップを開始してください。

警告!

Zenphotoは所有者のみがアクセスできる(パーミッションは0600)zp-dataフォルダーの機密ファイルを作成することをおすすめします。setup.logのファイルのパーミッションは未承認アクセスを許可できる0644である必要があります。
警告!

恐らくアップロードで問題があります。以下のファイルをチェックしてください:
zp-core/zp-extensions/tinymce4/themes/inlite/src/test/.eslintrc

zenphotoのセットアップが完了した後は、[管理ユーザ名とパスワードを設定する]のリンクをクリックして
zenphotoの管理ユーザーと一般ユーザーを作成してください。

管理ユーザ名とパスワードを設定する必要があります。

次に管理ユーザーでログインして、いま上で色々いじっていた
セットアップ画面が外部から見られないように設定を変えましょう。

ログイン後に「Overview」タグをクリック、「Utility functions」グループの中から
「Setup > protect script」をクリックしましょう。

これで完了です!
アルバムを作ったり、写真をアップロードしてみたり色々と試してください。

おまけ

PHPの設定で、デフォルトでは一度にアップロードできるファイル容量が2MBになっているかもしれません。
またファイルを直接配置(デフォルトでは/var/www/html/myphoto/albums/<作成したアルバム名)>してもOKです。

インストールされるパッケージ一覧

スクリプトを実行すると、以下のパッケージがインストールされます。

  • gcc
  • unzip (zenphotoのzip展開用)
  • mariadb, mariadb-server (DBサーバー)
  • httpd (Webサーバー)
  • mod_ssl (httpdSSL通信モジュール)
  • php周りの色々なパッケージ (zenphoto用)
  • imagick (zenphoto用)
  • ImageMagick (zenphoto用)
  • zenphoto
  • zenphotoのiOS用アドイン(オプション)

設定一覧

上記パッケージの設定ファイルなどを自動で編集します。

  • /etc/php.iniにextension=imagick.soを追加
  • スクリプト内の変数PHOTO_DBNAMEのデータベースが作成
  • スクリプト内の変数PHOTO_DBUSERNAMEのデータベース用ユーザー作成
  • mariadbのセキュリティ確保用スクリプトmysql_secure_installationを実行
  • /etc/httpd/confに変数SSL_CRT_BASENAMEのファイル名の秘密鍵・証明書を作成。
  • /etc/httpd/conf.d/ssl.confの証明書・秘密鍵のファイル名を↑のパスに変更
  • zenphotoを/var/www/htmlに展開。所有者・所有グループをapache:apacheに変更
  • /tmp/zenphoto-iOS-plugin-master.zipが存在すればzenphoto
  • httpdのセキュア設定(ServerTokensをProdに変更、TraceEnableをOffに設定等)

スクリプトの解説

やる気があったら書きます。
(でも読めばわかる内容だと思います。読んでみてください。)

プライバシーポリシー お問い合わせ