aboutsummaryrefslogtreecommitdiffstats
path: root/calendars/publish.php
blob: b3be15b0a65e266d311a0f236d0f37b1f086d91d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<?php

/*
Extension to PHP iCalendar for supporting publishing from Apple iCal
Date: 11.12.2003
Authors: Dietrich Ayala, Jo Rhett, Jim Hu
Copyright 2003 Dietrich Ayala

Description:
This allows iCal to publish to your PHP iCalendar site *without* WebDAV support.
This helps with commercial hosts where WebDAV is not available.

Features:
- supports publishing and deleting calendars
- does not require WebDAV

Installation:
1. place this file in your PHP iCalendar calendars directory (or anywhere else)
2. configure path to PHP iCalendar config file (below)
3. make sure that PHP has write access to the calendars directory (or whatever you set $calendar_path to)
4. set up directory security on your calendars directory
5. turn on publishing in your PHP iCalendar config file by setting $phpicalendar_publishing to 1.

Security:
The calendars directory should be configured to require authentication. 
This protects any private calendar data, and prevents unauthorized users
from updating or deleting your calendar data.

Three methods of HTTP authorization are supported.

1. Server-provided authentication - This can be done via any method supported by 
   your webserver. There is much documentation available on the web for doing 
   per-directory authentication for Apache.

2. PHP authentication against $auth_internal_username and $auth_internal_password.

 2a. using mod_php it just works.

 2b. If you can't configure the server for http authentication, and you are running
     PHP in CGI mode *AND* you have mod_rewrite enabled, then you should put the
     following lines in the .htaccess file in your directory:

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
</IfModule>

Usage (Apple iCal):
1. Open iCal, select a calendar for publishing
2. Select "Publish" from the "Calendar" menu
3. Configure to your liking, and set the URL to (eg): http://example.com/path/to/publish.php
4. Click the "Publish" button
5. Some PHP versions require a '?' at the end of the URL (eg): http://localhost/~dietricha/calendar/calendars/publish.php?

Usage (Sunbird Calendar):
1. Create a new calendar in Sunbird
	Type Remote
	Location http://example.com/path/to/publish.php/calendarname.ics
		calendarname.ics should be a unique filename and must end with .ics
	Username: either your web server username, or auth_internal_username 
	Password: either your web server password, or auth_internal_password 

Hints:
1. PHP 5.1.0 or greater is required
2. Your version of php and apache MUST support $_SERVER['PATH_INFO']
3. Depending on your web server environment, you may need to set safe_mode = Off
   (this won't be necessary if you are using a wrapper like cgiwrap or suexec) 

Troubleshooting:
You can turn on logging by setting the PHPICALENDAR_LOG_PUBLISHING constant to 1 below.
This will write out a log file to the same directory as this script.
Don't forget to turn off logging when done!!
*/

define('BASE', '../');
// include PHP iCalendar configuration variables
include_once(BASE.'functions/init.inc.php'); 

// allow/disallow publishing
$phpicalendar_publishing = isset($phpiCal_config->phpicalendar_publishing) ? $phpiCal_config->phpicalendar_publishing : 0;
define( 'PHPICALENDAR_PUBLISHING', $phpicalendar_publishing );
// only allow publishing if explicitly enabled
if(PHPICALENDAR_PUBLISHING != 1) {
	header('WWW-Authenticate: Basic realm="ERROR: Calendar Publishing is disabled on this server"');
	header('HTTP/1.1 401 Unauthorized');
	echo 'Calendar Publishing is disabled on this server!';
	exit;
}

// set calendar path, or just use current directory...make sure there's a trailing slash
if (isset($phpiCal_config->calendar_path) && $phpiCal_config->calendar_path != '') {
	if (substr($phpiCal_config->calendar_path, -1, 1) !='/') $calendar_path = $calendar_path.'/';
} else {
	$calendar_path = '';
}

// toggle logging
define( 'PHPICALENDAR_LOG_PUBLISHING', 1 );
if(defined('PHPICALENDAR_LOG_PUBLISHING') && PHPICALENDAR_LOG_PUBLISHING == 1) {
	if( ! $logfile = fopen('publish_log.txt','a+') ) {
		header('HTTP/1.1 401 Unauthorized');
		header('WWW-Authenticate: Basic realm="ERROR: Unable to open log file"');
		echo 'Unable to open log file.';
		exit;
	}
}

// Require authentication 
if (!isset($_SERVER['REMOTE_USER'])) {
	// Require authentication 
	if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
		list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])
			= explode( ':', base64_decode( substr($_SERVER['HTTP_AUTHORIZATION'], 6) ) );
	}
	if (!isset($_SERVER['PHP_AUTH_USER'])) {
		header('WWW-Authenticate: Basic realm="phpICalendar"');
		header('HTTP/1.1 401 Unauthorized');
		echo 'You must be authorized!';
		exit;
	} else {
		if ($_SERVER['PHP_AUTH_USER'] != $phpiCal_config->auth_internal_username || $_SERVER['PHP_AUTH_PW'] != $phpiCal_config->auth_internal_password) {
			header('WWW-Authenticate: Basic realm="phpICalendar"');
			header('HTTP/1.1 401 Unauthorized');
			echo 'You must be authorized!';
			exit;
		}
	}
}

switch ($_SERVER['REQUEST_METHOD']){
	// unpublishing
	case 'DELETE':
		// get calendar filename
		$calendar_file = $calendar_path.substr($_SERVER['REQUEST_URI'] , ( strrpos($_SERVER['REQUEST_URI'], '/') + 1) ) ;
		$calendar_file = urldecode($calendar_file);
		logmsg('received request to delete '.$calendar_file);
		// remove calendar file
		if(!unlink($calendar_file)){
			logmsg('unable to delete the calendar file');
		}else{
			logmsg('deleted');
		}
		break;
	// publishing
	case 'PUT':
		logmsg('PUT request');
		// get calendar data
		# php://input allows you to read raw POST data
		if($datain = fopen('php://input','r')){
			while(!@feof($datain)){
				$data .= fgets($datain,4096);
			}
			@fclose($datain);
		}else{
			logmsg('unable to read input data');
		}
		if(isset($data)){
			if (isset($_SERVER['PATH_INFO'])) {
				preg_match("/\/([\w\-\.\+ ]*).ics/i",$_SERVER['PATH_INFO'],$matches);
				$calendar_name = urldecode($matches[1]);
			}
			// If we don't have it from path info, use the supplied calendar name
			if( ! isset($calendar_name) ) {
				$cal_arr = explode("\n",$data);
				foreach($cal_arr as $k => $v){
					if(strstr($v,'X-WR-CALNAME:')){
						$arr = explode(':',$v);
						$calendar_name = trim($arr[1]);
						break;
					}
				}
			}
			logmsg('Received request to update: ' . $calendar_name);
			// Remove any invalid characters from the filename
			$calendar_name = preg_replace( "/[^\w\.\- ]/", '', $calendar_name );
			if( ( ! isset($calendar_name) ) || ( $calendar_name == '' ) ) {
				header('HTTP/1.1 401 Invalid calendar name');
				header('WWW-Authenticate: Basic realm="ERROR: Invalid calendar name."');
				echo 'Invalid calendar name.';
			}
			// If we don't have a name, assume default
			$calendar_name = isset($calendar_name) ? $calendar_name : 'default';
			logmsg('Updating calendar: ' . $calendar_name);
			// If this is Apple iCal, an event with a blank summary is private - mark as such
			if( preg_match( "/Apple.*iCal/", $_SERVER['HTTP_USER_AGENT'] ) ) {
				$data = preg_replace(
					"/^\s*SUMMARY:\s*$/m",
					"SUMMARY: **PRIVATE**\nCLASS:PRIVATE",
					$data
				);
			}
			// write to file
			if($dataout = fopen($calendar_path.$calendar_name.'.ics','w+')){
				fputs($dataout, $data, strlen($data) );
				@fclose($dataout);
			}else{
				logmsg( 'could not open file '.$calendar_path.$calendar_name.'.ics' );
			}

		}else {
			logmsg('PUT ERROR - No data supplied.');
		}
		break;
	case 'GET':
		if (isset($_SERVER['PATH_INFO'])) {
			preg_match("/\/([ A-Za-z0-9._]*).ics/i",$_SERVER['PATH_INFO'],$matches);
			$icsfile = urldecode($matches[1]);
	
			// get calendar data
			if (file_exists($calendar_path . $icsfile . '.ics') &&
				is_readable($calendar_path . $icsfile . '.ics') &&
				is_file($calendar_path . $icsfile . '.ics')
			) {
				echo file_get_contents($calendar_path . $icsfile . '.ics');
				logmsg('downloaded calendar ' . $icsfile);
			}
		}
}

if(defined('PHPICALENDAR_LOG_PUBLISHING') && PHPICALENDAR_LOG_PUBLISHING == 1) {
	fclose($logfile);
}

header('HTTP/1.1 200 OK');
exit;


// for logging
function logmsg($str){
	global $logfile;

	if(defined('PHPICALENDAR_LOG_PUBLISHING') && PHPICALENDAR_LOG_PUBLISHING == 1) {
		if( $_SERVER['PHP_AUTH_USER'] )
			$user =  $_SERVER['PHP_AUTH_USER'];
		else
			$user =  $_SERVER['REMOTE_USER'];

		$logline = date('Y-m-d H:i:s ') . $_SERVER['REMOTE_ADDR'] . ' ' . $user . ' ' . $str . "\n";

		fputs($logfile, $logline, strlen($logline) );
	}
}
?>

© 2014-2024 Faster IT GmbH | imprint | privacy policy