leilukin-tumbleblog/includes/lib/AtomFeed.php

345 lines
9.5 KiB
PHP

<?php
/**
* Class: AtomFeed
* Generates an Atom feed piece by piece.
*
* See Also:
* https://tools.ietf.org/html/rfc4287
*/
class AtomFeed implements FeedGenerator {
# Boolean: $open
# Has the feed been opened?
protected $open = false;
# Variable: $count
# The number of entries generated.
protected $count = 0;
# Array: $xml
# Holds the feed as an array.
protected $xml = array();
/**
* Function: type
* Returns the content type of the feed.
*/
public static function type(): string {
return "application/atom+xml";
}
/**
* Function: open
* Adds the opening feed element and top-level elements.
*
* Parameters:
* $title - Title for this feed.
* $subtitle - Subtitle (optional).
* $id - Feed ID (optional).
* $updated - Time of update (optional).
*/
public function open(
$title,
$subtitle = "",
$id = "",
$updated = null
): bool {
if ($this->open)
return false;
$this->open = true;
$language = lang_base(Config::current()->locale);
$feed = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
$feed.= '<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="'.
fix($language, true).'">'.
"\n";
$feed.= '<title>'.fix($title).'</title>'."\n";
if (!empty($subtitle))
$feed.= '<subtitle>'.fix($subtitle).'</subtitle>'."\n";
$feed.= '<id>'.fix(oneof($id, self_url())).'</id>'."\n";
$feed.= '<updated>'.
when(DATE_ATOM, oneof($updated, time())).
'</updated>'.
"\n";
$feed.= '<link href="'.
self_url().
'" rel="self" type="application/atom+xml" />'.
"\n";
$feed.= '<generator uri="http://chyrplite.net/" version="'.
CHYRP_VERSION.
'">'.
CHYRP_IDENTITY.
'</generator>'.
"\n";
$this->xml = array(
"feed" => $feed,
"items" => array()
);
return $this->open = true;
}
/**
* Function: entry
* Adds an individual feed entry.
*
* Parameters:
* $title - Title for this entry.
* $id - The unique ID.
* $content - Content for this entry.
* $link - The URL to the resource.
* $published - Time of creation.
* $updated - Time of update (optional).
* $name - Name of the author (optional).
* $uri - URI of the author (optional).
* $email - Email address of the author (optional).
*
* Notes:
* The entry remains open to allow triggered insertions.
*/
public function entry(
$title,
$id,
$content,
$link,
$published,
$updated = null,
$name = "",
$uri = "",
$email = ""
): bool {
if (!$this->open)
return false;
$this->count++;
$entry = '<title type="html">'.
fix($title, false, true).
'</title>'.
"\n";
$entry.= '<id>'.fix($id).'</id>'."\n";
$entry.= '<updated>'.
when(DATE_ATOM, oneof($updated, $published)).
'</updated>'.
"\n";
$entry.= '<published>'.
when(DATE_ATOM, $published).
'</published>'.
"\n";
$entry.= '<link rel="alternate" type="text/html" href="'.
fix($link, true).
'" />'.
"\n";
$entry.= '<author>'."\n";
$entry.= '<name>'.
fix(oneof($name, __("Guest"))).
'</name>'.
"\n";
if (!empty($uri) and is_url($uri))
$entry.= '<uri>'.fix($uri).'</uri>'."\n";
if (!empty($email) and is_email($email))
$entry.= '<email>'.fix($email).'</email>'."\n";
$entry.= '</author>'."\n";
$entry.= '<content type="html">'.
fix($content, false, true).
'</content>'.
"\n";
$item = $this->count - 1;
$this->xml["items"][$item] = $entry;
return true;
}
/**
* Function: category
* Adds a category element for an entry or feed.
*
* Parameters:
* $term - String that identifies the category.
* $scheme - URI for the categorization scheme (optional).
* $label - Human-readable label for the category (optional).
*/
public function category(
$term,
$scheme = "",
$label = ""
): bool {
if (!$this->open)
return false;
$category = '<category term="'.
fix($term, true).
'"';
if (!empty($scheme))
$category.= ' scheme="'.fix($scheme, true).'"';
if (!empty($label))
$category.= ' label="'.fix($label, true).'"';
$category.= ' />'."\n";
if (!$this->count) {
$this->xml["feed"].= $category;
} else {
$item = $this->count - 1;
$this->xml["items"][$item].= $category;
}
return true;
}
/**
* Function: rights
* Adds a rights element for an entry or feed.
*
* Parameters:
* $text - Human-readable licensing information.
*/
public function rights(
$text
): bool {
if (!$this->open)
return false;
$rights = '<rights>'.
fix($text, false, true).
'</rights>'.
"\n";
if (!$this->count) {
$this->xml["feed"].= $rights;
} else {
$item = $this->count - 1;
$this->xml["items"][$item].= $rights;
}
return true;
}
/**
* Function: enclosure
* Adds a link element for a resource that is potentially large in size.
*
* Parameters:
* $link - The URL to the resource.
* $length - Size in bytes of the resource (optional).
* $type - The media type of the resource (optional).
* $title - Title for the resource (optional).
*/
public function enclosure(
$link,
$length = null,
$type = "",
$title = ""
): bool {
if (!$this->open)
return false;
$enclosure = '<link rel="enclosure" href="'.
fix($link, true).
'"';
if (!empty($length))
$enclosure.= ' length="'.fix($length, true).'"';
if (!empty($type))
$enclosure.= ' type="'.fix($type, true).'"';
if (!empty($title))
$enclosure.= ' title="'.fix($title, true).'"';
$enclosure.= ' />'."\n";
if (!$this->count) {
$this->xml["feed"].= $enclosure;
} else {
$item = $this->count - 1;
$this->xml["items"][$item].= $enclosure;
}
return true;
}
/**
* Function: related
* Adds a link element for a resource related to an entry or feed.
*
* Parameters:
* $link - The URL to the resource.
*/
public function related(
$link
): bool {
if (!$this->open)
return false;
if (empty($link) or !is_url($link))
return false;
$related = '<link rel="related" href="'.
fix($link, true).
'" />'.
"\n";
if (!$this->count) {
$this->xml["feed"].= $related;
} else {
$item = $this->count - 1;
$this->xml["items"][$item].= $related;
}
return true;
}
/**
* Function: feed
* Returns the generated feed.
*/
public function feed(): string {
$feed = $this->xml["feed"];
$items = $this->xml["items"];
foreach ($items as $item) {
$feed.= '<entry>'."\n".
$item.
'</entry>'."\n";
}
$feed.= '</feed>'."\n";
return $feed;
}
/**
* Function: output
* Displays the generated feed.
*/
public function display(): bool {
if (headers_sent())
return false;
header("Content-Type: ".self::type()."; charset=UTF-8");
echo $this->feed();
return true;
}
}