サイボウズからのical出力です。
2017年当時、当社では、サイボウズ(スタンドアロン型)を使用していました。
別にいいんですが、iCal形式で出力させることにより、プライベートカレンダーである
Googleカレンダーとオーバーレイさせて表示させることができたり、
iPhone純正カレンダーから予定の確認できたりなどメリットがありました。
2023年末に、当社もクラウド版への移行にあたり、自前での出力が不要になりました。
前職でも、独自環境のスケジューラーでしたが、当時もこうやったらもっと便利だったなと思いました。
当時の環境
サイボウズデスクトップ10買い切り
YAMAHAのルーターでドメイン取得して、公開していました。
参考までに現在の環境
親アカウントに出力の許可をしてもらい、こちらから設定可能
現存する環境
$ more /proc/device-tree/model
Raspberry Pi Model B Plus Rev 1.2
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
流れ
1 サイボウズHTMLを見に行く。
2 予定っぽい表現内容を抜き出し、ical形式に出力
3 上記をwgetがてら、phpをical形式で保存
4 icalをdropboxに保存する。
5 非公開URLで共有し、iphone及びgoogleカレンダーで読みに行く。
6 念のため、過去分もバックアップ、アップロードする。
これで取得できる範囲は、1か月前~3ヶ月先までみたいな感じでした。
もちろん、読み込みのみですので、iphone及びgoogleカレンダーからは書き込みはできません。
参考サイト
<?php
/*
名古屋ではたらく社長ブログだもんで
サイボウズofffice8と同期するツール暫定版
http://ameblo.jp/sitescope/entry-10260113074.html
上記にて公開していただいているスクリプトをサイボウズ9用に勝手改変版
*/
//20170915 他のユーザーが追加した予定も出力できるように検索分改良
//20170921 27日前から77日後を取得する、基準日を翌月同日に設定
//
$timestamp = time() ;
$datetime = date( "YmdHi" , $timestamp ) ;
$setdate = date('Y.m.d', mktime(0,0,0,date('m')+1,date('d'),date('Y')));
$sstitle = @$_REQUEST['data'];
$uid = '';
if ( strlen($sstitle) > 5 ) {
$uid = substr($sstitle, 4);
}
//ユーザ名・パスワードをロード
require_once($sstitle.'namethis.php');
//-------------------------------------------------------------------------------------------------------------------
// 設定
//-------------------------------------------------------------------------------------------------------------------
//define("CHAR_CODE", 'SJIS'); //サイボウズの文字コード サイボウズ9はSJIS
define("CHAR_CODE", 'UTF-8'); //サイボウズの文字コード サイボウズ10はUTF
define("SCHEDULE_TITLE", 'Cybozu'); //スケジュールタイトル
define("SCHEDULE_MEMO", TRUE); //スケジュールメモまで取得する場合は'TRUE'
//define('PRODID', 'Cybozu2iCal'); //http://ameblo.jp/sitescope/entry-10260113074.html
define('PRODID', 'Cybozu2iCal2.2_'.$datetime.'_'.$setdate); //http://ameblo.jp/sitescope/entry-10260113074.html
//-------------------------------------------------------------------------------------------------------------------
//POSTデータ組み立て
$data = array(
"_System" => "login",
"_Login" => "1",
"LoginMethod" => "2",
// "_Account" => LOGIN_ID,
"_ID" => LOGIN_ID,
"Password" => LOGIN_PASS
);
$data = http_build_query($data, "", "&");
//headerにセット
$header = array(
"Content-Type: application/x-www-form-urlencoded",
"Content-Length: ".strlen($data)
);
$context = array(
"http" => array(
"method" => "POST",
"header" => implode("\r\n", $header),
"content" => $data
)
);
//printf("%s", $setdate);
//$nextmonth = $nextmonth + 1;
//基準日指定
//とりあえず個人月間スケジュール
if ( UID == "" ) {
// $url = CYBOZU_URL . '?page=ScheduleUserMonth';
// $url = CYBOZU_URL . '?page=ScheduleUserMonth';
// $url = CYBOZU_URL . '?page=ScheduleUserMonth#date=da.' . $setdate;
$url = CYBOZU_URL . '?page=ScheduleUserMonth&Date=da.' . $setdate;
} else {
// $url = CYBOZU_URL . '?page=ScheduleUserMonth&UID=' . UID;
// $url = CYBOZU_URL . '?page=ScheduleUserMonth&UID=' . UID . '#date=da.' . $setdate;
$url = CYBOZU_URL . '?page=ScheduleUserMonth&UID=' . UID . '&Date=da.' . $setdate;
}
//サイボウズからHTMLデータ取得
$work = file_get_contents($url, false, stream_context_create($context));
//printf("%s",$url );
//文字コードをUTF-8へ変換
$work = mb_convert_encoding($work, "UTF-8", CHAR_CODE);
//printf("%s",$work );
//正規表現がめんどくさいのでそのまま文字列比較で不要なとこをまず削除
$work = substr(strchr($work,'<table class="schedule usermonth" id="schedulemonth" width="100%" >'), 0);
$work = substr($work, 0, strpos($work, '<table class="monthNavi" '));
$work = substr(strchr($work,'<tbody id="um__body">'), 0);
$work = substr($work, 0, strpos($work, '</table>'));
//文字列比較でとりあえず、スケジュールを配列に格納
$wdate1 = "";
$wdate2 = "";
$schedule_list = "";
$loop_flg = TRUE;
while ( $loop_flg == TRUE ) {
//日付の取得
$wdate = "";
$wdate = substr(strchr($work,'<span class="date">'), 19);
$wdate = substr($wdate, 0, strpos($wdate, '</span>'));
if ($wdate == "") {
break;
}
//日付のフォーマットを変更
$date_sp = "";
$date_sp = split('/', $wdate);
$schedule_date = Date('Y') . sprintf("%02d",$date_sp[0]) . sprintf("%02d",$date_sp[1]);
//次の日も取得しとく
$schedule_date_tommorow = "";
$schedule_date_tommorow = Date('Ymd', mktime(0, 0, 0, (int)$date_sp[0], (int)((int)$date_sp[1] + 1), (int)Date('Y') ) );
//日付部分をカット
$work = substr(strchr($work,'<span class="date">'), 30);
$loop_flg2 = TRUE;
while ( $loop_flg2 == TRUE ) {
if ( strpos($work, '<a class="event" href=') > strpos($work, '<span class="date">') ) {
break;
} else {
//スケジュールIDを取得
//サイボウズ9
// $schedule_id = substr(strchr($work,'<div class="eventLink scheduleMarkTitle0" name="'), 53);
// $schedule_id = substr($schedule_id, 0, strpos($schedule_id, '">'));
//サイボウズ10
// $schedule_id = substr(strchr($work,'<div class="eventLink scheduleMarkTitle0 highlight-event'), 56);
$schedule_id = substr(strchr($work,' highlight-event'), 15);
$schedule_id = substr($schedule_id, 0, strpos($schedule_id, '" '));
if ( $schedule_id == "" ) {
break;
}
//----------------------------------
if ( SCHEDULE_MEMO == TRUE ) {
//printf("1___%s",$work2 );
//printf("%s", $work);
//スケジュール内容まで取得
$wlink = substr(strchr($work,'<a class="event" href="ag.exe?'), 30);
$wlink = substr($wlink, 0, strpos($wlink, '" title="'));
//固定リンクから見てみる。20170906
$url = CYBOZU_URL . '?page=ScheduleView&seid=' . substr($wlink,-16,6);
//printf("%s", $url);
// $url = CYBOZU_URL . '?' . $wlink;
//サイボウズからHTMLデータ取得
$work2 = file_get_contents($url, false, stream_context_create($context));
//文字コードをUTF-8へ変換
$work2 = mb_convert_encoding($work2, "UTF-8", CHAR_CODE);
//printf("%7s", $work2);
//正規表現がめんどくさいのでそのまま文字列比較で不要なとこをまず削除
$work2 = substr(strchr($work2,'<table class="dataView scheduleDataView" width="100%" >'), 0);
$work2 = substr($work2, 0, strpos($work2, '<span class="vr_scheduleUserCount">'));
//スケジュールタイトルを取得
$work2 = str_replace("\n\r","", $work2);
$work2 = str_replace("\n","", $work2);
$work2 = str_replace("\r","", $work2);
$schedule_description = substr(strchr($work2,'<div id="scheduleMemo"><tt>'), 27);
$schedule_description = substr($schedule_description, 0, strpos($schedule_description, '</tt>'));
$schedule_description = strip_tags($schedule_description);
} else {
$schedule_description = "";
}
//----------------------------------
//スケジュールタイトルを取得
$schedule_title = substr(strchr($work,'=sm" title="'), 12);
$schedule_title = substr($schedule_title, 0, strpos($schedule_title, '">'));
//時刻を取得
if (strpos($work, '<span class="eventDateTime">') < strpos($work, '=sm" title="')) {
$schedule_time = substr(strchr($work, '<span class="eventDateTime">'), 28);
$schedule_time = substr($schedule_time, 0, strpos($schedule_time, ' '));
} else {
$schedule_time = '';
}
//タイトル部分をカット
$work = substr(strchr($work,'=sm" title="'), 12);
//時間指定があるか判定
if ( !empty($schedule_time) ) {
$time_sp = "";
$time_sp = split('-', $schedule_time);
$from_sp = split(':', @$time_sp[0]);
//http://www.sunvisor.net/node/383
if ( count($time_sp) > 1 ) {
$to_sp = split(':', @$time_sp[1]);
} else {
$to_sp = $from_sp;
}
$from_sp[0] = sprintf('%02d', @$from_sp[0]);
$to_sp[0] = sprintf('%02d', @$to_sp[0]);
$from_hour = "";
$to_hour = "";
if ($from_sp[0]<10) {
$from_hour = '0' . @$from_sp[0];
} else {
$from_hour = $from_sp[0];
}
if ($to_sp[0]<10) {
$to_hour = '0' . $to_sp[0];
} else {
$to_hour = $to_sp[0];
}
if (count($to_sp)<2){
$to_hour = $from_hour + 1;
$to_sp[1] = $from_sp[1];
}
$schedule_summary = $schedule_title;
//http://www.sunvisor.net/node/383
$schedule_from = ':' . $schedule_date . 'T' . @$from_sp[0] . @$from_sp[1]. '00';
$schedule_to = ':' . $schedule_date . 'T' . @$to_sp[0] . @$to_sp[1]. '00';
$schedule_description = $schedule_title . " " . $schedule_description;
} else {
$schedule_summary = $schedule_title;
//http://www.sunvisor.net/node/383
$schedule_from = ';VALUE=DATE:' . $schedule_date;
$schedule_to = ';VALUE=DATE:' . $schedule_date_tommorow;
$schedule_description = $schedule_title . " " . $schedule_description;
}
//http://www.sunvisor.net/node/383
$schedule_list[] = Array('id' => $schedule_id.$schedule_date,
'description' => $schedule_description,
'dtstart' => $schedule_from,
'dtend' => $schedule_to,
'summary' => $schedule_summary);
}
}
}
//ここから出力
header('Content-Type: text/calendar; charset=utf-8');
echo 'BEGIN:VCALENDAR'. "\n";
echo 'PRODID:' . PRODID. "\n";
echo 'VERSION:2.0'. "\n";
echo 'METHOD:PUBLISH'. "\n";
echo 'CALSCALE:GREGORIAN'. "\n";
echo 'X-WR-CALNAME:' . SCHEDULE_TITLE . "\n";
echo 'X-WR-CALDESC:' . SCHEDULE_TITLE . "\n";
echo 'X-WR-TIMEZONE:Asia/Tokyo'. "\n";
if ( !empty($schedule_list) ) {
foreach ( $schedule_list as $key => $vale ) {
echo 'BEGIN:VEVENT'. "\n";
echo 'UID:' . SCHEDULE_TITLE . '-' . $vale['id'] . "\n";
echo 'DESCRIPTION:' . $vale['description']. "\n";
//http://www.sunvisor.net/node/383
echo 'DTSTART;TZID=Asia/Tokyo' . $vale['dtstart'] . "\n";
echo 'DTEND;TZID=Asia/Tokyo' . $vale['dtend'] . "\n";
echo 'SUMMARY:'. $vale['summary']. "\n";
echo 'END:VEVENT'. "\n";
}
}
echo 'BEGIN:VTIMEZONE'. "\n";
echo 'TZID:Asia/Tokyo'. "\n";
echo 'BEGIN:STANDARD'. "\n";
echo 'DTSTART:19700101T000000'. "\n";
echo 'TZOFFSETFROM:+0900'. "\n";
echo 'TZOFFSETTO:+0900'. "\n";
echo 'END:STANDARD'. "\n";
echo 'END:VTIMEZONE'. "\n";
echo 'END:VCALENDAR'. "\n";
?>
以下の設定ファイルも同じディレクトリに配置する。
<?php
//GoogleカレンダーでアクセスさせるURLは
//http://hoge.hoge/このファイル名本体.ics
//となりますので、このファイル名は適宜変更ください。
define('CYBOZU_URL', 'http://xxxxxxxx.netvolante.jp/scripts/cbag/ag.exe'); //サイボウズのURL
define("LOGIN_ID", 'xxxxxxx'); //ログインIDxxxxxxx
define("LOGIN_PASS", 'yyyyyyy'); //ログインパス
define("UID", 'iiiiiiii'); //取得したいスケジュールのID(無い場合はログインユ
?>
このindex.phpをapacheなどで公開し、アクセスすると、icalをダウンロードすることができます。
・毎朝、crontabなどでこのURLにアクセスし、icalを取得します。
・念の為、今日の日付ファイルとし、過去分も含めて保存しています。
・dropboxにアップロードします。
#!/bin/sh
# cyb/cyb2cal.sh
# 2017/09/09
# Cybozu to ical for Google calender
# and Upload to Dropbox
#
wget -O adcal/adcyb.ical http://127.0.0.1/cyb/index.php
cp adcal/adcyb.ical adcal/adcyb-`date +\%Y\%m\%d\%H\%M\%S`.ical
# dropbox_uploader.sh upload adcal/adcyb.ical cal/adcyb.ical
dropbox_uploader.sh upload adcal/*.* cal/
少しうろ覚えなところもありますが、現存するものを記録のために公開します。