新規アカウントの作成 さくらインターネットのメールで事前にアカウントを作成しておきますIMAP4 を選択 IMAP は、サーバにデータを保存しています。
アカウント情報を入力
サーバ情報を入力
情報の確認
ログイン パスワードは、アカウントの設定より登録できます。
受信処理 現在のアカウントを登録したアカウントに変更して、受信処理を行います ( 全受信はすべてのアカウントです )
メールアイテム格納用というフォルダは、他のメールクライアントで作成したものです。 Gmail は、安全性の低いアプリの許可を『有効』にする必要があります。
2018年10月18日
Sylpheed( Windows メールクライアント ) で さくらインターネットのメールを IMAP で受信する
2018年10月17日
PHP : IMAP 関数 でまずメールのヘッダ部分を整理してログに出力する / ※ JSON 出力を追加
本文は、マルチパートや添付ファイルなので、頭を切り替えて考える必要があります。とりあえずいろんなメールアカウントから、さくらインターネットのメールに転送してテストしました。 結果はすべて debug.log へ出力します。 データ取得後の管理の為、UID を取得して付加しています。 ▼ PHP マニュアルより imap_uidUID はユニークな ID であり時間が経過しても変わりません
<?php error_reporting( E_ALL & ~E_NOTICE & ~E_STRICT ); session_cache_limiter('nocache'); session_start(); header( "Content-Type: text/html; charset=utf-8" ); # デバッグログの初期化 file_put_contents("debug.log", "開始\n" ); mb_internal_encoding("UTF-8"); xlog("ログの出力"); # *************************** # IMAP 接続 # *************************** $con = @imap_open("{サーバ:993/imap/ssl}INBOX", "ユーザ", "パスワード"); if ( $con === FALSE ) { print imap_last_error(); xlog(imap_last_error()); exit(); } // 現在のメールボックスに関する情報を得る $mbox_info = imap_mailboxmsginfo( $con ); xlog("\n■■■ \$mbox_info 現在のメールボックスに関する情報 -------"); xlog( print_r( $mbox_info ,true )); if( $mbox_info->Nmsgs == 0 ) { xlog( "メールメッセージがありません" ); exit(); } // *************************** // メッセージ件数 // *************************** $max = $mbox_info->Nmsgs; xlog("【メッセージ件数:{$max}】" ); if ( $max > 100 ) { $max = 100; } // メールの主要データの集約 $mail = array(); // *************************** // $max 〜 1 // 最新から表示 // *************************** for( $i = $max; $i >= 1; $i-- ) { // *************************** // 全ヘッダーデータ // *************************** $mail_head = imap_header($con, $i); // アドレス xlog( "▼▼▼ \$mail_head このメールのヘッダデータ ({$i}番目) ▼▼▼" ); // 【UID】を取得して、$mail_head に追加 $mail["head"][$i]["UID"] = imap_uid( $con, $i ); $mail["head"][$i]["Msgno"] = $mail_head->Msgno; xlog( print_r( $mail_head ,true ) ); // *************************** // from : テキストと メールアドレス( アドレスのみの場合もある ) // *************************** xlog("■■■ fromaddress (decode 前) -------"); xlog( $mail_head->fromaddress ); // *************************** // ASCII と それ以外で分解 // *************************** $fromaddress = imap_mime_header_decode( $mail_head->fromaddress ); xlog("■■■ fromaddress (decode 後) -------"); xlog( print_r( $fromaddress, true ) ); $mail["head"][$i]["fromaddress"] = ""; foreach( $fromaddress as $key => $value ) { if( $value->charset != 'default' ) { $mail["head"][$i]['fromaddress'] .= mb_convert_encoding($value->text,'UTF-8',$value->charset); } else{ $mail["head"][$i]['fromaddress'] .= $value->text; } } xlog("■■■ fromaddress (編集後) -------"); xlog( $mail["head"][$i]['fromaddress'] ); xlog(""); // *************************** // subject : 件名 // *************************** xlog("■■■ subject (decode 前) -------"); xlog( $mail_head->subject ); // *************************** // ASCII と それ以外で分解 // *************************** $subject = imap_mime_header_decode( $mail_head->subject ); xlog("■■■ subject (decode 後) -------"); xlog( print_r( $subject, true ) ); $mail["head"][$i]["subject"] = ""; foreach( $subject as $key => $value ) { if( $value->charset != 'default' ) { $mail["head"][$i]['subject'] .= mb_convert_encoding($value->text,'UTF-8',$value->charset); } else{ $mail["head"][$i]['subject'] .= $value->text; } } xlog("■■■ subject (編集後) -------"); xlog( $mail["head"][$i]['subject'] ); xlog(""); // *************************** // 受信日時 // *************************** $data = $mail["head"][$i]['date'] = $mail_head->date; $data = $mail["head"][$i]['date_normal'] = date('Y-m-d H:i:s', strtotime($data)); // *************************** // サイズ // *************************** $data = $mail["head"][$i]['size'] = $mail_head->Size; $mail["head"][$i]["mail_head"] = $mail_head; } xlog("■■■ 編集後データの一覧 -------"); xlog( print_r( $mail["head"], true ) ); // *************************** // IMAP 接続解除 // *************************** imap_close($con); // *************************** // ログ出力 // *************************** function xlog($message) { file_put_contents("debug.log", "{$message}\n" , FILE_APPEND ); } ?> OK
json 文字列を出力して Ajax で使用できるように変更
<?php error_reporting( E_ALL & ~E_NOTICE & ~E_STRICT ); session_cache_limiter('nocache'); session_start(); header( "Access-Control-Allow-Origin: *" ); header( "Content-Type: application/json; charset=utf-8" ); # デバッグログの初期化 file_put_contents("debug.log", "開始\n" ); mb_internal_encoding("UTF-8"); xlog("ログの出力"); # *************************** # IMAP 接続 # *************************** $con = @imap_open("{さくらユーザ.sakura.ne.jp:993/imap/ssl}INBOX", "ユーザ@さくらユーザ.sakura.ne.jp", "パスワード"); if ( $con === FALSE ) { print imap_last_error(); xlog(imap_last_error()); exit(); } // 現在のメールボックスに関する情報を得る $mbox_info = imap_mailboxmsginfo( $con ); xlog("\n■■■ \$mbox_info 現在のメールボックスに関する情報 -------"); xlog( print_r( $mbox_info ,true )); if( $mbox_info->Nmsgs == 0 ) { xlog( "メールメッセージがありません" ); exit(); } // *************************** // メッセージ件数 // *************************** $max = $mbox_info->Nmsgs; xlog("【メッセージ件数:{$max}】" ); if ( $max > 100 ) { $max = 100; } // メールの主要データの集約 $mail = array(); $json = array(); // *************************** // $max 〜 1 // 最新から表示 // *************************** for( $i = $max; $i >= 1; $i-- ) { $obj = new stdClass(); // *************************** // 全ヘッダーデータ // *************************** $mail_head = imap_header($con, $i); // アドレス xlog( "▼▼▼ \$mail_head このメールのヘッダデータ ({$i}番目) ▼▼▼" ); // 【UID】を取得して、$mail_head に追加 $mail["head"][$i]["UID"] = imap_uid( $con, $i ); $mail["head"][$i]["Msgno"] = $mail_head->Msgno; xlog( print_r( $mail_head ,true ) ); // *************************** // from : テキストと メールアドレス( アドレスのみの場合もある ) // *************************** xlog("■■■ fromaddress (decode 前) -------"); xlog( $mail_head->fromaddress ); // *************************** // ASCII と それ以外で分解 // *************************** $fromaddress = imap_mime_header_decode( $mail_head->fromaddress ); xlog("■■■ fromaddress (decode 後) -------"); xlog( print_r( $fromaddress, true ) ); $mail["head"][$i]["fromaddress"] = ""; foreach( $fromaddress as $key => $value ) { if( $value->charset != 'default' ) { $mail["head"][$i]['fromaddress'] .= mb_convert_encoding($value->text,'UTF-8',$value->charset); } else{ $mail["head"][$i]['fromaddress'] .= $value->text; } } xlog("■■■ fromaddress (編集後) -------"); xlog( $mail["head"][$i]['fromaddress'] ); xlog(""); $obj->fromaddress = $mail["head"][$i]['fromaddress']; // *************************** // subject : 件名 // *************************** xlog("■■■ subject (decode 前) -------"); xlog( $mail_head->subject ); // *************************** // ASCII と それ以外で分解 // *************************** $subject = imap_mime_header_decode( $mail_head->subject ); xlog("■■■ subject (decode 後) -------"); xlog( print_r( $subject, true ) ); $mail["head"][$i]["subject"] = ""; foreach( $subject as $key => $value ) { if( $value->charset != 'default' ) { $mail["head"][$i]['subject'] .= mb_convert_encoding($value->text,'UTF-8',$value->charset); } else{ $mail["head"][$i]['subject'] .= $value->text; } } xlog("■■■ subject (編集後) -------"); xlog( $mail["head"][$i]['subject'] ); xlog(""); $obj->subject = $mail["head"][$i]['subject']; // *************************** // 受信日時 // *************************** $data = $mail["head"][$i]['date'] = $mail_head->date; $data = $mail["head"][$i]['date_normal'] = date('Y-m-d H:i:s', strtotime($data)); // *************************** // サイズ // *************************** $data = $mail["head"][$i]['size'] = $mail_head->Size; $mail["head"][$i]["mail_head"] = $mail_head; $json[] = $obj; } xlog("■■■ 編集後データの一覧 -------"); xlog( print_r( $mail["head"], true ) ); // *************************** // IMAP 接続解除 // *************************** imap_close($con); print json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); // *************************** // ログ出力 // *************************** function xlog($message) { file_put_contents("debug.log", "{$message}\n" , FILE_APPEND ); } ?>
2018年10月15日
CSS の @media screen と IFRAME を使用して PC コンテンツとスマホページを完全に別作成して切り替える
PC コンテンツとスマホページを純粋に CSS で切り替えるには、表示画面の設計がとても難しくなります。コンテンツ量が基本的には同量になるのを両立させるのは単純では無いと思います。 なので、本来のレスポンシブデザインでは無いですが、既存の PC ページへスマホページを追加する方法として、IFRAME を PC ページの中に展開するのが簡単です。 必要な HTML と CSS は以下のようなものになり、中身のサーバサイドの作成方法は昔ながらのリファレンスや、エージェント文字列で行います。 一番のポイントは、IFRAME をブラウザに fit させるのに必要な、html,body { height: 100%; } です。
<head> <meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport"> <style> html,body { height: 100%; } @media screen and ( min-width:480px ) { #container { display: block; } #ssub { display: none; } } @media screen and ( max-width:479px ) { #container { display: none; } #ssub { display: black; width: 100%; height: 100%; } } </style> </head> <body> <div id="container"> <!-- ここに PC 用のコンテンツを表示する --> </div> <!-- ここに スマホ 用のコンテンツを表示する --> <iframe id="ssub" src="スマホ専用ページ"></iframe> <!-- スマホ専用ページはこのページより参照されない場合はこのページを展開する --> <!-- ( このページとスマホ専用ページは同一 URL で作成 ) --> </body>
2018年10月14日
Ruby(mechanize) で Seesaa のエクスポート
さくらインターネットに mechanize をインストールしても、https が動かないので Windows10 で mechanize をインストールして実行しています。 Windows10 に mechanize のインストールも、C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/net-http-persistent-3.0.0/lib/net/http/persistent.rb を以下のリンク先のように変更する必要があります。 Sets a default pool size for Windows as Process::RLIMIT_NOFILE is not supported
# ▼ エラー DEFAULT_POOL_SIZE = Process.getrlimit(Process::RLIMIT_NOFILE).first / 4 # ▼ 変更 if Gem.win_platform? then DEFAULT_POOL_SIZE = 256 else DEFAULT_POOL_SIZE = Process.getrlimit(Process::RLIMIT_NOFILE).first / 4 end
引数は、cgi に引き渡される(cgi['no'])ので、#{cgi['no']} で文字列内に埋め込んで展開させます。 seesaa_backup.rb Windows では、STDOUT が crlf で出力される為、Seesaa からの出力と同じにする為に、冒頭で STDOUT.binmode を実行しています。
# Seesaa エクスポート STDOUT.binmode # CGI 用 require "cgi" cgi = CGI.new # ヘッダを出力( ダウンロード用に application/octet-stream と ファイル名 ) puts "Content-Type: application/octet-stream; charset=utf-8" puts "Content-Disposition: attachment; filename=export.log" puts "Expires: Thu, 19 Nov 1981 08:52:00 GMT" puts "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" puts "Pragma: no-cache" puts # Mechanize 用 require 'mechanize' agent = Mechanize.new agent.verify_mode = OpenSSL::SSL::VERIFY_NONE agent.follow_meta_refresh = true agent.user_agent = 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko' # ログインページ page = agent.get("https://ssl.seesaa.jp/pages/welcome/login/input") # FORM 要素の name 属性で参照 form = page.form_with(:name => 'authpost') # FORM 要素内の入力 form["member__email"] = "メールアドレス" form["password"] = "パスワード" # FORM 要素を使用して送信 page = form.submit # ここでログインが完了するので、目的のページへ移動する # 対象ブログのページ( デフォルトで新規投稿へ移動 ) page = agent.get("https://blog.seesaa.jp/cms/home/switch?blog_id=#{cgi['no']}") # エクスポートページへ移動 page = agent.get('https://blog.seesaa.jp/cms/tools/mt/export/input') # このページの1番目の FORM form = page.forms[0] # この FORM で送信 page = form.submit # 結果をブラウザに出力 print page.body
関連する記事
2018年10月09日
Oracle : sqlplus で、テーブルの create 文( DBMS_METADATA.GET_DDL ) と csv データを出力する
create 文の作成は、DBMS_METADATA.GET_DDL で行います。 ※ 94 DBMS_METADATA sqlplus 内のコマンドについては、SETシステム変数の一覧 を参照して下さい USER_ALL_TABLES の内容は、ALL_ALL_TABLES を参照して下さい build_create.sql sqlplus ユーザ/パスワード@識別子 @build_create
SET LONG 2000000 SET LINESIZE 32767 SET PAGESIZE 0 SET TRIMSPOOL ON SET FEEDBACK OFF SET TERMOUT OFF SPOOL create.sql SELECT DBMS_METADATA.GET_DDL('TABLE',u.table_name) FROM USER_ALL_TABLES u WHERE u.TABLE_NAME in ('社員マスタ','得意先マスタ'); SPOOL OFF SPOOL 社員.csv SELECT 社員コード||','||氏名||','||フリガナ||','||所属||','||性別||','||作成日||','||更新日||','||給与||','||手当||','||管理者||','||生年月日 from 社員マスタ; SPOOL OFF EXIT
取得した create table 文
CREATE TABLE "LIGHTBOX"."得意先マスタ" ( "得意先コード" NVARCHAR2(4), "得意先名" NVARCHAR2(50), "得意先区分" NVARCHAR2(1), "担当者" NVARCHAR2(4), "郵便番号" NVARCHAR2(7), "住所1" NVARCHAR2(100), "住所2" NVARCHAR2(100), "作成日" DATE, "更新日" DATE, "締日" NUMBER(2,0), "締日区分" NUMBER(1,0), "支払日" NUMBER(2,0), "備考" NVARCHAR2(100), PRIMARY KEY ("得意先コード") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "LIGHTBOXAREA" ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "LIGHTBOXAREA" CREATE TABLE "LIGHTBOX"."社員マスタ" ( "社員コード" NVARCHAR2(4), "氏名" NVARCHAR2(50), "フリガナ" NVARCHAR2(50), "所属" NVARCHAR2(4), "性別" NUMBER(1,0), "作成日" DATE, "更新日" DATE, "給与" NUMBER, "手当" NUMBER, "管理者" NVARCHAR2(4), "生年月日" DATE, PRIMARY KEY ("社員コード") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAUL T) TABLESPACE "LIGHTBOXAREA" ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAUL T) TABLESPACE "LIGHTBOXAREA"
C# : VB.net : SQLExpress(SQLServer) : SQL-DMO と同等の SMO によるバックアップ
SQL-DMO は、COM なので主に VBScript から使われていましたが、SMO は、SQL-DMO に取って代わる Framework ベースの API です。もともとが巨大なクラスの集合体なので、バックアップにしか通常使う事がありませんが、SQLServer の運用を行うなら知っておく必要はあります バックアップは SQL からも出来、そちらのほうが簡単です。SQL-DMO や SMO は、テープによるデータのバックアップを想定しており、デバイスを作成しても実体は作成されません。ディスクファイルでも、追加でバックアップされます バックアップ後の内容の確認は以下のようにして行いますRESTORE FILELISTONLY FROM DISK = 'C:\tmp\backup.dmp'参照としては以下の5つを追加します 1) Microsoft.SqlServer.ConnectionInfo 2) Microsoft.SqlServer.Management.Sdk.Sfc 3) Microsoft.SqlServer.Smo 4) Microsoft.SqlServer.SmoExtended 5) Microsoft.SqlServer.SqlEnum SMO ライブラリのダウンロードは nuget.exe が簡単です。 nuget.exe をダウンロードして専用のフォルダで実行します。nuget install Microsoft.SqlServer.SqlManagementObjects -Version 140.17283.0※ バージョン選択の参考ページ nuget.exe と同じ場所に、Microsoft.SqlServer.SqlManagementObjects.140.17283.0 フォルダが作成されるので、lib\net40 内から dll を参照して使用します。 ▼ C#
// サーバー Server srv; // インスタンス srv = new Server(); // サーバーインスタンスの情報 srv.ConnectionContext.AutoDisconnectMode = AutoDisconnectMode.NoAutoDisconnect; srv.ConnectionContext.LoginSecure = false; srv.ConnectionContext.Login = "sa"; srv.ConnectionContext.Password = "パスワード"; // 接続 srv.ConnectionContext.Connect(); // バージョンの表示 Console.WriteLine(srv.Information.Version); // デバイスオブジェクト BackupDevice backup_dev = new BackupDevice(); // サーバーと関係付ける backup_dev.Parent = srv; // 論理名を設定 backup_dev.Name = "BACKUP"; // 装置のタイプ backup_dev.BackupDeviceType = BackupDeviceType.Disk; // 実際の場所( バックアップするまで作成されません ) backup_dev.PhysicalLocation = @"c:\tmp\backup.dmp"; // 処理サンプルとして一旦削除して作成する if (srv.BackupDevices["BACKUP"].State == SqlSmoState.Existing) { srv.BackupDevices["BACKUP"].Drop(); backup_dev.Create(); } // バックアップオブジェクト Backup dbBackup = new Backup(); // デフォルトは Database dbBackup.Action = BackupActionType.Database; dbBackup.Database = "lightbox"; dbBackup.Devices.AddDevice("BACKUP", DeviceType.LogicalDevice); dbBackup.BackupSetName = "BACKUP_lightbox"; // バックアップ開始 dbBackup.SqlBackup(srv); // 接続解除 srv.ConnectionContext.Disconnect(); Console.WriteLine("バックアップが終了しました");
▼ VB.net
' サーバー Dim srv As Server ' インスタンス srv = New Server() ' サーバーインスタンスの情報 srv.ConnectionContext.AutoDisconnectMode = AutoDisconnectMode.NoAutoDisconnect srv.ConnectionContext.LoginSecure = False srv.ConnectionContext.Login = "sa" srv.ConnectionContext.Password = "パスワード" ' 接続 srv.ConnectionContext.Connect() ' バージョンの表示 Console.WriteLine(srv.Information.Version) ' デバイスオブジェクト Dim backup_dev As BackupDevice = New BackupDevice() ' サーバーと関係付ける backup_dev.Parent = srv ' 論理名を設定 backup_dev.Name = "BACKUP" ' 装置のタイプ backup_dev.BackupDeviceType = BackupDeviceType.Disk ' 実際の場所( バックアップするまで作成されません ) backup_dev.PhysicalLocation = "c:\tmp\backup.dmp" Try ' 既に存在する場合はそのまま使う backup_dev.Create() Catch ex As Exception End Try ' バックアップオブジェクト Dim dbBackup As Backup = New Backup() ' デフォルトは Database dbBackup.Action = BackupActionType.Database dbBackup.Database = "lightbox" dbBackup.Devices.AddDevice("BACKUP", DeviceType.LogicalDevice) dbBackup.BackupSetName = "BACKUP_lightbox" ' バックアップ開始 dbBackup.SqlBackup(srv) ' 接続解除 srv.ConnectionContext.Disconnect() Console.WriteLine("バックアップが終了しました")
関連する記事 SQLServer : SQLでバックアップ SQL-DMO による VBScriptによるバックアップ 関連するMicrosoft のリンク SMO クラス ライブラリ SQL-DMO のインストール( SQLServer2005_BC.msi )
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。 Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。 また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。 ※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです 対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。※ エキスパートモードで表示しています アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります
<% if:page_name eq 'archive' -%> アーカイブページでのみ表示される内容 <% /if %> <% if:page_name eq 'category' -%> カテゴリページでのみ表示される内容 <% /if %> <% if:page_name eq 'tag' -%> タグページでのみ表示される内容 <% /if %>この記述は、以下の場所で使用します![]()
|