Completed
Push — master ( ea0e5d...10ff2a )
by mw
02:37
created

formats/vcard/SRF_vCard.php (12 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Create vCard exports
4
 * @file
5
 * @ingroup SemanticResultFormats
6
 */
7
8
/**
9
 * Printer class for creating vCard exports
10
 * 
11
 * @author Markus Krötzsch
12
 * @author Denny Vrandecic
13
 * @author Frank Dengler
14
 * 
15
 * @ingroup SemanticResultFormats
16
 * 
17
 * TODO: fix the insane case
18
 * TODO: make SRFvCardAddress constructor sane
19
 */
20
class SRFvCard extends SMWExportPrinter {
21
	
22
	protected $m_title = '';
23
	protected $m_description = '';
24
25
	/**
26
	 * @see SMWIExportPrinter::getMimeType
27
	 *
28
	 * @since 1.8
29
	 *
30
	 * @param SMWQueryResult $queryResult
31
	 *
32
	 * @return string
33
	 */
34
	public function getMimeType( SMWQueryResult $queryResult ) {
35
		return 'text/x-vcard';
36
	}
37
38
	/**
39
	 * @see SMWIExportPrinter::getFileName
40
	 *
41
	 * @since 1.8
42
	 *
43
	 * @param SMWQueryResult $queryResult
44
	 *
45
	 * @return string|boolean
46
	 */
47
	public function getFileName( SMWQueryResult $queryResult ) {
48
		if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) {
49
			return str_replace( ' ', '_', $this->getSearchLabel( SMW_OUTPUT_WIKI ) ) . '.vcf';
50
		} else {
51
			return 'vCard.vcf';
52
		}
53
	}
54
55
	public function getQueryMode( $context ) {
56
		return ( $context == SMWQueryProcessor::SPECIAL_PAGE ) ? SMWQuery::MODE_INSTANCES : SMWQuery::MODE_NONE;
57
	}
58
59
	public function getName() {
60
		return wfMessage( 'srf_printername_vcard' )->text();
61
	}
62
63
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
64
		global $wgSitename;
65
		$result = '';
66
		$items = array();
67
		if ( $outputmode == SMW_OUTPUT_FILE ) { // make vCard file
68
			if ( $this->m_title == '' ) {
69
				$this->m_title = $wgSitename;
70
			}
71
			$row = $res->getNext();
72
			while ( $row !== false ) {
73
				$wikipage = $row[0]->getResultSubject(); // get Subject of the Result
74
				// name
75
				$prefix = ''; // something like 'Dr.'
76
				$firstname = ''; // given name
77
				$additionalname = ''; // typically the "middle" name (second first name)
78
				$lastname = ''; // family name
79
				$suffix = ''; // things like "jun." or "sen."
80
				$fullname = ''; // the "formatted name", may be independent from first/lastname & co.
81
				// contacts
82
				$emails = array();
83
				$tels = array();
84
				$addresses = array();
85
				// organisational details:
86
				$organization = ''; // any string
87
				$jobtitle = '';
88
				$role = '';
89
				$department = '';
90
				// other stuff
91
				$category = '';
92
				$birthday = ''; // a date
93
				$url = ''; // homepage, a legal URL
94
				$note = ''; // any text
95
				$workaddress = false;
96
				$homeaddress = false;
97
98
				$workpostofficebox = '';
99
				$workextendedaddress = '';
100
				$workstreet = '';
101
				$worklocality = '';
102
				$workregion = '';
103
				$workpostalcode = '';
104
				$workcountry = '';
105
106
107
				$homepostofficebox = '';
108
				$homeextendedaddress = '';
109
				$homestreet = '';
110
				$homelocality = '';
111
				$homeregion = '';
112
				$homepostalcode = '';
113
				$homecountry = '';
114
115
				foreach ( $row as $field ) {
116
					// later we may add more things like a generic
117
					// mechanism to add non-standard vCard properties as well
118
					// (could include funny things like geo, description etc.)
119
					$req = $field->getPrintRequest();
120
					
121
					switch( strtolower( $req->getLabel() ) ) {
122
						case "name":
123
							$value = $field->getNextDataValue();
124
							if ( $value !== false ) {
125
								$fullname = $value->getShortWikiText();
126
							}
127
						break;
128
129
						case "prefix":
130
							while( $value = $field->getNextDataValue() ) {
131
								$prefix .= ( $prefix ? ',':'' ) . $value->getShortWikiText();
132
							}
133
						break;
134
135
						case "suffix":
136
							while( $value = $field->getNextDataValue() ) {
137
								$suffix .= ( $suffix ? ',':'' ) . $value->getShortWikiText();
138
							}
139
						break;
140
141
						case "firstname":
142
							$value = $field->getNextDataValue(); // save only the first
143
							if ( $value !== false ) {
144
								$firstname = $value->getShortWikiText();
145
							}
146
						break;
147
148
						case "extraname":
149
							while( $value = $field->getNextDataValue() ) {
150
								$additionalname .= ( $additionalname ? ',':'' ) . $value->getShortWikiText();
151
							}
152
						break;
153
154
						case "lastname":
155
							$value = $field->getNextDataValue(); // save only the first
156
							if ( $value !== false ) {
157
								$lastname = $value->getShortWikiText();
158
							}
159
						break;
160
161
						case "note":
162
							while( $value = $field->getNextDataValue() ) {
163
								$note .= ( $note ? ', ':'' ) . $value->getShortWikiText();
164
							}
165
						break;
166
167
						case "email":
168
							while( $value = $field->getNextDataValue() ) {
169
								$emails[] = new SRFvCardEmail( 'internet', $value->getShortWikiText() );
170
							}
171
					 	break;
172
173
						case "workphone":
174
							while( $value = $field->getNextDataValue() ) {
175
								$tels[] = new SRFvCardTel( 'WORK', $value->getShortWikiText() );
176
							}
177
					 	break;
178
179
						case "cellphone":
180
							while( $value = $field->getNextDataValue() ) {
181
								$tels[] = new SRFvCardTel( 'CELL', $value->getShortWikiText() );
182
							}
183
						break;
184
185
						case "homephone":
186
							while( $value = $field->getNextDataValue() ) {
187
								$tels[] = new SRFvCardTel( 'HOME', $value->getShortWikiText() );
188
							}
189
						break;
190
191
						case "organization":
192
							$value = $field->getNextDataValue();
193
							if ( $value !== false ) {
194
								$organization = $value->getShortWikiText();
195
							}
196
						break;
197
198
						case "workpostofficebox":
199
							$value = $field->getNextDataValue();
200
							if ( $value !== false ) {
201
								$workpostofficebox = $value->getShortWikiText();
202
								$workaddress = true;
203
							}
204
						break;
205
206
						case "workextendedaddress":
207
							$value = $field->getNextDataValue();
208
							if ( $value !== false ) {
209
								$workextendedaddress = $value->getShortWikiText();
210
								$workaddress = true;
211
							}
212
						break;
213
214
						case "workstreet":
215
							$value = $field->getNextDataValue();
216
							if ( $value !== false ) {
217
								$workstreet = $value->getShortWikiText();
218
								$workaddress = true;
219
							}
220
						break;
221
222
						case "worklocality":
223
							$value = $field->getNextDataValue();
224
							if ( $value !== false ) {
225
								$worklocality = $value->getShortWikiText();
226
								$workaddress = true;
227
							}
228
						break;
229
230
						case "workregion":
231
							$value = $field->getNextDataValue();
232
							if ( $value !== false ) {
233
								$workregion = $value->getShortWikiText();
234
								$workaddress = true;
235
							}
236
						break;
237
238
						case "workpostalcode":
239
							$value = $field->getNextDataValue();
240
							if ( $value !== false ) {
241
								$workpostalcode = $value->getShortWikiText();
242
								$workaddress = true;
243
							}
244
						break;
245
246
						case "workcountry":
247
							$value = $field->getNextDataValue();
248
							if ( $value !== false ) {
249
								$workcountry = $value->getShortWikiText();
250
								$workaddress = true;
251
							}
252
						break;
253
254
						case "homepostofficebox":
255
							$value = $field->getNextDataValue();
256
							if ( $value !== false ) {
257
								$homepostofficebox = $value->getShortWikiText();
258
								$homeaddress = true;
259
							}
260
						break;
261
262
						case "homeextendedaddress":
263
							$value = $field->getNextDataValue();
264
							if ( $value !== false ) {
265
								$homeextendedaddress = $value->getShortWikiText();
266
								$homeaddress = true;
267
							}
268
						break;
269
270
						case "homestreet":
271
							$value = $field->getNextDataValue();
272
							if ( $value !== false ) {
273
								$homestreet = $value->getShortWikiText();
274
								$homeaddress = true;
275
							}
276
						break;
277
278
						case "homelocality":
279
							$value = $field->getNextDataValue();
280
							if ( $value !== false ) {
281
								$homelocality = $value->getShortWikiText();
282
								$homeaddress = true;
283
							}
284
						break;
285
286
						case "homeregion":
287
							$value = $field->getNextDataValue();
288
							if ( $value !== false ) {
289
								$homeregion = $value->getShortWikiText();
290
								$homeaddress = true;
291
							}
292
						break;
293
294
						case "homepostalcode":
295
							$value = $field->getNextDataValue();
296
							if ( $value !== false ) {
297
								$homepostalcode = $value->getShortWikiText();
298
								$homeaddress = true;
299
							}
300
						break;
301
302
						case "homecountry":
303
							$value = $field->getNextDataValue();
304
							if ( $value !== false ) {
305
								$homecountry = $value->getShortWikiText();
306
								$homeaddress = true;
307
							}
308
						break;
309
310
						case "birthday":
311
							if ( $req->getTypeID() == "_dat" )  {
312
								$value = $field->getNextDataValue();
313
								if ( $value !== false ) {
314
									$birthday =  $value->getXMLSchemaDate();
315
								}
316
							}
317
						break;
318
319
						case "homepage":
320
							if ( $req->getTypeID() == "_uri" )  {
321
								$value = $field->getNextDataValue();
322
								if ( $value !== false ) {
323
									$url =  $value->getWikiValue();
324
								}
325
							}
326
						break;
327
					}
328
				}
329
				$pagetitle = $wikipage->getTitle();
330
				if ( $workaddress ) $addresses[] = new SRFvCardAddress ( 'WORK', $workpostofficebox, $workextendedaddress, $workstreet, $worklocality, $workregion, $workpostalcode, $workcountry );
331
				if ( $homeaddress ) $addresses[] = new SRFvCardAddress ( 'HOME', $homepostofficebox, $homeextendedaddress, $homestreet, $homelocality, $homeregion, $homepostalcode, $homecountry );
332
				$items[] = new SRFvCardEntry( $pagetitle, $prefix, $firstname, $lastname, $additionalname, $suffix, $fullname, $tels, $addresses, $emails, $birthday, $jobtitle, $role, $organization, $department, $category, $url, $note );
333
            	$row = $res->getNext();
334
			}
335
            foreach ( $items as $item ) {
336
				$result .= $item->text();
337
			}
338
		} else { // just make link to vcard
339
			if ( $this->getSearchLabel( $outputmode ) ) {
340
				$label = $this->getSearchLabel( $outputmode );
341
			} else {
342
				$label = wfMessage( 'srf_vcard_link' )->inContentLanguage()->text();
343
			}
344
			$link = $res->getQueryLink( $label );
345
			$link->setParameter( 'vcard', 'format' );
346
			if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) {
347
				$link->setParameter( $this->getSearchLabel( SMW_OUTPUT_WIKI ), 'searchlabel' );
348
			}
349
			if ( array_key_exists( 'limit', $this->m_params ) ) {
350
				$link->setParameter( $this->m_params['limit'], 'limit' );
351
			} else { // use a reasonable default limit
352
				$link->setParameter( 20, 'limit' );
353
			}
354
			$result .= $link->getText( $outputmode, $this->mLinker );
355
			$this->isHTML = ( $outputmode == SMW_OUTPUT_HTML ); // yes, our code can be viewed as HTML if requested, no more parsing needed
356
		}
357
		return $result;
358
	}
359
}
360
361
/**
362
 * Represents a single entry in an vCard
363
 * @ingroup SemanticResultFormats
364
 */
365
class SRFvCardEntry {
366
	private $uri;
367
	private $label;
368
	private $fullname;
369
	private $firstname;
370
	private $lastname;
371
	private $additionalname;
372
	private $prefix;
373
	private $suffix;
374
	private $tels = array();
375
	private $addresses = array();
376
	private $emails = array();
377
	private $birthday;
378
	private $dtstamp;
379
	private $title;
380
	private $role;
381
	private $organization;
382
	private $department;
383
	private $category;
384
	private $note;
385
386
	/**
387
	 * Constructor for a single item in the vcard. Requires the URI of the item.
388
	 */
389
	public function __construct( Title $t, $prefix, $firstname, $lastname, $additionalname, $suffix, $fullname, $tels, $addresses, $emails, $birthday, $jobtitle, $role, $organization, $department, $category, $url, $note ) {
390
		$this->uri = $t->getFullURL();
391
		$this->url = $url;
392
		// read fullname or guess it in a simple way from other names that are given
393
		if ( $fullname != '' ) {
394
			$this->label = $fullname;
395
		} elseif ( $firstname . $lastname != '' ) {
396
			$this->label = $firstname . ( ( ( $firstname != '' ) && ( $lastname != '' ) ) ? ' ':'' ) .  $lastname;
397
		} else {
398
			$this->label = $t->getText();
399
		}
400
		$this->label = SRFVCardEntry::vCardEscape( $this->label );
401
		// read firstname and lastname, or guess it from other names that are given
402
		if ( $firstname . $lastname == '' ) { // guessing needed
403
			$nameparts = explode( ' ', $this->label );
404
			// Accepted forms for guessing:
405
			// "Lastname"
406
			// "Firstname Lastname"
407
			// "Firstname <Additionalnames> Lastname"
408
			$this->lastname = SRFvCardEntry::vCardEscape( array_pop( $nameparts ) );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
409
			if ( count( $nameparts ) > 0 ) $this->firstname = SRFvCardEntry::vCardEscape( array_shift( $nameparts ) );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
410
			foreach ( $nameparts as $name ) {
411
				$this->additionalname .= ( $this->additionalname != '' ? ',':'' ) . SRFvCardEntry::vCardEscape( $name );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
412
			}
413
		} else {
414
			$this->firstname = SRFvCardEntry::vCardEscape( $firstname );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
415
			$this->lastname = SRFvCardEntry::vCardEscape( $lastname );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
416
		}
417
		if ( $additionalname != '' ) $this->additionalname = $additionalname; // no escape, can be a value list
418
			// ^ overwrite above guessing in that case
419
		$this->prefix = SRFvCardEntry::vCardEscape( $prefix );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
420
		$this->suffix = SRFvCardEntry::vCardEscape( $suffix );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
421
		$this->tels = $tels;
422
		$this->addresses = $addresses;
423
		$this->emails = $emails;
424
		$this->birthday = $birthday;
425
		$this->title = SRFvCardEntry::vCardEscape( $jobtitle );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
426
		$this->role = SRFvCardEntry::vCardEscape( $role );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
427
		$this->organization = SRFvCardEntry::vCardEscape( $organization );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
428
		$this->department = SRFvCardEntry::vCardEscape( $department );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
429
		$this->category = $category; // allow non-escaped "," in here for making a list of categories
430
		$this->note = SRFvCardEntry::vCardEscape( $note );
0 ignored issues
show
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
431
432
		$article = new Article( $t );
433
		$this->dtstamp  = $article->getTimestamp();
434
	}
435
436
437
	/**
438
	 * Creates the vCard output for a single item.
439
	 * 
440
	 * CAUTION: this might hurt your eyes
441
	 */
442
	public function text() {
443
		$text  = "BEGIN:VCARD\r\n";
444
		$text .= "VERSION:3.0\r\n";
445
		// N and FN are required properties in vCard 3.0, we need to write something there
446
		$text .= "N;CHARSET=UTF-8:$this->lastname;$this->firstname;$this->additionalname;$this->prefix;$this->suffix\r\n";
447
		$text .= "FN;CHARSET=UTF-8:$this->label\r\n";
448
		// heuristic for setting confidentiality level of vCard:
449
		global $wgGroupPermissions;
450
		if ( ( array_key_exists( '*', $wgGroupPermissions ) ) &&
451
		     ( array_key_exists( 'read', $wgGroupPermissions['*'] ) ) ) {
452
			$public = $wgGroupPermissions['*']['read'];
453
		} else {
454
			$public = true;
455
		}
456
		$text .= ( $public ? 'CLASS:PUBLIC':'CLASS:CONFIDENTIAL' ) . "\r\n";
457
		if ( $this->birthday !== "" ) $text .= "BDAY:$this->birthday\r\n";
458
		if ( $this->title !== "" ) $text .= "TITLE;CHARSET=UTF-8:$this->title\r\n";
459
		if ( $this->role !== "" ) $text .= "ROLE;CHARSET=UTF-8:$this->role\r\n";
460
		if ( $this->organization !== "" ) $text .= "ORG;CHARSET=UTF-8:$this->organization;$this->department\r\n";
461
		if ( $this->category !== "" ) $text .= "CATEGORIES;CHARSET=UTF-8:$this->category\r\n";
462
		foreach ( $this->emails as $entry ) $text .= $entry->createVCardEmailText();
463
		foreach ( $this->addresses as $entry ) $text .= $entry->createVCardAddressText();
464
		foreach ( $this->tels as $entry ) $text .= $entry->createVCardTelText();
465
		if ( $this->note !== "" ) $text .= "NOTE;CHARSET=UTF-8:$this->note\r\n";
466
		$text .= "SOURCE;CHARSET=UTF-8:$this->uri\r\n";
467
		$text .= "PRODID:-////Semantic MediaWiki\r\n";
468
		$text .= "REV:$this->dtstamp\r\n";
469
		$text .= "URL:" . ( $this->url ? $this->url:$this->uri ) . "\r\n";
470
		$text .= "UID:$this->uri\r\n";
471
		$text .= "END:VCARD\r\n";
472
		return $text;
473
	}
474
475
	public static function vCardEscape( $text ) {
476
		return str_replace( array( '\\', ',', ':', ';' ), array( '\\\\', '\,', '\:', '\;' ), $text );
477
	}
478
479
}
480
481
/**
482
 * Represents a single address entry in an vCard entry.
483
 * @ingroup SemanticResultFormats
484
 */
485
class SRFvCardAddress {
486
	private $type;
487
	private $postofficebox;
488
	private $extendedaddress;
489
	private $street;
490
	private $locality;
491
	private $region;
492
	private $postalcode;
493
	private $country;
494
495
	/**
496
	 * Constructor for a single address item in the vcard item.
497
	 */
498
	public function __construct( $type, $postofficebox, $extendedaddress, $street, $locality, $region, $postalcode, $country ) {
499
		$this->type = $type;
500
		$this->postofficebox = SRFvCardEntry::vCardEscape( $postofficebox );
501
		$this->extendedaddress = SRFvCardEntry::vCardEscape( $extendedaddress );
502
		$this->street = SRFvCardEntry::vCardEscape( $street );
503
		$this->locality = SRFvCardEntry::vCardEscape( $locality );
504
		$this->region = SRFvCardEntry::vCardEscape( $region );
505
		$this->postalcode = SRFvCardEntry::vCardEscape( $postalcode );
506
		$this->country = SRFvCardEntry::vCardEscape( $country );
507
	}
508
509
	/**
510
	 * Creates the vCard output for a single address item.
511
	 */
512
	public function createVCardAddressText() {
513
		if ( $this->type == "" ) $this->type = "work";
514
		$text  =  "ADR;TYPE=$this->type;CHARSET=UTF-8:$this->postofficebox;$this->extendedaddress;$this->street;$this->locality;$this->region;$this->postalcode;$this->country\r\n";
515
		return $text;
516
	}
517
}
518
519
/**
520
 * Represents a single telephone entry in an vCard entry.
521
 * @ingroup SemanticResultFormats
522
 */
523
class SRFvCardTel {
524
	private $type;
525
	private $telnumber;
526
527
	/**
528
	 * Constructor for a single telephone item in the vcard item.
529
	 */
530
	public function __construct( $type, $telnumber ) {
531
		$this->type = $type;  // may be a vCard value list using ",", no escaping
532
		$this->telnumber = SRFvCardEntry::vCardEscape( $telnumber ); // escape to be sure
533
	}
534
535
	/**
536
	 * Creates the vCard output for a single telephone item.
537
	 */
538
	public function createVCardTelText() {
539
		if ( $this->type == "" ) $this->type = "work";
540
		$text  =  "TEL;TYPE=$this->type:$this->telnumber\r\n";
541
		return $text;
542
	}
543
}
544
545
/**
546
 * Represents a single email entry in an vCard entry.
547
 * @ingroup SemanticResultFormats
548
 */
549
class SRFvCardEmail {
550
	private $type;
551
	private $emailaddress;
552
553
	/**
554
	 * Constructor for a email telephone item in the vcard item.
555
	 */
556
	public function __construct( $type, $emailaddress ) {
557
		$this->type = $type;
558
		$this->emailaddress = $emailaddress; // no escape, normally not needed anyway
559
	}
560
561
	/**
562
	 * Creates the vCard output for a single email item.
563
	 */
564
	public function createVCardEmailText() {
565
		if ( $this->type == "" ) $this->type = "internet";
566
		$text  =  "EMAIL;TYPE=$this->type:$this->emailaddress\r\n";
567
		return $text;
568
	}
569
}
570