forked from Chaospott/site
added a few articles, added media
This commit is contained in:
5
_site/tmp/var/www/chaospott.de/engine/Hook.php
Normal file
5
_site/tmp/var/www/chaospott.de/engine/Hook.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
abstract class Hook
|
||||
{
|
||||
abstract public function doHook(Post $post);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
PHP Markdown & Extra
|
||||
Copyright (c) 2004-2009 Michel Fortin
|
||||
<http://michelf.com/>
|
||||
All rights reserved.
|
||||
|
||||
Based on Markdown
|
||||
Copyright (c) 2003-2006 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name "Markdown" nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as
|
||||
is" and any express or implied warranties, including, but not limited
|
||||
to, the implied warranties of merchantability and fitness for a
|
||||
particular purpose are disclaimed. In no event shall the copyright owner
|
||||
or contributors be liable for any direct, indirect, incidental, special,
|
||||
exemplary, or consequential damages (including, but not limited to,
|
||||
procurement of substitute goods or services; loss of use, data, or
|
||||
profits; or business interruption) however caused and on any theory of
|
||||
liability, whether in contract, strict liability, or tort (including
|
||||
negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
@ -0,0 +1,786 @@
|
||||
PHP Markdown Extra
|
||||
==================
|
||||
|
||||
Version 1.2.4 - Sat 10 Oct 2009
|
||||
|
||||
by Michel Fortin
|
||||
<http://michelf.com/>
|
||||
|
||||
based on Markdown by John Gruber
|
||||
<http://daringfireball.net/>
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is a special version of PHP Markdown with extra features. See
|
||||
<http://michelf.com/projects/php-markdown/extra/> for details.
|
||||
|
||||
Markdown is a text-to-HTML conversion tool for web writers. Markdown
|
||||
allows you to write using an easy-to-read, easy-to-write plain text
|
||||
format, then convert it to structurally valid XHTML (or HTML).
|
||||
|
||||
"Markdown" is two things: a plain text markup syntax, and a software
|
||||
tool, written in Perl, that converts the plain text markup to HTML.
|
||||
PHP Markdown is a port to PHP of the original Markdown program by
|
||||
John Gruber.
|
||||
|
||||
PHP Markdown can work as a plug-in for WordPress and bBlog, as a
|
||||
modifier for the Smarty templating engine, or as a remplacement for
|
||||
textile formatting in any software that support textile.
|
||||
|
||||
Full documentation of Markdown's syntax is available on John's
|
||||
Markdown page: <http://daringfireball.net/projects/markdown/>
|
||||
|
||||
|
||||
Installation and Requirement
|
||||
----------------------------
|
||||
|
||||
PHP Markdown requires PHP version 4.0.5 or later.
|
||||
|
||||
|
||||
### WordPress ###
|
||||
|
||||
PHP Markdown works with [WordPress][wp], version 1.2 or later.
|
||||
|
||||
[wp]: http://wordpress.org/
|
||||
|
||||
1. To use PHP Markdown with WordPress, place the "makrdown.php" file
|
||||
in the "plugins" folder. This folder is located inside
|
||||
"wp-content" at the root of your site:
|
||||
|
||||
(site home)/wp-content/plugins/
|
||||
|
||||
2. Activate the plugin with the administrative interface of
|
||||
WordPress. In the "Plugins" section you will now find Markdown.
|
||||
To activate the plugin, click on the "Activate" button on the
|
||||
same line than Markdown. Your entries will now be formatted by
|
||||
PHP Markdown.
|
||||
|
||||
3. To post Markdown content, you'll first have to disable the
|
||||
"visual" editor in the User section of WordPress.
|
||||
|
||||
You can configure PHP Markdown to not apply to the comments on your
|
||||
WordPress weblog. See the "Configuration" section below.
|
||||
|
||||
It is not possible at this time to apply a different set of
|
||||
filters to different entries. All your entries will be formated by
|
||||
PHP Markdown. This is a limitation of WordPress. If your old entries
|
||||
are written in HTML (as opposed to another formatting syntax, like
|
||||
Textile), they'll probably stay fine after installing Markdown.
|
||||
|
||||
|
||||
### bBlog ###
|
||||
|
||||
PHP Markdown also works with [bBlog][bb].
|
||||
|
||||
[bb]: http://www.bblog.com/
|
||||
|
||||
To use PHP Markdown with bBlog, rename "markdown.php" to
|
||||
"modifier.markdown.php" and place the file in the "bBlog_plugins"
|
||||
folder. This folder is located inside the "bblog" directory of
|
||||
your site, like this:
|
||||
|
||||
(site home)/bblog/bBlog_plugins/modifier.markdown.php
|
||||
|
||||
Select "Markdown" as the "Entry Modifier" when you post a new
|
||||
entry. This setting will only apply to the entry you are editing.
|
||||
|
||||
|
||||
### Replacing Textile in TextPattern ###
|
||||
|
||||
[TextPattern][tp] use [Textile][tx] to format your text. You can
|
||||
replace Textile by Markdown in TextPattern without having to change
|
||||
any code by using the *Texitle Compatibility Mode*. This may work
|
||||
with other software that expect Textile too.
|
||||
|
||||
[tx]: http://www.textism.com/tools/textile/
|
||||
[tp]: http://www.textpattern.com/
|
||||
|
||||
1. Rename the "markdown.php" file to "classTextile.php". This will
|
||||
make PHP Markdown behave as if it was the actual Textile parser.
|
||||
|
||||
2. Replace the "classTextile.php" file TextPattern installed in your
|
||||
web directory. It can be found in the "lib" directory:
|
||||
|
||||
(site home)/textpattern/lib/
|
||||
|
||||
Contrary to Textile, Markdown does not convert quotes to curly ones
|
||||
and does not convert multiple hyphens (`--` and `---`) into en- and
|
||||
em-dashes. If you use PHP Markdown in Textile Compatibility Mode, you
|
||||
can solve this problem by installing the "smartypants.php" file from
|
||||
[PHP SmartyPants][psp] beside the "classTextile.php" file. The Textile
|
||||
Compatibility Mode function will use SmartyPants automatically without
|
||||
further modification.
|
||||
|
||||
[psp]: http://michelf.com/projects/php-smartypants/
|
||||
|
||||
|
||||
### In Your Own Programs ###
|
||||
|
||||
You can use PHP Markdown easily in your current PHP program. Simply
|
||||
include the file and then call the Markdown function on the text you
|
||||
want to convert:
|
||||
|
||||
include_once "markdown.php";
|
||||
$my_html = Markdown($my_text);
|
||||
|
||||
If you wish to use PHP Markdown with another text filter function
|
||||
built to parse HTML, you should filter the text *after* the Markdown
|
||||
function call. This is an example with [PHP SmartyPants][psp]:
|
||||
|
||||
$my_html = SmartyPants(Markdown($my_text));
|
||||
|
||||
|
||||
### With Smarty ###
|
||||
|
||||
If your program use the [Smarty][sm] template engine, PHP Markdown
|
||||
can now be used as a modifier for your templates. Rename "markdown.php"
|
||||
to "modifier.markdown.php" and put it in your smarty plugins folder.
|
||||
|
||||
[sm]: http://smarty.php.net/
|
||||
|
||||
If you are using MovableType 3.1 or later, the Smarty plugin folder is
|
||||
located at `(MT CGI root)/php/extlib/smarty/plugins`. This will allow
|
||||
Markdown to work on dynamic pages.
|
||||
|
||||
|
||||
### Updating Markdown in Other Programs ###
|
||||
|
||||
Many web applications now ship with PHP Markdown, or have plugins to
|
||||
perform the conversion to HTML. You can update PHP Markdown -- or
|
||||
replace it with PHP Markdown Extra -- in many of these programs by
|
||||
swapping the old "markdown.php" file for the new one.
|
||||
|
||||
Here is a short non-exhaustive list of some programs and where they
|
||||
hide the "markdown.php" file.
|
||||
|
||||
| Program | Path to Markdown
|
||||
| ------- | ----------------
|
||||
| [Pivot][] | `(site home)/pivot/includes/markdown/`
|
||||
|
||||
If you're unsure if you can do this with your application, ask the
|
||||
developer, or wait for the developer to update his application or
|
||||
plugin with the new version of PHP Markdown.
|
||||
|
||||
[Pivot]: http://pivotlog.net/
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
By default, PHP Markdown produces XHTML output for tags with empty
|
||||
elements. E.g.:
|
||||
|
||||
<br />
|
||||
|
||||
Markdown can be configured to produce HTML-style tags; e.g.:
|
||||
|
||||
<br>
|
||||
|
||||
To do this, you must edit the "MARKDOWN_EMPTY_ELEMENT_SUFFIX"
|
||||
definition below the "Global default settings" header at the start of
|
||||
the "markdown.php" file.
|
||||
|
||||
|
||||
### WordPress-Specific Settings ###
|
||||
|
||||
By default, the Markdown plugin applies to both posts and comments on
|
||||
your WordPress weblog. To deactivate one or the other, edit the
|
||||
`MARKDOWN_WP_POSTS` or `MARKDOWN_WP_COMMENTS` definitions under the
|
||||
"WordPress settings" header at the start of the "markdown.php" file.
|
||||
|
||||
|
||||
Bugs
|
||||
----
|
||||
|
||||
To file bug reports please send email to:
|
||||
<michel.fortin@michelf.com>
|
||||
|
||||
Please include with your report: (1) the example input; (2) the output you
|
||||
expected; (3) the output PHP Markdown actually produced.
|
||||
|
||||
|
||||
Version History
|
||||
---------------
|
||||
|
||||
1.0.1n (10 Oct 2009):
|
||||
|
||||
* Enabled reference-style shortcut links. Now you can write reference-style
|
||||
links with less brakets:
|
||||
|
||||
This is [my website].
|
||||
|
||||
[my website]: http://example.com/
|
||||
|
||||
This was added in the 1.0.2 betas, but commented out in the 1.0.1 branch,
|
||||
waiting for the feature to be officialized. [But half of the other Markdown
|
||||
implementations are supporting this syntax][half], so it makes sense for
|
||||
compatibility's sake to allow it in PHP Markdown too.
|
||||
|
||||
[half]: http://babelmark.bobtfish.net/?markdown=This+is+%5Bmy+website%5D.%0D%0A%09%09%0D%0A%5Bmy+website%5D%3A+http%3A%2F%2Fexample.com%2F%0D%0A&src=1&dest=2
|
||||
|
||||
* Now accepting many valid email addresses in autolinks that were
|
||||
previously rejected, such as:
|
||||
|
||||
<abc+mailbox/department=shipping@example.com>
|
||||
<!#$%&'*+-/=?^_`.{|}~@example.com>
|
||||
<"abc@def"@example.com>
|
||||
<"Fred Bloggs"@example.com>
|
||||
<jsmith@[192.0.2.1]>
|
||||
|
||||
* Now accepting spaces in URLs for inline and reference-style links. Such
|
||||
URLs need to be surrounded by angle brakets. For instance:
|
||||
|
||||
[link text](<http://url/with space> "optional title")
|
||||
|
||||
[link text][ref]
|
||||
[ref]: <http://url/with space> "optional title"
|
||||
|
||||
There is still a quirk which may prevent this from working correctly with
|
||||
relative URLs in inline-style links however.
|
||||
|
||||
* Fix for adjacent list of different kind where the second list could
|
||||
end as a sublist of the first when not separated by an empty line.
|
||||
|
||||
* Fixed a bug where inline-style links wouldn't be recognized when the link
|
||||
definition contains a line break between the url and the title.
|
||||
|
||||
* Fixed a bug where tags where the name contains an underscore aren't parsed
|
||||
correctly.
|
||||
|
||||
* Fixed some corner-cases mixing underscore-ephasis and asterisk-emphasis.
|
||||
|
||||
|
||||
Extra 1.2.4:
|
||||
|
||||
* Fixed a problem where unterminated tags in indented code blocks could
|
||||
prevent proper escaping of characaters in the code block.
|
||||
|
||||
|
||||
Extra 1.2.3 (31 Dec 2008):
|
||||
|
||||
* In WordPress pages featuring more than one post, footnote id prefixes are
|
||||
now automatically applied with the current post ID to avoid clashes
|
||||
between footnotes belonging to different posts.
|
||||
|
||||
* Fix for a bug introduced in Extra 1.2 where block-level HTML tags where
|
||||
not detected correctly, thus the addition of erroneous `<p>` tags and
|
||||
interpretation of their content as Markdown-formatted instead of
|
||||
HTML-formatted.
|
||||
|
||||
|
||||
Extra 1.2.2 (21 Jun 2008):
|
||||
|
||||
* Fixed a problem where abbreviation definitions, footnote
|
||||
definitions and link references were stripped inside
|
||||
fenced code blocks.
|
||||
|
||||
* Fixed a bug where characters such as `"` in abbreviation
|
||||
definitions weren't properly encoded to HTML entities.
|
||||
|
||||
* Fixed a bug where double quotes `"` were not correctly encoded
|
||||
as HTML entities when used inside a footnote reference id.
|
||||
|
||||
|
||||
1.0.1m (21 Jun 2008):
|
||||
|
||||
* Lists can now have empty items.
|
||||
|
||||
* Rewrote the emphasis and strong emphasis parser to fix some issues
|
||||
with odly placed and overlong markers.
|
||||
|
||||
|
||||
Extra 1.2.1 (27 May 2008):
|
||||
|
||||
* Fixed a problem where Markdown headers and horizontal rules were
|
||||
transformed into their HTML equivalent inside fenced code blocks.
|
||||
|
||||
|
||||
Extra 1.2 (11 May 2008):
|
||||
|
||||
* Added fenced code block syntax which don't require indentation
|
||||
and can start and end with blank lines. A fenced code block
|
||||
starts with a line of consecutive tilde (~) and ends on the
|
||||
next line with the same number of consecutive tilde. Here's an
|
||||
example:
|
||||
|
||||
~~~~~~~~~~~~
|
||||
Hello World!
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Rewrote parts of the HTML block parser to better accomodate
|
||||
fenced code blocks.
|
||||
|
||||
* Footnotes may now be referenced from within another footnote.
|
||||
|
||||
* Added programatically-settable parser property `predef_attr` for
|
||||
predefined attribute definitions.
|
||||
|
||||
* Fixed an issue where an indented code block preceded by a blank
|
||||
line containing some other whitespace would confuse the HTML
|
||||
block parser into creating an HTML block when it should have
|
||||
been code.
|
||||
|
||||
|
||||
1.0.1l (11 May 2008):
|
||||
|
||||
* Now removing the UTF-8 BOM at the start of a document, if present.
|
||||
|
||||
* Now accepting capitalized URI schemes (such as HTTP:) in automatic
|
||||
links, such as `<HTTP://EXAMPLE.COM/>`.
|
||||
|
||||
* Fixed a problem where `<hr@example.com>` was seen as a horizontal
|
||||
rule instead of an automatic link.
|
||||
|
||||
* Fixed an issue where some characters in Markdown-generated HTML
|
||||
attributes weren't properly escaped with entities.
|
||||
|
||||
* Fix for code blocks as first element of a list item. Previously,
|
||||
this didn't create any code block for item 2:
|
||||
|
||||
* Item 1 (regular paragraph)
|
||||
|
||||
* Item 2 (code block)
|
||||
|
||||
* A code block starting on the second line of a document wasn't seen
|
||||
as a code block. This has been fixed.
|
||||
|
||||
* Added programatically-settable parser properties `predef_urls` and
|
||||
`predef_titles` for predefined URLs and titles for reference-style
|
||||
links. To use this, your PHP code must call the parser this way:
|
||||
|
||||
$parser = new Markdwon_Parser;
|
||||
$parser->predef_urls = array('linkref' => 'http://example.com');
|
||||
$html = $parser->transform($text);
|
||||
|
||||
You can then use the URL as a normal link reference:
|
||||
|
||||
[my link][linkref]
|
||||
[my link][linkRef]
|
||||
|
||||
Reference names in the parser properties *must* be lowercase.
|
||||
Reference names in the Markdown source may have any case.
|
||||
|
||||
* Added `setup` and `teardown` methods which can be used by subclassers
|
||||
as hook points to arrange the state of some parser variables before and
|
||||
after parsing.
|
||||
|
||||
|
||||
Extra 1.1.7 (26 Sep 2007):
|
||||
|
||||
1.0.1k (26 Sep 2007):
|
||||
|
||||
* Fixed a problem introduced in 1.0.1i where three or more identical
|
||||
uppercase letters, as well as a few other symbols, would trigger
|
||||
a horizontal line.
|
||||
|
||||
|
||||
Extra 1.1.6 (4 Sep 2007):
|
||||
|
||||
1.0.1j (4 Sep 2007):
|
||||
|
||||
* Fixed a problem introduced in 1.0.1i where the closing `code` and
|
||||
`pre` tags at the end of a code block were appearing in the wrong
|
||||
order.
|
||||
|
||||
* Overriding configuration settings by defining constants from an
|
||||
external before markdown.php is included is now possible without
|
||||
producing a PHP warning.
|
||||
|
||||
|
||||
Extra 1.1.5 (31 Aug 2007):
|
||||
|
||||
1.0.1i (31 Aug 2007):
|
||||
|
||||
* Fixed a problem where an escaped backslash before a code span
|
||||
would prevent the code span from being created. This should now
|
||||
work as expected:
|
||||
|
||||
Litteral backslash: \\`code span`
|
||||
|
||||
* Overall speed improvements, especially with long documents.
|
||||
|
||||
|
||||
Extra 1.1.4 (3 Aug 2007):
|
||||
|
||||
1.0.1h (3 Aug 2007):
|
||||
|
||||
* Added two properties (`no_markup` and `no_entities`) to the parser
|
||||
allowing HTML tags and entities to be disabled.
|
||||
|
||||
* Fix for a problem introduced in 1.0.1g where posting comments in
|
||||
WordPress would trigger PHP warnings and cause some markup to be
|
||||
incorrectly filtered by the kses filter in WordPress.
|
||||
|
||||
|
||||
Extra 1.1.3 (3 Jul 2007):
|
||||
|
||||
* Fixed a performance problem when parsing some invalid HTML as an HTML
|
||||
block which was resulting in too much recusion and a segmentation fault
|
||||
for long documents.
|
||||
|
||||
* The markdown="" attribute now accepts unquoted values.
|
||||
|
||||
* Fixed an issue where underscore-emphasis didn't work when applied on the
|
||||
first or the last word of an element having the markdown="1" or
|
||||
markdown="span" attribute set unless there was some surrounding whitespace.
|
||||
This didn't work:
|
||||
|
||||
<p markdown="1">_Hello_ _world_</p>
|
||||
|
||||
Now it does produce emphasis as expected.
|
||||
|
||||
* Fixed an issue preventing footnotes from working when the parser's
|
||||
footnote id prefix variable (fn_id_prefix) is not empty.
|
||||
|
||||
* Fixed a performance problem where the regular expression for strong
|
||||
emphasis introduced in version 1.1 could sometime be long to process,
|
||||
give slightly wrong results, and in some circumstances could remove
|
||||
entirely the content for a whole paragraph.
|
||||
|
||||
* Fixed an issue were abbreviations tags could be incorrectly added
|
||||
inside URLs and title of links.
|
||||
|
||||
* Placing footnote markers inside a link, resulting in two nested links, is
|
||||
no longer allowed.
|
||||
|
||||
|
||||
1.0.1g (3 Jul 2007):
|
||||
|
||||
* Fix for PHP 5 compiled without the mbstring module. Previous fix to
|
||||
calculate the length of UTF-8 strings in `detab` when `mb_strlen` is
|
||||
not available was only working with PHP 4.
|
||||
|
||||
* Fixed a problem with WordPress 2.x where full-content posts in RSS feeds
|
||||
were not processed correctly by Markdown.
|
||||
|
||||
* Now supports URLs containing literal parentheses for inline links
|
||||
and images, such as:
|
||||
|
||||
[WIMP](http://en.wikipedia.org/wiki/WIMP_(computing))
|
||||
|
||||
Such parentheses may be arbitrarily nested, but must be
|
||||
balanced. Unbalenced parentheses are allowed however when the URL
|
||||
when escaped or when the URL is enclosed in angle brakets `<>`.
|
||||
|
||||
* Fixed a performance problem where the regular expression for strong
|
||||
emphasis introduced in version 1.0.1d could sometime be long to process,
|
||||
give slightly wrong results, and in some circumstances could remove
|
||||
entirely the content for a whole paragraph.
|
||||
|
||||
* Some change in version 1.0.1d made possible the incorrect nesting of
|
||||
anchors within each other. This is now fixed.
|
||||
|
||||
* Fixed a rare issue where certain MD5 hashes in the content could
|
||||
be changed to their corresponding text. For instance, this:
|
||||
|
||||
The MD5 value for "+" is "26b17225b626fb9238849fd60eabdf60".
|
||||
|
||||
was incorrectly changed to this in previous versions of PHP Markdown:
|
||||
|
||||
<p>The MD5 value for "+" is "+".</p>
|
||||
|
||||
* Now convert escaped characters to their numeric character
|
||||
references equivalent.
|
||||
|
||||
This fix an integration issue with SmartyPants and backslash escapes.
|
||||
Since Markdown and SmartyPants have some escapable characters in common,
|
||||
it was sometime necessary to escape them twice. Previously, two
|
||||
backslashes were sometime required to prevent Markdown from "eating" the
|
||||
backslash before SmartyPants sees it:
|
||||
|
||||
Here are two hyphens: \\--
|
||||
|
||||
Now, only one backslash will do:
|
||||
|
||||
Here are two hyphens: \--
|
||||
|
||||
|
||||
Extra 1.1.2 (7 Feb 2007)
|
||||
|
||||
* Fixed an issue where headers preceded too closely by a paragraph
|
||||
(with no blank line separating them) where put inside the paragraph.
|
||||
|
||||
* Added the missing TextileRestricted method that was added to regular
|
||||
PHP Markdown since 1.0.1d but which I forgot to add to Extra.
|
||||
|
||||
|
||||
1.0.1f (7 Feb 2007):
|
||||
|
||||
* Fixed an issue with WordPress where manually-entered excerpts, but
|
||||
not the auto-generated ones, would contain nested paragraphs.
|
||||
|
||||
* Fixed an issue introduced in 1.0.1d where headers and blockquotes
|
||||
preceded too closely by a paragraph (not separated by a blank line)
|
||||
where incorrectly put inside the paragraph.
|
||||
|
||||
* Fixed an issue introduced in 1.0.1d in the tokenizeHTML method where
|
||||
two consecutive code spans would be merged into one when together they
|
||||
form a valid tag in a multiline paragraph.
|
||||
|
||||
* Fixed an long-prevailing issue where blank lines in code blocks would
|
||||
be doubled when the code block is in a list item.
|
||||
|
||||
This was due to the list processing functions relying on artificially
|
||||
doubled blank lines to correctly determine when list items should
|
||||
contain block-level content. The list item processing model was thus
|
||||
changed to avoid the need for double blank lines.
|
||||
|
||||
* Fixed an issue with `<% asp-style %>` instructions used as inline
|
||||
content where the opening `<` was encoded as `<`.
|
||||
|
||||
* Fixed a parse error occuring when PHP is configured to accept
|
||||
ASP-style delimiters as boundaries for PHP scripts.
|
||||
|
||||
* Fixed a bug introduced in 1.0.1d where underscores in automatic links
|
||||
got swapped with emphasis tags.
|
||||
|
||||
|
||||
Extra 1.1.1 (28 Dec 2006)
|
||||
|
||||
* Fixed a problem where whitespace at the end of the line of an atx-style
|
||||
header would cause tailing `#` to appear as part of the header's content.
|
||||
This was caused by a small error in the regex that handles the definition
|
||||
for the id attribute in PHP Markdown Extra.
|
||||
|
||||
* Fixed a problem where empty abbreviations definitions would eat the
|
||||
following line as its definition.
|
||||
|
||||
* Fixed an issue with calling the Markdown parser repetitivly with text
|
||||
containing footnotes. The footnote hashes were not reinitialized properly.
|
||||
|
||||
|
||||
1.0.1e (28 Dec 2006)
|
||||
|
||||
* Added support for internationalized domain names for email addresses in
|
||||
automatic link. Improved the speed at which email addresses are converted
|
||||
to entities. Thanks to Milian Wolff for his optimisations.
|
||||
|
||||
* Made deterministic the conversion to entities of email addresses in
|
||||
automatic links. This means that a given email address will always be
|
||||
encoded the same way.
|
||||
|
||||
* PHP Markdown will now use its own function to calculate the length of an
|
||||
UTF-8 string in `detab` when `mb_strlen` is not available instead of
|
||||
giving a fatal error.
|
||||
|
||||
|
||||
Extra 1.1 (1 Dec 2006)
|
||||
|
||||
* Added a syntax for footnotes.
|
||||
|
||||
* Added an experimental syntax to define abbreviations.
|
||||
|
||||
|
||||
1.0.1d (1 Dec 2006)
|
||||
|
||||
* Fixed a bug where inline images always had an empty title attribute. The
|
||||
title attribute is now present only when explicitly defined.
|
||||
|
||||
* Link references definitions can now have an empty title, previously if the
|
||||
title was defined but left empty the link definition was ignored. This can
|
||||
be useful if you want an empty title attribute in images to hide the
|
||||
tooltip in Internet Explorer.
|
||||
|
||||
* Made `detab` aware of UTF-8 characters. UTF-8 multi-byte sequences are now
|
||||
correctly mapped to one character instead of the number of bytes.
|
||||
|
||||
* Fixed a small bug with WordPress where WordPress' default filter `wpautop`
|
||||
was not properly deactivated on comment text, resulting in hard line breaks
|
||||
where Markdown do not prescribes them.
|
||||
|
||||
* Added a `TextileRestrited` method to the textile compatibility mode. There
|
||||
is no restriction however, as Markdown does not have a restricted mode at
|
||||
this point. This should make PHP Markdown work again in the latest
|
||||
versions of TextPattern.
|
||||
|
||||
* Converted PHP Markdown to a object-oriented design.
|
||||
|
||||
* Changed span and block gamut methods so that they loop over a
|
||||
customizable list of methods. This makes subclassing the parser a more
|
||||
interesting option for creating syntax extensions.
|
||||
|
||||
* Also added a "document" gamut loop which can be used to hook document-level
|
||||
methods (like for striping link definitions).
|
||||
|
||||
* Changed all methods which were inserting HTML code so that they now return
|
||||
a hashed representation of the code. New methods `hashSpan` and `hashBlock`
|
||||
are used to hash respectivly span- and block-level generated content. This
|
||||
has a couple of significant effects:
|
||||
|
||||
1. It prevents invalid nesting of Markdown-generated elements which
|
||||
could occur occuring with constructs like `*something [link*][1]`.
|
||||
2. It prevents problems occuring with deeply nested lists on which
|
||||
paragraphs were ill-formed.
|
||||
3. It removes the need to call `hashHTMLBlocks` twice during the the
|
||||
block gamut.
|
||||
|
||||
Hashes are turned back to HTML prior output.
|
||||
|
||||
* Made the block-level HTML parser smarter using a specially-crafted regular
|
||||
expression capable of handling nested tags.
|
||||
|
||||
* Solved backtick issues in tag attributes by rewriting the HTML tokenizer to
|
||||
be aware of code spans. All these lines should work correctly now:
|
||||
|
||||
<span attr='`ticks`'>bar</span>
|
||||
<span attr='``double ticks``'>bar</span>
|
||||
`<test a="` content of attribute `">`
|
||||
|
||||
* Changed the parsing of HTML comments to match simply from `<!--` to `-->`
|
||||
instead using of the more complicated SGML-style rule with paired `--`.
|
||||
This is how most browsers parse comments and how XML defines them too.
|
||||
|
||||
* `<address>` has been added to the list of block-level elements and is now
|
||||
treated as an HTML block instead of being wrapped within paragraph tags.
|
||||
|
||||
* Now only trim trailing newlines from code blocks, instead of trimming
|
||||
all trailing whitespace characters.
|
||||
|
||||
* Fixed bug where this:
|
||||
|
||||
[text](http://m.com "title" )
|
||||
|
||||
wasn't working as expected, because the parser wasn't allowing for spaces
|
||||
before the closing paren.
|
||||
|
||||
* Filthy hack to support markdown='1' in div tags.
|
||||
|
||||
* _DoAutoLinks() now supports the 'dict://' URL scheme.
|
||||
|
||||
* PHP- and ASP-style processor instructions are now protected as
|
||||
raw HTML blocks.
|
||||
|
||||
<? ... ?>
|
||||
<% ... %>
|
||||
|
||||
* Fix for escaped backticks still triggering code spans:
|
||||
|
||||
There are two raw backticks here: \` and here: \`, not a code span
|
||||
|
||||
|
||||
Extra 1.0 - 5 September 2005
|
||||
|
||||
* Added support for setting the id attributes for headers like this:
|
||||
|
||||
Header 1 {#header1}
|
||||
========
|
||||
|
||||
## Header 2 ## {#header2}
|
||||
|
||||
This only work only for headers for now.
|
||||
|
||||
* Tables will now work correctly as the first element of a definition
|
||||
list. For example, this input:
|
||||
|
||||
Term
|
||||
|
||||
: Header | Header
|
||||
------- | -------
|
||||
Cell | Cell
|
||||
|
||||
used to produce no definition list and a table where the first
|
||||
header was named ": Header". This is now fixed.
|
||||
|
||||
* Fix for a problem where a paragraph following a table was not
|
||||
placed between `<p>` tags.
|
||||
|
||||
|
||||
Extra 1.0b4 - 1 August 2005
|
||||
|
||||
* Fixed some issues where whitespace around HTML blocks were trigging
|
||||
empty paragraph tags.
|
||||
|
||||
* Fixed an HTML block parsing issue that would cause a block element
|
||||
following a code span or block with unmatched opening bracket to be
|
||||
placed inside a paragraph.
|
||||
|
||||
* Removed some PHP notices that could appear when parsing definition
|
||||
lists and tables with PHP notice reporting flag set.
|
||||
|
||||
|
||||
Extra 1.0b3 - 29 July 2005
|
||||
|
||||
* Definition lists now require a blank line before each term. Solves
|
||||
an ambiguity where the last line of lazy-indented definitions could
|
||||
be mistaken by PHP Markdown as a new term in the list.
|
||||
|
||||
* Definition lists now support multiple terms per definition.
|
||||
|
||||
* Some special tags were replaced in the output by their md5 hash
|
||||
key. Things such as this now work as expected:
|
||||
|
||||
## Header <?php echo $number ?> ##
|
||||
|
||||
|
||||
Extra 1.0b2 - 26 July 2005
|
||||
|
||||
* Definition lists can now take two or more definitions for one term.
|
||||
This should have been the case before, but a bug prevented this
|
||||
from working right.
|
||||
|
||||
* Fixed a problem where single column table with a pipe only at the
|
||||
end where not parsed as table. Here is such a table:
|
||||
|
||||
| header
|
||||
| ------
|
||||
| cell
|
||||
|
||||
* Fixed problems with empty cells in the first column of a table with
|
||||
no leading pipe, like this one:
|
||||
|
||||
header | header
|
||||
------ | ------
|
||||
| cell
|
||||
|
||||
* Code spans containing pipes did not within a table. This is now
|
||||
fixed by parsing code spans before splitting rows into cells.
|
||||
|
||||
* Added the pipe character to the backlash escape character lists.
|
||||
|
||||
Extra 1.0b1 (25 Jun 2005)
|
||||
|
||||
* First public release of PHP Markdown Extra.
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
PHP Markdown & Extra
|
||||
Copyright (c) 2004-2009 Michel Fortin
|
||||
<http://michelf.com/>
|
||||
All rights reserved.
|
||||
|
||||
Based on Markdown
|
||||
Copyright (c) 2003-2005 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name "Markdown" nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as
|
||||
is" and any express or implied warranties, including, but not limited
|
||||
to, the implied warranties of merchantability and fitness for a
|
||||
particular purpose are disclaimed. In no event shall the copyright owner
|
||||
or contributors be liable for any direct, indirect, incidental, special,
|
||||
exemplary, or consequential damages (including, but not limited to,
|
||||
procurement of substitute goods or services; loss of use, data, or
|
||||
profits; or business interruption) however caused and on any theory of
|
||||
liability, whether in contract, strict liability, or tort (including
|
||||
negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
2932
_site/tmp/var/www/chaospott.de/engine/PHPMarkdownExtra/markdown.php
Normal file
2932
_site/tmp/var/www/chaospott.de/engine/PHPMarkdownExtra/markdown.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,394 @@
|
||||
PHP SmartyPants
|
||||
===============
|
||||
|
||||
Version 1.5.1e - Fri 9 Dec 2005
|
||||
|
||||
by Michel Fortin
|
||||
<http://www.michelf.com/>
|
||||
|
||||
based on work by John Gruber
|
||||
<http://daringfireball.net/>
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
PHP SmartyPants is a port to PHP of the original SmartyPants written
|
||||
in Perl by John Gruber.
|
||||
|
||||
PHP SmartyPants is a free web publishing plug-in for WordPress and
|
||||
Smarty template engine that easily translates plain ASCII punctuation
|
||||
characters into "smart" typographic punctuation HTML entities.
|
||||
SmartyPants can also be invoked as a standalone PHP function.
|
||||
|
||||
SmartyPants can perform the following transformations:
|
||||
|
||||
* Straight quotes (`"` and `'`) into "curly" quote HTML entities
|
||||
* Backtick-style quotes (` ``like this'' `) into "curly" quote HTML
|
||||
entities
|
||||
* Dashes (`--` and `---`) into en- and em-dash entities
|
||||
* Three consecutive dots (`...`) into an ellipsis entity
|
||||
|
||||
This means you can write, edit, and save using plain old ASCII straight
|
||||
quotes, plain dashes, and plain dots, but your published posts (and
|
||||
final HTML output) will appear with smart quotes, em-dashes, and proper
|
||||
ellipses.
|
||||
|
||||
SmartyPants does not modify characters within `<pre>`, `<code>`,
|
||||
`<kbd>`, or `<script>` tag blocks. Typically, these tags are used to
|
||||
display text where smart quotes and other "smart punctuation" would not
|
||||
be appropriate, such as source code or example markup.
|
||||
|
||||
|
||||
### Backslash Escapes ###
|
||||
|
||||
If you need to use literal straight quotes (or plain hyphens and
|
||||
periods), SmartyPants accepts the following backslash escape sequences
|
||||
to force non-smart punctuation. It does so by transforming the escape
|
||||
sequence into a decimal-encoded HTML entity:
|
||||
|
||||
|
||||
Escape Value Character
|
||||
------ ----- ---------
|
||||
\\ \ \
|
||||
\" " "
|
||||
\' ' '
|
||||
\. . .
|
||||
\- - -
|
||||
\` ` `
|
||||
|
||||
|
||||
This is useful, for example, when you want to use straight quotes as
|
||||
foot and inch marks:
|
||||
|
||||
6\'2\" tall
|
||||
|
||||
translates into:
|
||||
|
||||
6'2" tall
|
||||
|
||||
in SmartyPants's HTML output. Which, when rendered by a web browser,
|
||||
looks like:
|
||||
|
||||
6'2" tall
|
||||
|
||||
|
||||
Installation and Requirement
|
||||
----------------------------
|
||||
|
||||
PHP SmartyPants require PHP version 4.0.5 or later.
|
||||
|
||||
|
||||
### WordPress ###
|
||||
|
||||
WordPress already include a filter called "Texturize" with the same
|
||||
goal as SmartyPants. You could still find some usefulness to
|
||||
PHP SmartyPants if you are not happy enough with the standard algorithm.
|
||||
|
||||
PHP SmartyPants works with [WordPress][wp], version 1.2 or later.
|
||||
|
||||
[wp]: http://wordpress.org/
|
||||
|
||||
1. To use PHP SmartyPants with WordPress, place the "smartypants.php"
|
||||
file in the "plugins" folder. This folder is hidden inside
|
||||
"wp-content" at the root of your site:
|
||||
|
||||
(site home)/wp-content/plugins/smartypants.php
|
||||
|
||||
2. Activate the plugin with the administrative interface of WordPress.
|
||||
In the "Plugins" section you will now find SmartyPants. To activate
|
||||
the plugin, click on the "Activate" button on the same line than
|
||||
SmartyPants. Your entries will now be filtered by PHP SmartyPants.
|
||||
|
||||
Note: It is not possible at this time to apply a different set of
|
||||
filters to different entries. All your entries will be filtered by
|
||||
PHP SmartyPants if the plugin is active. This is currently a limitation
|
||||
of WordPress.
|
||||
|
||||
|
||||
### Blosxom ###
|
||||
|
||||
SmartyPants works with Blosxom version 2.0 or later.
|
||||
|
||||
1. Rename the "SmartyPants.pl" plug-in to "SmartyPants" (case is
|
||||
important). Movable Type requires plug-ins to have a ".pl"
|
||||
extension; Blosxom forbids it (at least as of this writing).
|
||||
|
||||
2. Copy the "SmartyPants" plug-in file to your Blosxom plug-ins folder.
|
||||
If you're not sure where your Blosxom plug-ins folder is, see the
|
||||
Blosxom documentation for information.
|
||||
|
||||
3. That's it. The entries in your weblog should now automatically have
|
||||
SmartyPants's default transformations applied.
|
||||
|
||||
4. If you wish to configure SmartyPants's behavior, open the
|
||||
"SmartyPants" plug-in, and edit the value of the `$smartypants_attr`
|
||||
configuration variable, located near the top of the script. The
|
||||
default value is 1; see "Options", below, for the full list of
|
||||
supported values.
|
||||
|
||||
|
||||
### In your programs ###
|
||||
|
||||
You can use PHP SmartyPants easily in your current PHP program. Simply
|
||||
include the file and then call the `SmartyPants` function on the text
|
||||
you want to convert:
|
||||
|
||||
include_once "smartypants.php";
|
||||
$my_text = SmartyPants($my_text);
|
||||
|
||||
|
||||
### With Smarty ###
|
||||
|
||||
If your program use the [Smarty][sm] template engine, PHP SmartyPants
|
||||
can now be used as a modifier for your templates. Rename
|
||||
"smartypants.php" to "modifier.smartypants.php" and put it in your
|
||||
smarty plugins folder.
|
||||
|
||||
[sm]: http://smarty.php.net/
|
||||
|
||||
|
||||
Options and Configuration
|
||||
-------------------------
|
||||
|
||||
Settings are specified by editing the value of the `$smartypants_attr`
|
||||
variable in the "smartypants.php" file. For users of the Smarty template
|
||||
engine, the "smartypants" modifier also takes an optional attribute where
|
||||
you can specify configuration options, like this:
|
||||
`{$var|smartypants:1}` (where "1" is the configuration option).
|
||||
|
||||
Numeric values are the easiest way to configure SmartyPants's behavior:
|
||||
|
||||
"0"
|
||||
Suppress all transformations. (Do nothing.)
|
||||
|
||||
"1"
|
||||
Performs default SmartyPants transformations: quotes (including
|
||||
backticks-style), em-dashes, and ellipses. `--` (dash dash) is
|
||||
used to signify an em-dash; there is no support for en-dashes.
|
||||
|
||||
"2"
|
||||
Same as smarty_pants="1", except that it uses the old-school
|
||||
typewriter shorthand for dashes: `--` (dash dash) for en-dashes,
|
||||
`---` (dash dash dash) for em-dashes.
|
||||
|
||||
"3"
|
||||
Same as smarty_pants="2", but inverts the shorthand for dashes: `--`
|
||||
(dash dash) for em-dashes, and `---` (dash dash dash) for en-dashes.
|
||||
|
||||
"-1"
|
||||
Stupefy mode. Reverses the SmartyPants transformation process,
|
||||
turning the HTML entities produced by SmartyPants into their ASCII
|
||||
equivalents. E.g. `“` is turned into a simple double-quote
|
||||
(`"`), `—` is turned into two dashes, etc. This is useful if you
|
||||
wish to suppress smart punctuation in specific pages, such as
|
||||
RSS feeds.
|
||||
|
||||
The following single-character attribute values can be combined to
|
||||
toggle individual transformations from within the smarty_pants
|
||||
attribute. For example, to educate normal quotes and em-dashes, but not
|
||||
ellipses or backticks-style quotes:
|
||||
|
||||
$smartypants_attr = "qd";
|
||||
|
||||
Or inside a Smarty template:
|
||||
|
||||
{$var|smartypants:"qd"}
|
||||
|
||||
"q"
|
||||
Educates normal quote characters: (`"`) and (`'`).
|
||||
|
||||
"b"
|
||||
Educates ` ``backticks'' ` double quotes.
|
||||
|
||||
"B"
|
||||
Educates backticks-style double quotes and ` `single' ` quotes.
|
||||
|
||||
"d"
|
||||
Educates em-dashes.
|
||||
|
||||
"D"
|
||||
Educates em-dashes and en-dashes, using old-school typewriter
|
||||
shorthand: (dash dash) for en-dashes, (dash dash dash) for
|
||||
em-dashes.
|
||||
|
||||
"i"
|
||||
Educates em-dashes and en-dashes, using inverted old-school
|
||||
typewriter shorthand: (dash dash) for em-dashes, (dash dash dash)
|
||||
for en-dashes.
|
||||
|
||||
"e"
|
||||
Educates ellipses.
|
||||
|
||||
"w"
|
||||
Translates any instance of `"` into a normal double-quote
|
||||
character. This should be of no interest to most people, but of
|
||||
particular interest to anyone who writes their posts using
|
||||
Dreamweaver, as Dreamweaver inexplicably uses this entity to
|
||||
represent a literal double-quote character. SmartyPants only
|
||||
educates normal quotes, not entities (because ordinarily, entities
|
||||
are used for the explicit purpose of representing the specific
|
||||
character they represent). The "w" option must be used in
|
||||
conjunction with one (or both) of the other quote options ("q" or
|
||||
"b"). Thus, if you wish to apply all SmartyPants transformations
|
||||
(quotes, en- and em-dashes, and ellipses) and also translate
|
||||
`"` entities into regular quotes so SmartyPants can educate
|
||||
them, you should pass the following to the smarty_pants attribute:
|
||||
|
||||
$smartypants_attr = "qDew";
|
||||
|
||||
Inside a Smarty template, this will be:
|
||||
|
||||
{$var|smartypants:"qDew"}
|
||||
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
### Why You Might Not Want to Use Smart Quotes in Your Weblog ###
|
||||
|
||||
For one thing, you might not care.
|
||||
|
||||
Most normal, mentally stable individuals do not take notice of proper
|
||||
typographic punctuation. Many design and typography nerds, however,
|
||||
break out in a nasty rash when they encounter, say, a restaurant sign
|
||||
that uses a straight apostrophe to spell "Joe's".
|
||||
|
||||
If you're the sort of person who just doesn't care, you might well want
|
||||
to continue not caring. Using straight quotes -- and sticking to the
|
||||
7-bit ASCII character set in general -- is certainly a simpler way to
|
||||
live.
|
||||
|
||||
Even if you *do* care about accurate typography, you still might want to
|
||||
think twice before educating the quote characters in your weblog. One
|
||||
side effect of publishing curly quote HTML entities is that it makes
|
||||
your weblog a bit harder for others to quote from using copy-and-paste.
|
||||
What happens is that when someone copies text from your blog, the copied
|
||||
text contains the 8-bit curly quote characters (as well as the 8-bit
|
||||
characters for em-dashes and ellipses, if you use these options). These
|
||||
characters are not standard across different text encoding methods,
|
||||
which is why they need to be encoded as HTML entities.
|
||||
|
||||
People copying text from your weblog, however, may not notice that
|
||||
you're using curly quotes, and they'll go ahead and paste the unencoded
|
||||
8-bit characters copied from their browser into an email message or
|
||||
their own weblog. When pasted as raw "smart quotes", these characters
|
||||
are likely to get mangled beyond recognition.
|
||||
|
||||
That said, my own opinion is that any decent text editor or email client
|
||||
makes it easy to stupefy smart quote characters into their 7-bit
|
||||
equivalents, and I don't consider it my problem if you're using an
|
||||
indecent text editor or email client.
|
||||
|
||||
### Algorithmic Shortcomings ###
|
||||
|
||||
One situation in which quotes will get curled the wrong way is when
|
||||
apostrophes are used at the start of leading contractions. For example:
|
||||
|
||||
'Twas the night before Christmas.
|
||||
|
||||
In the case above, SmartyPants will turn the apostrophe into an opening
|
||||
single-quote, when in fact it should be a closing one. I don't think
|
||||
this problem can be solved in the general case -- every word processor
|
||||
I've tried gets this wrong as well. In such cases, it's best to use the
|
||||
proper HTML entity for closing single-quotes (`’` or `’`) by
|
||||
hand.
|
||||
|
||||
|
||||
Bugs
|
||||
----
|
||||
|
||||
To file bug reports or feature requests (other than topics listed in the
|
||||
Caveats section above) please send email to:
|
||||
|
||||
<michel.fortin@michelf.com>
|
||||
|
||||
If the bug involves quotes being curled the wrong way, please send
|
||||
example text to illustrate.
|
||||
|
||||
|
||||
Version History
|
||||
---------------
|
||||
|
||||
1.5.1e (9 Dec 2005)
|
||||
|
||||
* Corrected a bug that prevented special characters from being
|
||||
escaped.
|
||||
|
||||
|
||||
1.5.1d (6 Jun 2005)
|
||||
|
||||
* Correct a small bug in `_TokenizeHTML` where a Doctype declaration
|
||||
was not seen as HTML, making curly quotes inside it.
|
||||
|
||||
|
||||
1.5.1c (13 Dec 2004)
|
||||
|
||||
* Changed a regular expression in `_TokenizeHTML` that could lead
|
||||
to a segmentation fault with PHP 4.3.8 on Linux.
|
||||
|
||||
|
||||
1.5.1b (6 Sep 2004)
|
||||
|
||||
* Corrected a problem with quotes immediately following a dash
|
||||
with no space between: `Text--"quoted text"--text.`
|
||||
|
||||
* PHP SmartyPants can now be used as a modifier by the Smarty
|
||||
template engine. Rename the file to "modifier.smartypants.php"
|
||||
and put it in your smarty plugins folder.
|
||||
|
||||
* Replaced a lot of spaces characters by tabs, saving about 4 KB.
|
||||
|
||||
|
||||
1.5.1a (30 Jun 2004)
|
||||
|
||||
* PHP Markdown and PHP Smartypants now share the same `_TokenizeHTML`
|
||||
function when loaded simultanously.
|
||||
|
||||
* Changed the internals of `_TokenizeHTML` to lower the PHP version
|
||||
requirement to PHP 4.0.5.
|
||||
|
||||
|
||||
1.5.1 (6 Jun 2004)
|
||||
|
||||
* Initial release of PHP SmartyPants, based on version 1.5.1 of the
|
||||
original SmartyPants written in Perl.
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright (c) 2005 Michel Fortin
|
||||
<http://www.michelf.com/>
|
||||
All rights reserved.
|
||||
|
||||
Copyright (c) 2003-2004 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name "SmartyPants" nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as
|
||||
is" and any express or implied warranties, including, but not limited
|
||||
to, the implied warranties of merchantability and fitness for a
|
||||
particular purpose are disclaimed. In no event shall the copyright owner
|
||||
or contributors be liable for any direct, indirect, incidental, special,
|
||||
exemplary, or consequential damages (including, but not limited to,
|
||||
procurement of substitute goods or services; loss of use, data, or
|
||||
profits; or business interruption) however caused and on any theory of
|
||||
liability, whether in contract, strict liability, or tort (including
|
||||
negligence or otherwise) arising in any way out of the use of this
|
||||
software, even if advised of the possibility of such damage.
|
@ -0,0 +1,860 @@
|
||||
<?php
|
||||
|
||||
#
|
||||
# SmartyPants - Smart punctuation for web sites
|
||||
#
|
||||
# by John Gruber
|
||||
# <http://daringfireball.net>
|
||||
#
|
||||
# PHP port by Michel Fortin
|
||||
# <http://www.michelf.com/>
|
||||
#
|
||||
# Copyright (c) 2003-2004 John Gruber
|
||||
# Copyright (c) 2004-2005 Michel Fortin
|
||||
#
|
||||
|
||||
|
||||
global $SmartyPantsPHPVersion, $SmartyPantsSyntaxVersion,
|
||||
$smartypants_attr, $sp_tags_to_skip;
|
||||
|
||||
$SmartyPantsPHPVersion = '1.5.1e'; # Fru 9 Dec 2005
|
||||
$SmartyPantsSyntaxVersion = '1.5.1'; # Fri 12 Mar 2004
|
||||
|
||||
|
||||
# Configurable variables:
|
||||
$smartypants_attr = "1"; # Change this to configure.
|
||||
# 1 => "--" for em-dashes; no en-dash support
|
||||
# 2 => "---" for em-dashes; "--" for en-dashes
|
||||
# 3 => "--" for em-dashes; "---" for en-dashes
|
||||
# See docs for more configuration options.
|
||||
|
||||
# Globals:
|
||||
$sp_tags_to_skip = '<(/?)(?:pre|code|kbd|script|math)[\s>]';
|
||||
|
||||
|
||||
# -- WordPress plugin interface -----------------------------------------------
|
||||
/*
|
||||
Plugin Name: SmartyPants
|
||||
Plugin URI: http://www.michelf.com/projects/php-smartypants/
|
||||
Description: SmartyPants is a web publishing utility that translates plain ASCII punctuation characters into “smart” typographic punctuation HTML entities. This plugin <strong>replace the default WordPress Texturize algorithm</strong> for the content and the title of your posts, the comments body and author name, and everywhere else Texturize normally apply. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>.
|
||||
Version: 1.5.1e
|
||||
Author: Michel Fortin
|
||||
Author URI: http://www.michelf.com/
|
||||
*/
|
||||
if (isset($wp_version)) {
|
||||
# Remove default Texturize filter that would conflict with SmartyPants.
|
||||
remove_filter('category_description', 'wptexturize');
|
||||
remove_filter('list_cats', 'wptexturize');
|
||||
remove_filter('comment_author', 'wptexturize');
|
||||
remove_filter('comment_text', 'wptexturize');
|
||||
remove_filter('single_post_title', 'wptexturize');
|
||||
remove_filter('the_title', 'wptexturize');
|
||||
remove_filter('the_content', 'wptexturize');
|
||||
remove_filter('the_excerpt', 'wptexturize');
|
||||
# Add SmartyPants filter with priority 10 (same as Texturize).
|
||||
add_filter('category_description', 'SmartyPants', 10);
|
||||
add_filter('list_cats', 'SmartyPants', 10);
|
||||
add_filter('comment_author', 'SmartyPants', 10);
|
||||
add_filter('comment_text', 'SmartyPants', 10);
|
||||
add_filter('single_post_title', 'SmartyPants', 10);
|
||||
add_filter('the_title', 'SmartyPants', 10);
|
||||
add_filter('the_content', 'SmartyPants', 10);
|
||||
add_filter('the_excerpt', 'SmartyPants', 10);
|
||||
}
|
||||
|
||||
# -- Smarty Modifier Interface ------------------------------------------------
|
||||
function smarty_modifier_smartypants($text, $attr = NULL) {
|
||||
return SmartyPants($text, $attr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function SmartyPants($text, $attr = NULL, $ctx = NULL) {
|
||||
global $smartypants_attr, $sp_tags_to_skip;
|
||||
# Paramaters:
|
||||
$text; # text to be parsed
|
||||
$attr; # value of the smart_quotes="" attribute
|
||||
$ctx; # MT context object (unused)
|
||||
if ($attr == NULL) $attr = $smartypants_attr;
|
||||
|
||||
# Options to specify which transformations to make:
|
||||
$do_stupefy = FALSE;
|
||||
$convert_quot = 0; # should we translate " entities into normal quotes?
|
||||
|
||||
# Parse attributes:
|
||||
# 0 : do nothing
|
||||
# 1 : set all
|
||||
# 2 : set all, using old school en- and em- dash shortcuts
|
||||
# 3 : set all, using inverted old school en and em- dash shortcuts
|
||||
#
|
||||
# q : quotes
|
||||
# b : backtick quotes (``double'' only)
|
||||
# B : backtick quotes (``double'' and `single')
|
||||
# d : dashes
|
||||
# D : old school dashes
|
||||
# i : inverted old school dashes
|
||||
# e : ellipses
|
||||
# w : convert " entities to " for Dreamweaver users
|
||||
|
||||
if ($attr == "0") {
|
||||
# Do nothing.
|
||||
return $text;
|
||||
}
|
||||
else if ($attr == "1") {
|
||||
# Do everything, turn all options on.
|
||||
$do_quotes = 1;
|
||||
$do_backticks = 1;
|
||||
$do_dashes = 1;
|
||||
$do_ellipses = 1;
|
||||
}
|
||||
else if ($attr == "2") {
|
||||
# Do everything, turn all options on, use old school dash shorthand.
|
||||
$do_quotes = 1;
|
||||
$do_backticks = 1;
|
||||
$do_dashes = 2;
|
||||
$do_ellipses = 1;
|
||||
}
|
||||
else if ($attr == "3") {
|
||||
# Do everything, turn all options on, use inverted old school dash shorthand.
|
||||
$do_quotes = 1;
|
||||
$do_backticks = 1;
|
||||
$do_dashes = 3;
|
||||
$do_ellipses = 1;
|
||||
}
|
||||
else if ($attr == "-1") {
|
||||
# Special "stupefy" mode.
|
||||
$do_stupefy = 1;
|
||||
}
|
||||
else {
|
||||
$chars = preg_split('//', $attr);
|
||||
foreach ($chars as $c){
|
||||
if ($c == "q") { $do_quotes = 1; }
|
||||
else if ($c == "b") { $do_backticks = 1; }
|
||||
else if ($c == "B") { $do_backticks = 2; }
|
||||
else if ($c == "d") { $do_dashes = 1; }
|
||||
else if ($c == "D") { $do_dashes = 2; }
|
||||
else if ($c == "i") { $do_dashes = 3; }
|
||||
else if ($c == "e") { $do_ellipses = 1; }
|
||||
else if ($c == "w") { $convert_quot = 1; }
|
||||
else {
|
||||
# Unknown attribute option, ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tokens = _TokenizeHTML($text);
|
||||
$result = '';
|
||||
$in_pre = 0; # Keep track of when we're inside <pre> or <code> tags.
|
||||
|
||||
$prev_token_last_char = ""; # This is a cheat, used to get some context
|
||||
# for one-character tokens that consist of
|
||||
# just a quote char. What we do is remember
|
||||
# the last character of the previous text
|
||||
# token, to use as context to curl single-
|
||||
# character quote tokens correctly.
|
||||
|
||||
foreach ($tokens as $cur_token) {
|
||||
if ($cur_token[0] == "tag") {
|
||||
# Don't mess with quotes inside tags.
|
||||
$result .= $cur_token[1];
|
||||
if (preg_match("@$sp_tags_to_skip@", $cur_token[1], $matches)) {
|
||||
$in_pre = isset($matches[1]) && $matches[1] == '/' ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
$t = $cur_token[1];
|
||||
$last_char = substr($t, -1); # Remember last char of this token before processing.
|
||||
if (! $in_pre) {
|
||||
$t = ProcessEscapes($t);
|
||||
|
||||
if ($convert_quot) {
|
||||
$t = preg_replace('/"/', '"', $t);
|
||||
}
|
||||
|
||||
if ($do_dashes) {
|
||||
if ($do_dashes == 1) $t = EducateDashes($t);
|
||||
if ($do_dashes == 2) $t = EducateDashesOldSchool($t);
|
||||
if ($do_dashes == 3) $t = EducateDashesOldSchoolInverted($t);
|
||||
}
|
||||
|
||||
if ($do_ellipses) $t = EducateEllipses($t);
|
||||
|
||||
# Note: backticks need to be processed before quotes.
|
||||
if ($do_backticks) {
|
||||
$t = EducateBackticks($t);
|
||||
if ($do_backticks == 2) $t = EducateSingleBackticks($t);
|
||||
}
|
||||
|
||||
if ($do_quotes) {
|
||||
if ($t == "'") {
|
||||
# Special case: single-character ' token
|
||||
if (preg_match('/\S/', $prev_token_last_char)) {
|
||||
$t = "’";
|
||||
}
|
||||
else {
|
||||
$t = "‘";
|
||||
}
|
||||
}
|
||||
else if ($t == '"') {
|
||||
# Special case: single-character " token
|
||||
if (preg_match('/\S/', $prev_token_last_char)) {
|
||||
$t = "”";
|
||||
}
|
||||
else {
|
||||
$t = "“";
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Normal case:
|
||||
$t = EducateQuotes($t);
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_stupefy) $t = StupefyEntities($t);
|
||||
}
|
||||
$prev_token_last_char = $last_char;
|
||||
$result .= $t;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function SmartQuotes($text, $attr = NULL, $ctx = NULL) {
|
||||
global $smartypants_attr, $sp_tags_to_skip;
|
||||
# Paramaters:
|
||||
$text; # text to be parsed
|
||||
$attr; # value of the smart_quotes="" attribute
|
||||
$ctx; # MT context object (unused)
|
||||
if ($attr == NULL) $attr = $smartypants_attr;
|
||||
|
||||
$do_backticks; # should we educate ``backticks'' -style quotes?
|
||||
|
||||
if ($attr == 0) {
|
||||
# do nothing;
|
||||
return $text;
|
||||
}
|
||||
else if ($attr == 2) {
|
||||
# smarten ``backticks'' -style quotes
|
||||
$do_backticks = 1;
|
||||
}
|
||||
else {
|
||||
$do_backticks = 0;
|
||||
}
|
||||
|
||||
# Special case to handle quotes at the very end of $text when preceded by
|
||||
# an HTML tag. Add a space to give the quote education algorithm a bit of
|
||||
# context, so that it can guess correctly that it's a closing quote:
|
||||
$add_extra_space = 0;
|
||||
if (preg_match("/>['\"]\\z/", $text)) {
|
||||
$add_extra_space = 1; # Remember, so we can trim the extra space later.
|
||||
$text .= " ";
|
||||
}
|
||||
|
||||
$tokens = _TokenizeHTML($text);
|
||||
$result = '';
|
||||
$in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
|
||||
|
||||
$prev_token_last_char = ""; # This is a cheat, used to get some context
|
||||
# for one-character tokens that consist of
|
||||
# just a quote char. What we do is remember
|
||||
# the last character of the previous text
|
||||
# token, to use as context to curl single-
|
||||
# character quote tokens correctly.
|
||||
|
||||
foreach ($tokens as $cur_token) {
|
||||
if ($cur_token[0] == "tag") {
|
||||
# Don't mess with quotes inside tags
|
||||
$result .= $cur_token[1];
|
||||
if (preg_match("@$sp_tags_to_skip@", $cur_token[1], $matches)) {
|
||||
$in_pre = isset($matches[1]) && $matches[1] == '/' ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
$t = $cur_token[1];
|
||||
$last_char = substr($t, -1); # Remember last char of this token before processing.
|
||||
if (! $in_pre) {
|
||||
$t = ProcessEscapes($t);
|
||||
if ($do_backticks) {
|
||||
$t = EducateBackticks($t);
|
||||
}
|
||||
|
||||
if ($t == "'") {
|
||||
# Special case: single-character ' token
|
||||
if (preg_match('/\S/', $prev_token_last_char)) {
|
||||
$t = "’";
|
||||
}
|
||||
else {
|
||||
$t = "‘";
|
||||
}
|
||||
}
|
||||
else if ($t == '"') {
|
||||
# Special case: single-character " token
|
||||
if (preg_match('/\S/', $prev_token_last_char)) {
|
||||
$t = "”";
|
||||
}
|
||||
else {
|
||||
$t = "“";
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Normal case:
|
||||
$t = EducateQuotes($t);
|
||||
}
|
||||
|
||||
}
|
||||
$prev_token_last_char = $last_char;
|
||||
$result .= $t;
|
||||
}
|
||||
}
|
||||
|
||||
if ($add_extra_space) {
|
||||
preg_replace('/ \z/', '', $result); # Trim trailing space if we added one earlier.
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function SmartDashes($text, $attr = NULL, $ctx = NULL) {
|
||||
global $smartypants_attr, $sp_tags_to_skip;
|
||||
# Paramaters:
|
||||
$text; # text to be parsed
|
||||
$attr; # value of the smart_dashes="" attribute
|
||||
$ctx; # MT context object (unused)
|
||||
if ($attr == NULL) $attr = $smartypants_attr;
|
||||
|
||||
# reference to the subroutine to use for dash education, default to EducateDashes:
|
||||
$dash_sub_ref = 'EducateDashes';
|
||||
|
||||
if ($attr == 0) {
|
||||
# do nothing;
|
||||
return $text;
|
||||
}
|
||||
else if ($attr == 2) {
|
||||
# use old smart dash shortcuts, "--" for en, "---" for em
|
||||
$dash_sub_ref = 'EducateDashesOldSchool';
|
||||
}
|
||||
else if ($attr == 3) {
|
||||
# inverse of 2, "--" for em, "---" for en
|
||||
$dash_sub_ref = 'EducateDashesOldSchoolInverted';
|
||||
}
|
||||
|
||||
$tokens;
|
||||
$tokens = _TokenizeHTML($text);
|
||||
|
||||
$result = '';
|
||||
$in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
|
||||
foreach ($tokens as $cur_token) {
|
||||
if ($cur_token[0] == "tag") {
|
||||
# Don't mess with quotes inside tags
|
||||
$result .= $cur_token[1];
|
||||
if (preg_match("@$sp_tags_to_skip@", $cur_token[1], $matches)) {
|
||||
$in_pre = isset($matches[1]) && $matches[1] == '/' ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
$t = $cur_token[1];
|
||||
if (! $in_pre) {
|
||||
$t = ProcessEscapes($t);
|
||||
$t = $dash_sub_ref($t);
|
||||
}
|
||||
$result .= $t;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function SmartEllipses($text, $attr = NULL, $ctx = NULL) {
|
||||
# Paramaters:
|
||||
$text; # text to be parsed
|
||||
$attr; # value of the smart_ellipses="" attribute
|
||||
$ctx; # MT context object (unused)
|
||||
if ($attr == NULL) $attr = $smartypants_attr;
|
||||
|
||||
if ($attr == 0) {
|
||||
# do nothing;
|
||||
return $text;
|
||||
}
|
||||
|
||||
$tokens;
|
||||
$tokens = _TokenizeHTML($text);
|
||||
|
||||
$result = '';
|
||||
$in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
|
||||
foreach ($tokens as $cur_token) {
|
||||
if ($cur_token[0] == "tag") {
|
||||
# Don't mess with quotes inside tags
|
||||
$result .= $cur_token[1];
|
||||
if (preg_match("@$sp_tags_to_skip@", $cur_token[1], $matches)) {
|
||||
$in_pre = isset($matches[1]) && $matches[1] == '/' ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
$t = $cur_token[1];
|
||||
if (! $in_pre) {
|
||||
$t = ProcessEscapes($t);
|
||||
$t = EducateEllipses($t);
|
||||
}
|
||||
$result .= $t;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
function EducateQuotes($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
#
|
||||
# Returns: The string, with "educated" curly quote HTML entities.
|
||||
#
|
||||
# Example input: "Isn't this fun?"
|
||||
# Example output: “Isn’t this fun?”
|
||||
#
|
||||
# Make our own "punctuation" character class, because the POSIX-style
|
||||
# [:PUNCT:] is only available in Perl 5.6 or later:
|
||||
$punct_class = "[!\"#\\$\\%'()*+,-.\\/:;<=>?\\@\\[\\\\\]\\^_`{|}~]";
|
||||
|
||||
# Special case if the very first character is a quote
|
||||
# followed by punctuation at a non-word-break. Close the quotes by brute force:
|
||||
$_ = preg_replace(
|
||||
array("/^'(?=$punct_class\\B)/", "/^\"(?=$punct_class\\B)/"),
|
||||
array('’', '”'), $_);
|
||||
|
||||
|
||||
# Special case for double sets of quotes, e.g.:
|
||||
# <p>He said, "'Quoted' words in a larger quote."</p>
|
||||
$_ = preg_replace(
|
||||
array("/\"'(?=\w)/", "/'\"(?=\w)/"),
|
||||
array('“‘', '‘“'), $_);
|
||||
|
||||
# Special case for decade abbreviations (the '80s):
|
||||
$_ = preg_replace("/'(?=\\d{2}s)/", '’', $_);
|
||||
|
||||
$close_class = '[^\ \t\r\n\[\{\(\-]';
|
||||
$dec_dashes = '&\#8211;|&\#8212;';
|
||||
|
||||
# Get most opening single quotes:
|
||||
$_ = preg_replace("{
|
||||
(
|
||||
\\s | # a whitespace char, or
|
||||
| # a non-breaking space entity, or
|
||||
-- | # dashes, or
|
||||
&[mn]dash; | # named dash entities
|
||||
$dec_dashes | # or decimal entities
|
||||
&\\#x201[34]; # or hex
|
||||
)
|
||||
' # the quote
|
||||
(?=\\w) # followed by a word character
|
||||
}x", '\1‘', $_);
|
||||
# Single closing quotes:
|
||||
$_ = preg_replace("{
|
||||
($close_class)?
|
||||
'
|
||||
(?(1)| # If $1 captured, then do nothing;
|
||||
(?=\\s | s\\b) # otherwise, positive lookahead for a whitespace
|
||||
) # char or an 's' at a word ending position. This
|
||||
# is a special case to handle something like:
|
||||
# \"<i>Custer</i>'s Last Stand.\"
|
||||
}xi", '\1’', $_);
|
||||
|
||||
# Any remaining single quotes should be opening ones:
|
||||
$_ = str_replace("'", '‘', $_);
|
||||
|
||||
|
||||
# Get most opening double quotes:
|
||||
$_ = preg_replace("{
|
||||
(
|
||||
\\s | # a whitespace char, or
|
||||
| # a non-breaking space entity, or
|
||||
-- | # dashes, or
|
||||
&[mn]dash; | # named dash entities
|
||||
$dec_dashes | # or decimal entities
|
||||
&\\#x201[34]; # or hex
|
||||
)
|
||||
\" # the quote
|
||||
(?=\\w) # followed by a word character
|
||||
}x", '\1“', $_);
|
||||
|
||||
# Double closing quotes:
|
||||
$_ = preg_replace("{
|
||||
($close_class)?
|
||||
\"
|
||||
(?(1)|(?=\\s)) # If $1 captured, then do nothing;
|
||||
# if not, then make sure the next char is whitespace.
|
||||
}x", '\1”', $_);
|
||||
|
||||
# Any remaining quotes should be opening ones.
|
||||
$_ = str_replace('"', '“', $_);
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateBackticks($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
# Returns: The string, with ``backticks'' -style double quotes
|
||||
# translated into HTML curly quote entities.
|
||||
#
|
||||
# Example input: ``Isn't this fun?''
|
||||
# Example output: “Isn't this fun?”
|
||||
#
|
||||
|
||||
$_ = str_replace(array("``", "''",),
|
||||
array('“', '”'), $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateSingleBackticks($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
# Returns: The string, with `backticks' -style single quotes
|
||||
# translated into HTML curly quote entities.
|
||||
#
|
||||
# Example input: `Isn't this fun?'
|
||||
# Example output: ‘Isn’t this fun?’
|
||||
#
|
||||
|
||||
$_ = str_replace(array("`", "'",),
|
||||
array('‘', '’'), $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateDashes($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
#
|
||||
# Returns: The string, with each instance of "--" translated to
|
||||
# an em-dash HTML entity.
|
||||
#
|
||||
|
||||
$_ = str_replace('--', '—', $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateDashesOldSchool($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
#
|
||||
# Returns: The string, with each instance of "--" translated to
|
||||
# an en-dash HTML entity, and each "---" translated to
|
||||
# an em-dash HTML entity.
|
||||
#
|
||||
|
||||
# em en
|
||||
$_ = str_replace(array("---", "--",),
|
||||
array('—', '–'), $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateDashesOldSchoolInverted($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
#
|
||||
# Returns: The string, with each instance of "--" translated to
|
||||
# an em-dash HTML entity, and each "---" translated to
|
||||
# an en-dash HTML entity. Two reasons why: First, unlike the
|
||||
# en- and em-dash syntax supported by
|
||||
# EducateDashesOldSchool(), it's compatible with existing
|
||||
# entries written before SmartyPants 1.1, back when "--" was
|
||||
# only used for em-dashes. Second, em-dashes are more
|
||||
# common than en-dashes, and so it sort of makes sense that
|
||||
# the shortcut should be shorter to type. (Thanks to Aaron
|
||||
# Swartz for the idea.)
|
||||
#
|
||||
|
||||
# en em
|
||||
$_ = str_replace(array("---", "--",),
|
||||
array('–', '—'), $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function EducateEllipses($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
# Returns: The string, with each instance of "..." translated to
|
||||
# an ellipsis HTML entity. Also converts the case where
|
||||
# there are spaces between the dots.
|
||||
#
|
||||
# Example input: Huh...?
|
||||
# Example output: Huh…?
|
||||
#
|
||||
|
||||
$_ = str_replace(array("...", ". . .",), '…', $_);
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function StupefyEntities($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
# Returns: The string, with each SmartyPants HTML entity translated to
|
||||
# its ASCII counterpart.
|
||||
#
|
||||
# Example input: “Hello — world.”
|
||||
# Example output: "Hello -- world."
|
||||
#
|
||||
|
||||
# en-dash em-dash
|
||||
$_ = str_replace(array('–', '—'),
|
||||
array('-', '--'), $_);
|
||||
|
||||
# single quote open close
|
||||
$_ = str_replace(array('‘', '’'), "'", $_);
|
||||
|
||||
# double quote open close
|
||||
$_ = str_replace(array('“', '”'), '"', $_);
|
||||
|
||||
$_ = str_replace('…', '...', $_); # ellipsis
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
function ProcessEscapes($_) {
|
||||
#
|
||||
# Parameter: String.
|
||||
# Returns: The string, with after processing the following backslash
|
||||
# escape sequences. This is useful if you want to force a "dumb"
|
||||
# quote or other character to appear.
|
||||
#
|
||||
# Escape Value
|
||||
# ------ -----
|
||||
# \\ \
|
||||
# \" "
|
||||
# \' '
|
||||
# \. .
|
||||
# \- -
|
||||
# \` `
|
||||
#
|
||||
$_ = str_replace(
|
||||
array('\\\\', '\"', "\'", '\.', '\-', '\`'),
|
||||
array('\', '"', ''', '.', '-', '`'), $_);
|
||||
|
||||
return $_;
|
||||
}
|
||||
|
||||
|
||||
# _TokenizeHTML is shared between PHP SmartyPants and PHP Markdown.
|
||||
# We only define it if it is not already defined.
|
||||
if (!function_exists('_TokenizeHTML')) :
|
||||
function _TokenizeHTML($str) {
|
||||
#
|
||||
# Parameter: String containing HTML markup.
|
||||
# Returns: An array of the tokens comprising the input
|
||||
# string. Each token is either a tag (possibly with nested,
|
||||
# tags contained therein, such as <a href="<MTFoo>">, or a
|
||||
# run of text between tags. Each element of the array is a
|
||||
# two-element array; the first is either 'tag' or 'text';
|
||||
# the second is the actual value.
|
||||
#
|
||||
#
|
||||
# Regular expression derived from the _tokenize() subroutine in
|
||||
# Brad Choate's MTRegex plugin.
|
||||
# <http://www.bradchoate.com/past/mtregex.php>
|
||||
#
|
||||
$index = 0;
|
||||
$tokens = array();
|
||||
|
||||
$match = '(?s:<!(?:--.*?--\s*)+>)|'. # comment
|
||||
'(?s:<\?.*?\?>)|'. # processing instruction
|
||||
# regular tags
|
||||
'(?:<[/!$]?[-a-zA-Z0-9:]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)';
|
||||
|
||||
$parts = preg_split("{($match)}", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (++$index % 2 && $part != '')
|
||||
$tokens[] = array('text', $part);
|
||||
else
|
||||
$tokens[] = array('tag', $part);
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
endif;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
PHP SmartyPants
|
||||
===============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This is a PHP translation of the original SmartyPants quote educator written in
|
||||
Perl by John Gruber.
|
||||
|
||||
SmartyPants is a web publishing utility that translates plain ASCII
|
||||
punctuation characters into "smart" typographic punctuation HTML
|
||||
entities. SmartyPants can perform the following transformations:
|
||||
|
||||
* Straight quotes (`"` and `'`) into "curly" quote HTML entities
|
||||
* Backticks-style quotes (` ``like this'' `) into "curly" quote HTML
|
||||
entities
|
||||
* Dashes (`--` and `---`) into en- and em-dash entities
|
||||
* Three consecutive dots (`...`) into an ellipsis entity
|
||||
|
||||
SmartyPants does not modify characters within `<pre>`, `<code>`, `<kbd>`,
|
||||
`<script>`, or `<math>` tag blocks. Typically, these tags are used to
|
||||
display text where smart quotes and other "smart punctuation" would not
|
||||
be appropriate, such as source code or example markup.
|
||||
|
||||
|
||||
### Backslash Escapes ###
|
||||
|
||||
If you need to use literal straight quotes (or plain hyphens and
|
||||
periods), SmartyPants accepts the following backslash escape sequences
|
||||
to force non-smart punctuation. It does so by transforming the escape
|
||||
sequence into a decimal-encoded HTML entity:
|
||||
|
||||
Escape Value Character
|
||||
------ ----- ---------
|
||||
\\ \ \
|
||||
\" " "
|
||||
\' ' '
|
||||
\. . .
|
||||
\- - -
|
||||
\` ` `
|
||||
|
||||
This is useful, for example, when you want to use straight quotes as
|
||||
foot and inch marks: 6'2" tall; a 17" iMac.
|
||||
|
||||
|
||||
Bugs
|
||||
----
|
||||
|
||||
To file bug reports or feature requests (other than topics listed in the
|
||||
Caveats section above) please send email to:
|
||||
|
||||
<michel.fortin@michelf.com>
|
||||
|
||||
If the bug involves quotes being curled the wrong way, please send example
|
||||
text to illustrate.
|
||||
|
||||
|
||||
### Algorithmic Shortcomings ###
|
||||
|
||||
One situation in which quotes will get curled the wrong way is when
|
||||
apostrophes are used at the start of leading contractions. For example:
|
||||
|
||||
'Twas the night before Christmas.
|
||||
|
||||
In the case above, SmartyPants will turn the apostrophe into an opening
|
||||
single-quote, when in fact it should be a closing one. I don't think
|
||||
this problem can be solved in the general case -- every word processor
|
||||
I've tried gets this wrong as well. In such cases, it's best to use the
|
||||
proper HTML entity for closing single-quotes (`’`) by hand.
|
||||
|
||||
|
||||
Version History
|
||||
---------------
|
||||
|
||||
1.5.1e (9 Dec 2005)
|
||||
|
||||
* Corrected a bug that prevented special characters from being
|
||||
escaped.
|
||||
|
||||
|
||||
1.5.1d (25 May 2005)
|
||||
|
||||
* Corrected a small bug in `_TokenizeHTML` where a Doctype declaration
|
||||
was not seen as HTML (smart quotes where applied inside).
|
||||
|
||||
|
||||
1.5.1c (13 Dec 2004)
|
||||
|
||||
* Changed a regular expression in `_TokenizeHTML` that could lead to
|
||||
a segmentation fault with PHP 4.3.8 on Linux.
|
||||
|
||||
|
||||
1.5.1b (6 Sep 2004)
|
||||
|
||||
* Corrected a problem with quotes immediately following a dash
|
||||
with no space between: `Text--"quoted text"--text.`
|
||||
|
||||
* PHP SmartyPants can now be used as a modifier by the Smarty
|
||||
template engine. Rename the file to "modifier.smartypants.php"
|
||||
and put it in your smarty plugins folder.
|
||||
|
||||
* Replaced a lot of space characters by tabs, saving about 4 KB.
|
||||
|
||||
|
||||
1.5.1a (30 Jun 2004)
|
||||
|
||||
* PHP Markdown and PHP Smartypants now share the same `_TokenizeHTML`
|
||||
function when loaded simultanously.
|
||||
|
||||
* Changed the internals of `_TokenizeHTML` to lower the PHP version
|
||||
requirement to PHP 4.0.5.
|
||||
|
||||
|
||||
1.5.1 (6 Jun 2004)
|
||||
|
||||
* Initial release of PHP SmartyPants, based on version 1.5.1 of the
|
||||
original SmartyPants written in Perl.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
John Gruber
|
||||
<http://daringfireball.net/>
|
||||
|
||||
Ported to PHP by Michel Fortin
|
||||
<http://www.michelf.com/>
|
||||
|
||||
|
||||
Additional Credits
|
||||
------------------
|
||||
|
||||
Portions of this plug-in are based on Brad Choate's nifty MTRegex plug-in.
|
||||
Brad Choate also contributed a few bits of source code to this plug-in.
|
||||
Brad Choate is a fine hacker indeed. (<http://bradchoate.com/>)
|
||||
|
||||
Jeremy Hedley (<http://antipixel.com/>) and Charles Wiltgen
|
||||
(<http://playbacktime.com/>) deserve mention for exemplary beta testing.
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright (c) 2003 John Gruber
|
||||
<http://daringfireball.net/>
|
||||
All rights reserved.
|
||||
|
||||
Copyright (c) 2004-2005 Michel Fortin
|
||||
<http://www.michelf.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name "SmartyPants" nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
This software is provided by the copyright holders and contributors "as is"
|
||||
and any express or implied warranties, including, but not limited to, the
|
||||
implied warranties of merchantability and fitness for a particular purpose
|
||||
are disclaimed. In no event shall the copyright owner or contributors be
|
||||
liable for any direct, indirect, incidental, special, exemplary, or
|
||||
consequential damages (including, but not limited to, procurement of
|
||||
substitute goods or services; loss of use, data, or profits; or business
|
||||
interruption) however caused and on any theory of liability, whether in
|
||||
contract, strict liability, or tort (including negligence or otherwise)
|
||||
arising in any way out of the use of this software, even if advised of the
|
||||
possibility of such damage.
|
||||
|
||||
*/
|
||||
?>
|
326
_site/tmp/var/www/chaospott.de/engine/Post.php
Normal file
326
_site/tmp/var/www/chaospott.de/engine/Post.php
Normal file
@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
$fdir = dirname(__FILE__);
|
||||
require_once($fdir . '/PHPMarkdownExtra/markdown.php');
|
||||
require_once($fdir . '/PHPSmartyPants/smartypants.php');
|
||||
require_once($fdir . '/Updater.php');
|
||||
require_once($fdir . '/Template.php');
|
||||
require_once($fdir . '/Utils.php');
|
||||
|
||||
class Post
|
||||
{
|
||||
public static $blog_title = 'Untitled Blog';
|
||||
public static $blog_url = 'http://no-idea.com/';
|
||||
public static $blog_description = 'About my blog.';
|
||||
|
||||
public $source_filename = '';
|
||||
public $title = '';
|
||||
public $is_draft = false;
|
||||
public $publish_now = false;
|
||||
public $timestamp = 0;
|
||||
public $slug = '';
|
||||
public $type = '';
|
||||
public $headers = array();
|
||||
public $tags = array();
|
||||
public $body = '';
|
||||
|
||||
public $year;
|
||||
public $month;
|
||||
public $day;
|
||||
public $offset_in_day;
|
||||
|
||||
public $is_first_post_on_this_date = false; // Used for index-page rendering
|
||||
|
||||
public static function from_files(array $filenames)
|
||||
{
|
||||
$posts = array();
|
||||
$last_date = false;
|
||||
foreach ($filenames as $f) {
|
||||
if (! file_exists($f)) continue;
|
||||
$post = new Post($f);
|
||||
$date = $post->year . $post->month . $post->day;
|
||||
if ($date != $last_date) {
|
||||
$post->is_first_post_on_this_date = true;
|
||||
$last_date = $date;
|
||||
}
|
||||
$posts[] = $post;
|
||||
}
|
||||
return $posts;
|
||||
}
|
||||
|
||||
public static function next_sequence_number_for_day($filename_prefix)
|
||||
{
|
||||
$max = 0;
|
||||
foreach (glob($filename_prefix . '*' . Updater::$post_extension) as $filename) {
|
||||
$n = intval(substr(substring_after($filename, $filename_prefix), 0, 2));
|
||||
if ($n > $max) $max = $n;
|
||||
}
|
||||
return str_pad($max + 1, 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
public function __construct($source_filename, $is_draft = -1 /* auto */)
|
||||
{
|
||||
$this->source_filename = $source_filename;
|
||||
$this->is_draft = ($is_draft === -1 ? (false !== strpos($source_filename, 'drafts/') || false !== strpos($source_filename, 'pages/')) : $is_draft);
|
||||
$this->timestamp = filemtime($source_filename);
|
||||
|
||||
$segments = preg_split( '/\R\R/', trim(file_get_contents($source_filename)), 2);
|
||||
if (! isset($segments[1])) $segments[1] = '';
|
||||
|
||||
if (count($segments) > 1) {
|
||||
// Read headers for Tag, Type values
|
||||
$headers = explode("\n", $segments[0]);
|
||||
$has_title_yet = false;
|
||||
foreach ($headers as $header) {
|
||||
if (isset($header[0]) && $header[0] == '=') {
|
||||
$has_title_yet = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $has_title_yet) {
|
||||
$has_title_yet = true;
|
||||
$this->title = $header;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->is_draft && strtolower($header) == 'publish-now') {
|
||||
$this->publish_now = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$fields = explode(':', $header, 2);
|
||||
if (count($fields) < 2) continue;
|
||||
$fname = strtolower($fields[0]);
|
||||
$fields[1] = trim($fields[1]);
|
||||
if ($fname == 'tags') {
|
||||
$this->tags = self::parse_tag_str($fields[1]);
|
||||
} else if ($fname == 'type') {
|
||||
$this->type = str_replace('|', ' ', $fields[1]);
|
||||
} else if ($fname == 'published') {
|
||||
$this->timestamp = strtotime($fields[1]);
|
||||
} else {
|
||||
$this->headers[$fname] = $fields[1];
|
||||
}
|
||||
|
||||
if (isset($this->headers['link'])) $this->type = 'link';
|
||||
}
|
||||
array_shift($segments);
|
||||
}
|
||||
|
||||
$this->body = isset($segments[0]) ? $segments[0] : '';
|
||||
|
||||
$filename = basename($source_filename);
|
||||
$filename_datestr = substr($filename, 0, 8);
|
||||
if (is_numeric($filename_datestr)) {
|
||||
$this->year = intval(substr($filename_datestr, 0, 4));
|
||||
$this->month = intval(substr($filename_datestr, 4, 2));
|
||||
$this->day = intval(substr($filename_datestr, 6, 2));
|
||||
$this->offset_in_day = intval(substr($filename, 9, 2));
|
||||
$this->slug = ltrim(substr($filename, 11, -(strlen(Updater::$post_extension))), '-');
|
||||
} else {
|
||||
$this->year = intval(idate('Y', $this->timestamp));
|
||||
$this->month = intval(idate('m', $this->timestamp));
|
||||
$this->day = intval(idate('d', $this->timestamp));
|
||||
$posts_in_ym = Updater::posts_in_year_month($this->year, $this->month);
|
||||
$this->offset_in_day = isset($posts_in_ym[$this->day]) ? count($posts_in_ym[$this->day]) + 1 : 1;
|
||||
$this->slug = substring_before($filename, '.');
|
||||
}
|
||||
|
||||
if (! $this->is_draft && $source_filename != $this->expected_source_filename()) {
|
||||
error_log("Expected filename mismatch:\nfilename: $source_filename\nexpected: " . $this->expected_source_filename());
|
||||
}
|
||||
}
|
||||
|
||||
public function expected_source_filename($for_new_file = false)
|
||||
{
|
||||
$padded_month = str_pad($this->month, 2, '0', STR_PAD_LEFT);
|
||||
$padded_day = str_pad($this->day, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
$prefix =
|
||||
Updater::$source_path . '/posts/' .
|
||||
$this->year . '/' . $padded_month . '/' .
|
||||
$this->year . $padded_month . $padded_day . '-'
|
||||
;
|
||||
|
||||
if ($for_new_file) $padded_offset = self::next_sequence_number_for_day($prefix);
|
||||
else $padded_offset = str_pad($this->offset_in_day, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
if ($for_new_file) {
|
||||
$slug = trim(preg_replace('/[^a-z0-9-]+/ms', '-', strtolower($this->slug)), '-');
|
||||
if (! $slug) $slug = 'post';
|
||||
} else {
|
||||
$slug = $this->slug;
|
||||
}
|
||||
|
||||
return $prefix . $padded_offset . '-' . strtolower($slug) . Updater::$post_extension;
|
||||
}
|
||||
|
||||
public function normalized_source()
|
||||
{
|
||||
$out_headers = $this->headers;
|
||||
|
||||
if ($this->is_draft) unset($out_headers['published']);
|
||||
else $out_headers['published'] = date('Y-m-d h:i:sa', $this->timestamp);
|
||||
$source = $this->title . "\n" . str_repeat('=', max(10, min(40, strlen($this->title)))) . "\n";
|
||||
if ($this->type) $out_headers['type'] = $this->type;
|
||||
if ($this->tags) $out_headers['tags'] = implode(', ', $this->tags);
|
||||
foreach ($out_headers as $k => $v) $source .= ucfirst($k) . ': ' . $v . "\n";
|
||||
$source .= "\n" . $this->body;
|
||||
return $source;
|
||||
}
|
||||
|
||||
public function array_for_template()
|
||||
{
|
||||
$tags = array();
|
||||
foreach ($this->tags as $tag) { $tags[$tag] = array('post-tag' => $tag); }
|
||||
|
||||
// Convert relative image references to absolute so index pages work
|
||||
$base_uri = '/' . $this->year . '/' . str_pad($this->month, 2, '0', STR_PAD_LEFT) . '/' . str_pad($this->day, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
return array_merge(
|
||||
$this->headers,
|
||||
array(
|
||||
'post-title' => html_entity_decode(SmartyPants($this->title), ENT_QUOTES, 'UTF-8'),
|
||||
'post-slug' => $this->slug,
|
||||
'post-timestamp' => $this->timestamp,
|
||||
'post-rss-date' => date('D, d M Y H:i:s T', $this->timestamp),
|
||||
'post-body' => SmartyPants(Markdown($this->body)),
|
||||
'post-tags' => $tags,
|
||||
'post-type' => $this->type,
|
||||
'post-permalink' => $base_uri . '/' . $this->slug,
|
||||
'post-permalink-or-link' => isset($this->headers['link']) && $this->headers['link'] ? $this->headers['link'] : $base_uri . '/' . $this->slug,
|
||||
'post-absolute-permalink' => rtrim(self::$blog_url, '/') . $base_uri . '/' . $this->slug,
|
||||
'post-absolute-permalink-or-link' => rtrim(self::$blog_url, '/') . (isset($this->headers['link']) && $this->headers['link'] ? $this->headers['link'] : $base_uri . '/' . $this->slug),
|
||||
|
||||
'post-is-first-on-date' => $this->is_first_post_on_this_date ? 'yes' : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function write_page()
|
||||
{
|
||||
$t = new Template(Updater::$page_template);
|
||||
$t->content = array(
|
||||
'page-title' => html_entity_decode(SmartyPants($this->title), ENT_QUOTES, 'UTF-8'),
|
||||
'page-body' => SmartyPants(Markdown($this->body)),
|
||||
'blog-title' => html_entity_decode(SmartyPants(self::$blog_title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-url' => self::$blog_url,
|
||||
'blog-description' => html_entity_decode(SmartyPants(self::$blog_description), ENT_QUOTES, 'UTF-8'),
|
||||
'page-type' => 'page',
|
||||
'archives' => array(),
|
||||
'previous_page_url' => false,
|
||||
'next_page_url' => false,
|
||||
);
|
||||
$output_html = $t->outputHTML();
|
||||
|
||||
if (! file_exists(Updater::$dest_path)) mkdir_as_parent_owner(Updater::$dest_path, 0755, true);
|
||||
file_put_contents_as_dir_owner(Updater::$dest_path . '/' . $this->slug, $output_html);
|
||||
}
|
||||
|
||||
public function write_permalink_page($draft = false)
|
||||
{
|
||||
$post_data = $this->array_for_template();
|
||||
$post_data['post-is-first-on-date'] = true;
|
||||
|
||||
$t = new Template(Updater::$permalink_template);
|
||||
$t->content = array_merge(
|
||||
$post_data,
|
||||
array(
|
||||
'page-title' => html_entity_decode(SmartyPants(self::$blog_title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-title' => html_entity_decode(SmartyPants(self::$blog_title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-url' => self::$blog_url,
|
||||
'blog-description' => html_entity_decode(SmartyPants(self::$blog_description), ENT_QUOTES, 'UTF-8'),
|
||||
'page-type' => 'post',
|
||||
'posts' => array($post_data),
|
||||
'post' => $post_data,
|
||||
'archives' => array(),
|
||||
'previous_page_url' => false,
|
||||
'next_page_url' => false,
|
||||
)
|
||||
);
|
||||
$output_html = $t->outputHTML();
|
||||
|
||||
if (! $draft || Updater::$write_public_drafts) {
|
||||
$output_www_path = $draft ? '/drafts' : dirname($post_data['post-permalink']);
|
||||
$output_path = Updater::$dest_path . $output_www_path;
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
file_put_contents_as_dir_owner(Updater::$dest_path . ($draft ? '/drafts/' . $this->slug : $post_data['post-permalink']), $output_html);
|
||||
}
|
||||
|
||||
if ($draft) file_put_contents_as_dir_owner(Updater::$source_path . '/drafts/_previews/' . $this->slug . '.html', $output_html);
|
||||
}
|
||||
|
||||
public static function write_index($dest_path, $title, $type, array $posts, $template = 'main.html', $archive_array = false, $seq_count = 0)
|
||||
{
|
||||
$posts_data = array();
|
||||
foreach ($posts as $p) $posts_data[] = $p->array_for_template();
|
||||
|
||||
$t = new Template($template);
|
||||
$t->content = array(
|
||||
'page-title' => html_entity_decode(SmartyPants($title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-title' => html_entity_decode(SmartyPants(self::$blog_title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-url' => self::$blog_url,
|
||||
'blog-description' => html_entity_decode(SmartyPants(self::$blog_description), ENT_QUOTES, 'UTF-8'),
|
||||
'page-type' => $type,
|
||||
'posts' => $posts_data,
|
||||
'previous_page_url' => false,
|
||||
'next_page_url' => $seq_count > 1 ? substring_after(substring_before($dest_path, '.', true), Updater::$dest_path) . '-2' : false,
|
||||
'archives' => $archive_array ? $archive_array : array(),
|
||||
);
|
||||
$output_html = $t->outputHTML();
|
||||
|
||||
$output_path = dirname($dest_path);
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
file_put_contents_as_dir_owner($dest_path, $output_html);
|
||||
}
|
||||
|
||||
public function write_index_sequence($dest_path, $title, $type, array $posts, $template = 'main.html', $archive_array = false, $posts_per_page = 20)
|
||||
{
|
||||
$sequence = 0;
|
||||
$new_dest_path = $dest_path;
|
||||
// $dest_uri = substring_after(substring_before($dest_path, '.', true), Updater::$dest_path);
|
||||
$dest_uri = substring_after(substring_after($dest_path, '/', true), Updater::$dest_path);
|
||||
$total_sequences = ceil(count($posts) / $posts_per_page);
|
||||
while ($posts) {
|
||||
$sequence++;
|
||||
$seq_array = array_splice($posts, 0, $posts_per_page);
|
||||
if ($sequence == 1) continue; // skip writing the redundant "-1" page
|
||||
|
||||
$new_dest_path = $dest_path . '-' . $sequence . '.html';
|
||||
|
||||
$posts_data = array();
|
||||
foreach ($seq_array as $p) $posts_data[] = $p->array_for_template();
|
||||
|
||||
$t = new Template($template);
|
||||
$t->content = array(
|
||||
'page-title' => html_entity_decode(SmartyPants($title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-title' => html_entity_decode(SmartyPants(self::$blog_title), ENT_QUOTES, 'UTF-8'),
|
||||
'blog-url' => self::$blog_url,
|
||||
'blog-description' => html_entity_decode(SmartyPants(self::$blog_description), ENT_QUOTES, 'UTF-8'),
|
||||
'page-type' => $type,
|
||||
'posts' => $posts_data,
|
||||
'previous_page_url' => $sequence != 1 ? ($sequence == 2 ? $dest_uri : $dest_uri . '-' . ($sequence - 1)) : false,
|
||||
'next_page_url' => $sequence < $total_sequences ? $dest_uri . '-' . ($sequence + 1) : false,
|
||||
'archives' => $archive_array ? $archive_array : array(),
|
||||
);
|
||||
$output_html = $t->outputHTML();
|
||||
|
||||
$output_path = dirname($new_dest_path);
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
file_put_contents_as_dir_owner($new_dest_path, $output_html);
|
||||
}
|
||||
|
||||
return $total_sequences;
|
||||
}
|
||||
|
||||
public static function parse_tag_str($tag_str)
|
||||
{
|
||||
// Tags are comma-separated, and any spaces between multiple words in a tag will be converted to underscores for URLs
|
||||
if (! strlen($tag_str)) return array();
|
||||
$tags = array_map('trim', explode(',', strtolower($tag_str)));
|
||||
$tags = str_replace(' ', '_', $tags);
|
||||
$tags = array_unique(array_filter($tags, 'strlen'));
|
||||
sort($tags);
|
||||
return $tags;
|
||||
}
|
||||
}
|
26
_site/tmp/var/www/chaospott.de/engine/Template.php
Normal file
26
_site/tmp/var/www/chaospott.de/engine/Template.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class Template
|
||||
{
|
||||
public static $template_dir = '.';
|
||||
|
||||
public $content = array();
|
||||
|
||||
private $template_filename = false;
|
||||
private $dom;
|
||||
|
||||
public function __construct($template_name)
|
||||
{
|
||||
$this->template_filename = self::$template_dir . '/' . $template_name;
|
||||
}
|
||||
|
||||
public function outputHTML()
|
||||
{
|
||||
ob_start();
|
||||
$content = $this->content;
|
||||
include($this->template_filename);
|
||||
$contents = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $contents;
|
||||
}
|
||||
}
|
726
_site/tmp/var/www/chaospott.de/engine/Updater.php
Normal file
726
_site/tmp/var/www/chaospott.de/engine/Updater.php
Normal file
@ -0,0 +1,726 @@
|
||||
<?php
|
||||
|
||||
require_once(dirname(__FILE__) . '/Post.php');
|
||||
require_once(dirname(__FILE__) . '/Hook.php');
|
||||
|
||||
class Updater
|
||||
{
|
||||
public static $source_path;
|
||||
public static $dest_path;
|
||||
public static $cache_path;
|
||||
public static $post_extension = '.md';
|
||||
|
||||
// This option writes each draft preview into (web root)/drafts/whatever-slug
|
||||
// Without it, drafts only reside in the (source)/drafts/_previews folder
|
||||
// and are not accessible publicly.
|
||||
public static $write_public_drafts = false;
|
||||
|
||||
public static $frontpage_post_limit = 4;
|
||||
public static $frontpage_template = 'front.php';
|
||||
public static $frontpage_tag_filter = '!rss-only';
|
||||
public static $frontpage_type_filter = false;
|
||||
public static $frontpage_paginate = false;
|
||||
|
||||
public static $logbuch_post_limit = 20;
|
||||
public static $logbuch_template = 'main.php';
|
||||
public static $logbuch_tag_filter = '!rss-only';
|
||||
public static $logbuch_type_filter = false;
|
||||
public static $logbuch_paginate = false;
|
||||
|
||||
public static $rss_post_limit = 20;
|
||||
public static $rss_template = 'rss.php';
|
||||
public static $rss_tag_filter = '!site-only';
|
||||
public static $rss_type_filter = false;
|
||||
|
||||
public static $archive_month_template = 'main.php';
|
||||
public static $archive_year_template = 'main.php';
|
||||
public static $archive_tag_filter = '!rss-only';
|
||||
public static $archive_type_filter = '!ad';
|
||||
|
||||
public static $tag_page_post_limit = 20;
|
||||
|
||||
public static $permalink_template = 'main.php';
|
||||
public static $tag_page_template = 'main.php';
|
||||
public static $type_page_template = 'main.php';
|
||||
public static $page_template = 'main.php';
|
||||
|
||||
public static $api_blog_id = 1;
|
||||
public static $api_blog_username = '';
|
||||
public static $api_blog_password = '';
|
||||
|
||||
public static $changes_were_written = false;
|
||||
|
||||
private static $index_to_be_updated = false;
|
||||
private static $index_months_to_be_updated = array();
|
||||
private static $tags_to_be_updated = array();
|
||||
private static $types_to_be_updated = array();
|
||||
private static $posts_to_be_updated = array();
|
||||
private static $pages_to_be_updated = array();
|
||||
|
||||
public static function posts_in_year_month($year, $month, $require_tag = false, $require_type = false)
|
||||
{
|
||||
$month = str_pad($month, 2, '0', STR_PAD_LEFT);
|
||||
$cache_fname = self::$cache_path . "/posts-$year-$month-" . md5($require_tag . ' ' . $require_type);
|
||||
if (file_exists($cache_fname)) {
|
||||
$files = unserialize(file_get_contents($cache_fname));
|
||||
} else {
|
||||
$all_files = self::filelist(self::$source_path . "/posts/$year/$month", true);
|
||||
ksort($all_files);
|
||||
$in_month = false;
|
||||
$files = array();
|
||||
foreach ($all_files as $fname => $info) {
|
||||
if (substr($fname, -(strlen(self::$post_extension))) != self::$post_extension) continue;
|
||||
|
||||
// Tag/type filtering
|
||||
list($ignored_hash, $type, $tags) = explode('|', $info, 3);
|
||||
$include = true;
|
||||
if ($require_type) {
|
||||
if ($require_type[0] == '!' && $type == $require_type) $include = false;
|
||||
else if ($require_type[0] != '!' && $type != $require_type) $include = false;
|
||||
}
|
||||
if ($require_tag) {
|
||||
if ($require_tag[0] == '!' && in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
|
||||
else if ($require_tag[0] != '!' && ! in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
|
||||
}
|
||||
if (! $include) continue;
|
||||
|
||||
list($y, $m, $d) = array_map('intval', array_slice(explode('/', $fname), -3, 3));
|
||||
$d = intval(substr($d, 6));
|
||||
if ($year == $y && $month == $m) {
|
||||
if (isset($files[$d])) $files[$d][] = $fname;
|
||||
else $files[$d] = array($fname);
|
||||
} else {
|
||||
if ($in_month) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
|
||||
file_put_contents_as_dir_owner($cache_fname, serialize($files));
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
public static function post_filenames_in_year_month($year, $month, $require_tag = false, $require_type = false)
|
||||
{
|
||||
$out = array();
|
||||
foreach (self::posts_in_year_month($year, $month, $require_tag, $require_type) as $day) {
|
||||
foreach ($day as $filename) $out[] = $filename;
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
private static function resequence_post_offsets($year, $month, $day)
|
||||
{
|
||||
$month = str_pad($month, 2, '0', STR_PAD_LEFT);
|
||||
$day = str_pad($day, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
error_log("Resequencing post offsets for $year-$month-$day");
|
||||
|
||||
$prefix = self::$source_path . "/posts/$year/$month/$year$month$day-";
|
||||
$files = glob($prefix . '*' . self::$post_extension);
|
||||
if (count($files) > 99) {
|
||||
error_log("Cannot resequence offsets for $year-$month-$day: too many posts (" . count($files) . ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$timestamps = array();
|
||||
foreach ($files as $filename) {
|
||||
$p = new Post($filename, false);
|
||||
if (in_array($p->timestamp, $timestamps)) {
|
||||
// Multiple posts with identical timestamp. No good way to handle this. Abort resequencing.
|
||||
error_log("Cannot resequence offsets for $year-$month-$day: multiple identical timestamps");
|
||||
return false;
|
||||
}
|
||||
$timestamps[$filename] = $p->timestamp;
|
||||
}
|
||||
asort($timestamps);
|
||||
|
||||
$offset = 0;
|
||||
$slugs = array();
|
||||
$out_files = array();
|
||||
$made_changes = false;
|
||||
foreach ($timestamps as $filename => $timestamp) {
|
||||
$offset++;
|
||||
|
||||
$slug = preg_replace('/-p[0-9]{1,2}$/ms', '', substr(basename($filename), 12, -(strlen(self::$post_extension))));
|
||||
if (! isset($slugs[$slug])) $slugs[$slug] = 1;
|
||||
else $slugs[$slug]++;
|
||||
|
||||
$correct_filename =
|
||||
$prefix .
|
||||
str_pad($offset, 2, '0', STR_PAD_LEFT) . '-' .
|
||||
$slug . ($slugs[$slug] < 2 ? '' : '-p' .$slugs[$slug]) .
|
||||
self::$post_extension
|
||||
;
|
||||
if ($filename != $correct_filename) {
|
||||
error_log("file [$filename] should be [$correct_filename]");
|
||||
if (isset($out_files[$correct_filename])) throw new Exception("Target-filename collision for [$correct_filename], this should never happen");
|
||||
$made_changes = true;
|
||||
$out_files[$correct_filename] = array(file_get_contents($filename), $timestamp);
|
||||
safe_unlink($filename);
|
||||
}
|
||||
|
||||
foreach ($out_files as $correct_filename => $a) {
|
||||
list($contents, $timestamp) = $a;
|
||||
file_put_contents_as_dir_owner($correct_filename, $contents);
|
||||
@touch($correct_filename, $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
return $made_changes;
|
||||
}
|
||||
|
||||
private static function filelist($dir, $parse_info_in_text_files = true, $use_cached_info = array(), &$deleted_files = array())
|
||||
{
|
||||
$out = array();
|
||||
if (is_dir($dir)) {
|
||||
if ($dh = opendir($dir)) {
|
||||
while ( ($file = readdir($dh) ) !== false) {
|
||||
if ($file[0] == '.') continue;
|
||||
$fullpath = $dir . '/' . $file;
|
||||
if (is_dir($fullpath)) {
|
||||
$out = array_merge($out, self::filelist($fullpath, $parse_info_in_text_files, $use_cached_info, $deleted_files));
|
||||
} else {
|
||||
if (isset($deleted_files[$fullpath])) unset($deleted_files[$fullpath]);
|
||||
|
||||
$new_stat_prefix = filemtime($fullpath) . '-' . filesize($fullpath);
|
||||
|
||||
if (isset($use_cached_info[$fullpath])) {
|
||||
$stat_prefix = substr($use_cached_info[$fullpath], 0, strpos($use_cached_info[$fullpath], '|'));
|
||||
if ($stat_prefix == $new_stat_prefix) continue;
|
||||
}
|
||||
|
||||
$tags = '';
|
||||
$type = '';
|
||||
if ($parse_info_in_text_files && substr($fullpath, -(strlen(self::$post_extension))) == self::$post_extension) {
|
||||
$post = new Post($fullpath);
|
||||
$tags = implode(',', $post->tags);
|
||||
$type = $post->type;
|
||||
$expected_fname = $post->expected_source_filename();
|
||||
if ($expected_fname != $fullpath && ! $post->is_draft) {
|
||||
rename($fullpath, $expected_fname);
|
||||
$fullpath = $expected_fname;
|
||||
}
|
||||
}
|
||||
|
||||
$out[$fullpath] = $new_stat_prefix . '|' . $type . '|' . $tags;
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public static function changed_files_in_directory($directory)
|
||||
{
|
||||
$cache_fname = self::$cache_path . '/dir-' . md5($directory);
|
||||
$changed = array();
|
||||
if (file_exists($cache_fname)) {
|
||||
$fileinfo = unserialize(file_get_contents($cache_fname));
|
||||
$doesnt_exist_anymore = $fileinfo;
|
||||
foreach (self::filelist($directory, true, $fileinfo, $doesnt_exist_anymore) as $filename => $new_info) {
|
||||
if (! isset($fileinfo[$filename]) || $fileinfo[$filename] != $new_info) {
|
||||
$changed[$filename] = array(isset($fileinfo[$filename]) ? $fileinfo[$filename] : '||', $new_info);
|
||||
$fileinfo[$filename] = $new_info;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($doesnt_exist_anymore as $deleted_fname => $old_info) {
|
||||
error_log("Deleted file: $deleted_fname");
|
||||
$changed[$deleted_fname] = array($old_info, '||');
|
||||
unset($fileinfo[$deleted_fname]);
|
||||
}
|
||||
} else {
|
||||
$fileinfo = self::filelist($directory, true);
|
||||
foreach ($fileinfo as $filename => $new_info) $changed[$filename] = array('||', $new_info);
|
||||
if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
|
||||
}
|
||||
if ($changed) file_put_contents_as_dir_owner($cache_fname, serialize($fileinfo));
|
||||
return $changed;
|
||||
}
|
||||
|
||||
public static function most_recent_post_filenames($limit = 0, $require_tag = false, $require_type = false)
|
||||
{
|
||||
$cache_fname = self::$cache_path . '/dir-' . md5(self::$source_path . '/posts');
|
||||
if (! file_exists($cache_fname)) throw new Exception('Cache files not found, expected in [' . self::$cache_path . ']');
|
||||
$fileinfo = unserialize(file_get_contents($cache_fname));
|
||||
krsort($fileinfo); // reverse-chrono
|
||||
|
||||
$posts = array();
|
||||
foreach ($fileinfo as $filename => $info) {
|
||||
if (substr($filename, -(strlen(self::$post_extension))) != self::$post_extension) continue;
|
||||
list($ignored_hash, $type, $tags) = explode('|', $info, 3);
|
||||
$include = true;
|
||||
if ($require_type) {
|
||||
if ($require_type[0] == '!' && $type == substr($require_type, 1)) $include = false;
|
||||
else if ($require_type[0] != '!' && $type != $require_type) $include = false;
|
||||
}
|
||||
|
||||
if ($require_tag) {
|
||||
if ($require_tag[0] == '!' && in_array(substr($require_tag, 1), Post::parse_tag_str($tags))) $include = false;
|
||||
else if ($require_tag[0] != '!' && ! in_array($require_tag, Post::parse_tag_str($tags))) $include = false;
|
||||
}
|
||||
|
||||
if (! $include) continue;
|
||||
$posts[] = $filename;
|
||||
if ($limit && count($posts) >= $limit) break;
|
||||
}
|
||||
return $posts;
|
||||
}
|
||||
|
||||
public static function set_has_posts_for_month($year, $month, $scope = '')
|
||||
{
|
||||
$cache_fname = self::$cache_path . "/months-with-posts-$scope";
|
||||
if (file_exists($cache_fname)) {
|
||||
$existing = unserialize(file_get_contents($cache_fname));
|
||||
} else {
|
||||
$existing = array();
|
||||
}
|
||||
|
||||
$changed = false;
|
||||
if (! isset($existing[$year])) {
|
||||
$existing[$year] = array($month => true);
|
||||
$changed = true;
|
||||
} else if (! isset($existing[$year][$month])) {
|
||||
$existing[$year][$month] = true;
|
||||
$changed = true;
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
if (! file_exists(self::$cache_path)) mkdir_as_parent_owner(self::$cache_path, 0755, true);
|
||||
file_put_contents_as_dir_owner($cache_fname, serialize($existing));
|
||||
}
|
||||
}
|
||||
|
||||
public static function months_with_posts($scope = '')
|
||||
{
|
||||
$cache_fname = self::$cache_path . "/months-with-posts-$scope";
|
||||
if (! file_exists($cache_fname)) throw new Exception('Cache files not found, expected ' . $cache_fname);
|
||||
return unserialize(file_get_contents($cache_fname));
|
||||
}
|
||||
|
||||
public static function archive_array($scope = '')
|
||||
{
|
||||
$out = array();
|
||||
foreach (self::months_with_posts($scope) as $year => $months) {
|
||||
foreach ($months as $month => $x) {
|
||||
$ts = mktime(0, 0, 0, $month, 15, $year);
|
||||
$out[$year . str_pad($month, 2, '0', STR_PAD_LEFT)] = array(
|
||||
'archives-uri' => "/$year/" . str_pad($month, 2, '0', STR_PAD_LEFT) . '/' . $scope,
|
||||
'archives-year' => $year,
|
||||
'archives-month-number' => intval($month),
|
||||
'archives-month-name' => date('F', $ts),
|
||||
'archives-month-short-name' => date('M', $ts),
|
||||
);
|
||||
}
|
||||
}
|
||||
arsort($out);
|
||||
return $out;
|
||||
}
|
||||
|
||||
public static function update_drafts()
|
||||
{
|
||||
foreach (self::changed_files_in_directory(self::$source_path . '/drafts') as $filename => $info) {
|
||||
self::$changes_were_written = true;
|
||||
|
||||
if (contains($filename, '/_publish-now/') && file_exists($filename)) {
|
||||
$post = new Post($filename, false);
|
||||
$expected_fname = $post->expected_source_filename(true);
|
||||
error_log("Publishing draft $filename");
|
||||
$dir = dirname($expected_fname);
|
||||
if (! file_exists($dir)) mkdir_as_parent_owner($dir, 0755, true);
|
||||
if (file_put_contents_as_dir_owner($expected_fname, $post->normalized_source())) safe_unlink($filename);
|
||||
self::post_hooks($post);
|
||||
}
|
||||
|
||||
if (! file_exists($filename)) {
|
||||
if (ends_with($filename, self::$post_extension)) {
|
||||
error_log("Deleted draft $filename");
|
||||
$slug = substring_before(basename($filename), '.', true);
|
||||
$html_preview_filename = self::$source_path . '/drafts/_previews/' . $slug . '.html';
|
||||
$webroot_preview_filename = self::$dest_path . '/drafts/' . $slug;
|
||||
if (file_exists($html_preview_filename)) safe_unlink($html_preview_filename);
|
||||
if (file_exists($webroot_preview_filename)) safe_unlink($webroot_preview_filename);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
|
||||
$post = new Post($filename, true);
|
||||
if ($post->publish_now) {
|
||||
$post = new Post($filename, false);
|
||||
$expected_fname = $post->expected_source_filename(true);
|
||||
error_log("Publishing draft $filename");
|
||||
$dir = dirname($expected_fname);
|
||||
if (! file_exists($dir)) mkdir_as_parent_owner($dir, 0755, true);
|
||||
if (file_put_contents_as_dir_owner($expected_fname, $post->normalized_source())) safe_unlink($filename);
|
||||
self::post_hooks($post);
|
||||
} else {
|
||||
$post->write_permalink_page(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function update_styles()
|
||||
{
|
||||
foreach (self::changed_files_in_directory(self::$source_path . '/templates') as $filename => $info) {
|
||||
$file_info = pathinfo($filename);
|
||||
if ($file_info['extension'] != 'css') continue;
|
||||
|
||||
error_log("Changed style file: $filename");
|
||||
$uri = substring_after($filename, self::$source_path . '/templates');
|
||||
$dest_filename = self::$dest_path . $uri;
|
||||
$output_path = dirname($dest_filename);
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
copy($filename, $dest_filename);
|
||||
self::$changes_were_written = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static function post_hooks($post)
|
||||
{
|
||||
$dir = self::$source_path . '/hooks';
|
||||
if (is_dir($dir)) {
|
||||
if ( ($dh = opendir($dir)) ) {
|
||||
while ( ($file = readdir($dh) ) !== false) {
|
||||
if ($file[0] == '.') continue;
|
||||
if (substr($file, 0, 5) == 'post_') {
|
||||
$fullpath = $dir . '/' . $file;
|
||||
require_once($fullpath);
|
||||
$className = ucfirst(substr($file, 5, strlen($file) - 9));
|
||||
$hook = new $className;
|
||||
$hook->doHook($post);
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function update_pages()
|
||||
{
|
||||
foreach (self::changed_files_in_directory(self::$source_path . '/pages') as $filename => $info) {
|
||||
self::$changes_were_written = true;
|
||||
|
||||
if (! file_exists($filename)) {
|
||||
if (ends_with($filename, self::$post_extension)) {
|
||||
error_log("Deleted page $filename");
|
||||
$dest_filename = self::$dest_path . '/' . substring_before(basename($filename), '.', true);
|
||||
if (file_exists($dest_filename)) safe_unlink($dest_filename);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
|
||||
$post = new Post($filename, true);
|
||||
$post->slug = basename($filename, self::$post_extension);
|
||||
error_log("Writing page [{$post->slug}]");
|
||||
$post->write_page(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const RESEQUENCED_POSTS = -1;
|
||||
public static function update()
|
||||
{
|
||||
if (! file_exists(self::$cache_path)) {
|
||||
// Starting fresh, probably multiple resequences to do.
|
||||
// Let them all happen at once.
|
||||
$status = self::_update(false);
|
||||
}
|
||||
|
||||
do {
|
||||
$status = self::_update();
|
||||
} while ($status == self::RESEQUENCED_POSTS);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private static function _update($restart_if_resequenced = true)
|
||||
{
|
||||
if (! file_exists(self::$dest_path)) mkdir_as_parent_owner(self::$dest_path, 0755, true);
|
||||
if (! file_exists(self::$dest_path . '/.htaccess')) copy(dirname(__FILE__) . '/default.htaccess', self::$dest_path . '/.htaccess');
|
||||
|
||||
if (! file_exists(self::$source_path . '/drafts/_publish-now')) mkdir_as_parent_owner(self::$source_path . '/drafts/_publish-now', 0755, true);
|
||||
if (! file_exists(self::$source_path . '/drafts/_previews')) mkdir_as_parent_owner(self::$source_path . '/drafts/_previews', 0755, true);
|
||||
if (! file_exists(self::$source_path . '/pages')) mkdir_as_parent_owner(self::$source_path . '/pages', 0755, true);
|
||||
|
||||
self::update_pages();
|
||||
self::update_drafts();
|
||||
self::update_styles();
|
||||
|
||||
foreach (self::changed_files_in_directory(self::$source_path . '/media') as $filename => $info) {
|
||||
error_log("Changed media file: $filename");
|
||||
$uri = substring_after($filename, self::$source_path);
|
||||
$dest_filename = self::$dest_path . $uri;
|
||||
$output_path = dirname($dest_filename);
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
copy($filename, $dest_filename);
|
||||
self::$changes_were_written = true;
|
||||
}
|
||||
|
||||
$resequence_days = array();
|
||||
|
||||
foreach (self::changed_files_in_directory(self::$source_path . '/posts') as $filename => $info) {
|
||||
self::$posts_to_be_updated[$filename] = true;
|
||||
|
||||
if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
|
||||
list($old_info, $new_info) = $info;
|
||||
list($old_hash, $old_type, $old_tags) = explode('|', $old_info, 3);
|
||||
list($new_hash, $new_type, $new_tags) = explode('|', $new_info, 3);
|
||||
|
||||
if ($old_type) self::$types_to_be_updated[$old_type] = true;
|
||||
if ($new_type) self::$types_to_be_updated[$new_type] = true;
|
||||
|
||||
foreach (Post::parse_tag_str($old_tags) as $tag) self::$tags_to_be_updated[$tag] = true;
|
||||
foreach (Post::parse_tag_str($new_tags) as $tag) self::$tags_to_be_updated[$tag] = true;
|
||||
}
|
||||
|
||||
$yearpos = strpos($filename, '/posts/') + 7;
|
||||
$year = substr($filename, $yearpos, 4);
|
||||
$month = substr($filename, $yearpos + 5, 2);
|
||||
$day = substr($filename, $yearpos + 14, 2);
|
||||
$resequence_days[$year . $month . $day] = array($year, $month, $day);
|
||||
self::$index_months_to_be_updated[$year . '-' . $month] = true;
|
||||
self::$index_to_be_updated = true;
|
||||
}
|
||||
|
||||
foreach (self::$posts_to_be_updated as $filename => $x) {
|
||||
if (! file_exists($filename)) {
|
||||
// This file was deleted. Delete corresponding output file
|
||||
$filename_datestr = substr(basename($filename), 0, 8);
|
||||
if (is_numeric($filename_datestr)) {
|
||||
$year = substr($filename_datestr, 0, 4);
|
||||
$month = substr($filename_datestr, 4, 2);
|
||||
$day = substr($filename_datestr, 6, 2);
|
||||
$slug = substr(basename($filename), 12, -(strlen(self::$post_extension)));
|
||||
$target_filename = self::$dest_path . "/$year/$month/$day/$slug";
|
||||
if ($year && $month && $day && $slug && file_exists($target_filename)) {
|
||||
error_log("Deleting abandoned target file: $target_filename");
|
||||
safe_unlink($target_filename);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
error_log("Updating post: $filename");
|
||||
self::$changes_were_written = true;
|
||||
|
||||
if (substr($filename, -(strlen(self::$post_extension))) == self::$post_extension) {
|
||||
$post = new Post($filename);
|
||||
$post->write_permalink_page();
|
||||
|
||||
self::set_has_posts_for_month($post->year, $post->month);
|
||||
foreach ($post->tags as $tag) self::set_has_posts_for_month($post->year, $post->month, 'tagged-' . $tag);
|
||||
if ($post->type) self::set_has_posts_for_month($post->year, $post->month, 'type-' . $post->type);
|
||||
|
||||
} else {
|
||||
$filename_datestr = substr(basename($filename), 0, 8);
|
||||
if (is_numeric($filename_datestr)) {
|
||||
$year = intval(substr($filename_datestr, 0, 4));
|
||||
$month = intval(substr($filename_datestr, 4, 2));
|
||||
$day = intval(substr($filename_datestr, 6, 2));
|
||||
if ($year && $month && $day) {
|
||||
$output_path = self::$dest_path . "/$year/" . str_pad($month, 2, '0', STR_PAD_LEFT) . '/' . str_pad($day, 2, '0', STR_PAD_LEFT);
|
||||
if (! file_exists($output_path)) mkdir_as_parent_owner($output_path, 0755, true);
|
||||
$output_filename = $output_path . '/' . basename($filename);
|
||||
copy($filename, $output_filename);
|
||||
$resequence_days[$year . $month . $day] = array($year, $month, $day);
|
||||
} else {
|
||||
error_log("Can't figure out where to put unrecognized numeric filename [$filename]");
|
||||
}
|
||||
} else {
|
||||
error_log("Can't figure out where to put unrecognized filename [$filename]");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$sequence_changed = false;
|
||||
foreach ($resequence_days as $a) {
|
||||
list($year, $month, $day) = array_map('intval', $a);
|
||||
if (self::resequence_post_offsets($year, $month, $day)) $sequence_changed = true;
|
||||
}
|
||||
|
||||
if ($sequence_changed && $restart_if_resequenced) {
|
||||
self::$changes_were_written = true;
|
||||
error_log("Resequencing was performed. Restarting update...");
|
||||
return self::RESEQUENCED_POSTS;
|
||||
}
|
||||
|
||||
if (! self::$index_to_be_updated) self::$index_to_be_updated = self::$index_months_to_be_updated || self::$tags_to_be_updated || self::$types_to_be_updated || self::$posts_to_be_updated;
|
||||
|
||||
if (self::$index_to_be_updated) {
|
||||
error_log("Updating frontpage...");
|
||||
self::$changes_were_written = true;
|
||||
|
||||
$seq_count = 0;
|
||||
if (self::$frontpage_paginate) {
|
||||
$seq_count = Post::write_index_sequence(
|
||||
self::$dest_path . "/index",
|
||||
Post::$blog_title,
|
||||
'frontpage',
|
||||
Post::from_files(self::most_recent_post_filenames(0, self::$frontpage_tag_filter, self::$frontpage_type_filter)),
|
||||
self::$frontpage_template,
|
||||
self::archive_array(),
|
||||
self::$frontpage_post_limit
|
||||
);
|
||||
}
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/index.html",
|
||||
Post::$blog_title,
|
||||
'frontpage',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, self::$frontpage_tag_filter, self::$frontpage_type_filter)),
|
||||
self::$frontpage_template,
|
||||
self::archive_array(),
|
||||
$seq_count
|
||||
);
|
||||
|
||||
$seq_count = 0;
|
||||
if (self::$logbuch_paginate) {
|
||||
$seq_count = Post::write_index_sequence(
|
||||
self::$dest_path . "/logbuch",
|
||||
Post::$blog_title,
|
||||
'frontpage',
|
||||
Post::from_files(self::most_recent_post_filenames(0, self::$logbuch_tag_filter, self::$flogbuch_type_filter)),
|
||||
self::$logbuch_template,
|
||||
self::archive_array(),
|
||||
self::$logbuch_post_limit
|
||||
);
|
||||
}
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/logbuch.html",
|
||||
Post::$blog_title,
|
||||
'frontpage',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$logbuch_post_limit, self::$logbuch_tag_filter, self::$logbuch_type_filter)),
|
||||
self::$logbuch_template,
|
||||
self::archive_array(),
|
||||
$seq_count
|
||||
);
|
||||
|
||||
error_log("Updating RSS...");
|
||||
Post::write_index(
|
||||
self::$dest_path . "/rss.xml",
|
||||
Post::$blog_title,
|
||||
'rss',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, self::$rss_tag_filter, self::$rss_type_filter)),
|
||||
self::$rss_template
|
||||
);
|
||||
}
|
||||
|
||||
foreach (self::$index_months_to_be_updated as $ym => $x) {
|
||||
error_log("Updating month index: $ym");
|
||||
self::$changes_were_written = true;
|
||||
|
||||
list($year, $month) = explode('-', $ym);
|
||||
$posts = Post::from_files(self::post_filenames_in_year_month($year, $month, self::$archive_tag_filter, self::$archive_type_filter));
|
||||
$ts = mktime(0, 0, 0, $month, 15, $year);
|
||||
Post::write_index(
|
||||
self::$dest_path . "/$year/$month/index.html",
|
||||
date('F Y', $ts),
|
||||
'archive',
|
||||
$posts,
|
||||
self::$archive_month_template,
|
||||
self::archive_array()
|
||||
);
|
||||
}
|
||||
|
||||
foreach (self::$tags_to_be_updated as $tag => $x) {
|
||||
if (! strlen($tag)) continue;
|
||||
error_log("Updating tag: $tag");
|
||||
self::$changes_were_written = true;
|
||||
|
||||
$seq_count = Post::write_index_sequence(
|
||||
self::$dest_path . "/tagged-$tag",
|
||||
Post::$blog_title,
|
||||
'tag',
|
||||
Post::from_files(self::most_recent_post_filenames(0, $tag, self::$archive_tag_filter)),
|
||||
self::$tag_page_template,
|
||||
self::archive_array(),
|
||||
self::$tag_page_post_limit
|
||||
);
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/tagged-$tag.html",
|
||||
Post::$blog_title,
|
||||
'tag',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, $tag, self::$archive_tag_filter)),
|
||||
self::$tag_page_template,
|
||||
self::archive_array('tagged-' . $tag),
|
||||
$seq_count
|
||||
);
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/tagged-$tag.xml",
|
||||
Post::$blog_title,
|
||||
'tag',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, $tag, self::$archive_tag_filter)),
|
||||
self::$rss_template,
|
||||
self::archive_array('tagged-' . $tag)
|
||||
);
|
||||
|
||||
$months_with_posts = self::months_with_posts('tagged-' . $tag);
|
||||
foreach (self::$index_months_to_be_updated as $ym => $x) {
|
||||
list($year, $month) = explode('-', $ym);
|
||||
if (! isset($months_with_posts[$year]) || ! isset($months_with_posts[$year][intval($month)])) continue;
|
||||
error_log("Updating month index: $ym for tag: $tag");
|
||||
$posts = Post::from_files(self::post_filenames_in_year_month($year, $month, $tag, self::$archive_type_filter));
|
||||
$ts = mktime(0, 0, 0, $month, 15, $year);
|
||||
Post::write_index(
|
||||
self::$dest_path . "/$year/$month/tagged-$tag.html",
|
||||
date('F Y', $ts),
|
||||
'tag',
|
||||
$posts,
|
||||
self::$tag_page_template,
|
||||
self::archive_array('tagged-' . $tag)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (self::$types_to_be_updated as $type => $x) {
|
||||
if (! strlen($type)) continue;
|
||||
error_log("Updating type: $type");
|
||||
self::$changes_were_written = true;
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/type-$type.html",
|
||||
Post::$blog_title,
|
||||
'type',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$frontpage_post_limit, self::$archive_type_filter, $type)),
|
||||
self::$type_page_template,
|
||||
self::archive_array('type-' . $type)
|
||||
);
|
||||
|
||||
Post::write_index(
|
||||
self::$dest_path . "/type-$type.xml",
|
||||
Post::$blog_title,
|
||||
'type',
|
||||
Post::from_files(self::most_recent_post_filenames(self::$rss_post_limit, self::$archive_type_filter, $type)),
|
||||
self::$rss_template,
|
||||
self::archive_array('type-' . $type)
|
||||
);
|
||||
|
||||
$months_with_posts = self::months_with_posts('type-' . $type);
|
||||
foreach (self::$index_months_to_be_updated as $ym => $x) {
|
||||
list($year, $month) = explode('-', $ym);
|
||||
if (! isset($months_with_posts[$year]) || ! isset($months_with_posts[$year][intval($month)])) continue;
|
||||
error_log("Updating month index: $ym for type: $type");
|
||||
$posts = Post::from_files(self::post_filenames_in_year_month($year, $month, self::$archive_tag_filter, $type));
|
||||
$ts = mktime(0, 0, 0, $month, 15, $year);
|
||||
Post::write_index(
|
||||
self::$dest_path . "/$year/$month/type-$type.html",
|
||||
date('F Y', $ts),
|
||||
'type',
|
||||
$posts,
|
||||
self::$type_page_template,
|
||||
self::archive_array('type-' . $type)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
201
_site/tmp/var/www/chaospott.de/engine/Utils.php
Normal file
201
_site/tmp/var/www/chaospott.de/engine/Utils.php
Normal file
@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
function _match_owners_if_possible($target_filename, $match_from_filename)
|
||||
{
|
||||
try {
|
||||
if (false === ($intended_uid = fileowner($match_from_filename)) ) throw new Exception("fileowner failed on source");
|
||||
if (false === ($intended_gid = filegroup($match_from_filename)) ) throw new Exception("filegroup failed on source");
|
||||
|
||||
if (false === ($uid = fileowner($target_filename)) ) throw new Exception("fileowner failed on target");
|
||||
if (false === ($gid = filegroup($target_filename)) ) throw new Exception("filegroup failed on target");
|
||||
|
||||
if ($intended_uid != $uid && ! chown($target_filename, $intended_uid)) throw new Exception("chown failed on target");
|
||||
if ($intended_gid != $gid && ! chgrp($target_filename, $intended_gid)) throw new Exception("chgrp failed on target");
|
||||
} catch (Exception $e) {
|
||||
error_log("Cannot assign ownership of [$target_filename] to owner of [$match_from_filename]: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function file_put_contents_as_dir_owner($filename, $data)
|
||||
{
|
||||
if (false !== ($ret = file_put_contents($filename, $data)) ) {
|
||||
_match_owners_if_possible($filename, dirname($filename));
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function mkdir_as_parent_owner($pathname, $mode = 0777, $recursive = false)
|
||||
{
|
||||
echo "$pathname\n";
|
||||
if (false !== ($ret = mkdir($pathname, $mode, $recursive)) ) {
|
||||
_match_owners_if_possible($pathname, dirname($pathname));
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function h($text)
|
||||
{
|
||||
$text =$text;// mb_convert_encoding($text, 'UTF-8', 'UTF-8');
|
||||
return htmlentities($text, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
function js_array($in_array)
|
||||
{
|
||||
if (! is_array($in_array)) return '[]';
|
||||
return '[' . implode(',', array_map('js_string', $in_array)) . ']';
|
||||
}
|
||||
|
||||
function js_string($input)
|
||||
{
|
||||
if (! strlen($input)) return "''";
|
||||
try {
|
||||
$wchars = mb_convert_encoding($input, 'UCS-2', 'UTF-8');
|
||||
$out = '';
|
||||
foreach (str_split($wchars, 2) as $wchar) {
|
||||
list($o1, $o2) = array(ord($wchar[0]), ord($wchar[1]));
|
||||
if ($o1 == 0 && (
|
||||
$o2 <= 0x1F ||
|
||||
$wchar[1] == '<' || $wchar[1] == '>' || $wchar[1] == '"' || $wchar[1] == '&'
|
||||
)) {
|
||||
$out .= '\x' . sprintf('%02x', $o2);
|
||||
} else if ($o1 == 0 && $wchar[1] == "\\") {
|
||||
$out .= "\\\\";
|
||||
} else if ($o1 == 0 && $wchar[1] == "'") {
|
||||
$out .= "\'";
|
||||
} else if ($o1 == 0 && $o2 <= 0x7F) {
|
||||
$out .= $wchar[1];
|
||||
} else {
|
||||
$out .= '\u' . sprintf('%02x%02x', $o1, $o2);
|
||||
}
|
||||
}
|
||||
return "'$out'";
|
||||
} catch (Exception $e) {
|
||||
error_log('js_string(): ' . $e->getMessage() . ' [input:[' . $input . ']]');
|
||||
|
||||
$str = str_replace(array('\\', "'"), array("\\\\", "\\'"), $input);
|
||||
$str = preg_replace('#([\x00-\x1F])#e', '"\x" . sprintf("%02x", ord("\1"))', $str);
|
||||
return "'{$str}'";
|
||||
}
|
||||
}
|
||||
|
||||
function starts_with($haystack, $needle)
|
||||
{
|
||||
return (substr($haystack, 0, strlen($needle)) == $needle);
|
||||
}
|
||||
|
||||
function ends_with($haystack, $needle)
|
||||
{
|
||||
return (substr($haystack, 0 - strlen($needle)) == $needle);
|
||||
}
|
||||
|
||||
function contains($haystack, $needle)
|
||||
{
|
||||
return (strpos($haystack, $needle) !== false);
|
||||
}
|
||||
|
||||
function contains_any($haystack, array $needles)
|
||||
{
|
||||
foreach ($needles as $needle) {
|
||||
if (strpos($haystack, $needle) !== false) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function contains_all($haystack, array $needles)
|
||||
{
|
||||
foreach ($needles as $needle) {
|
||||
if (strpos($haystack, $needle) === false) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function substring_before($haystack, $needle, $from_end = false)
|
||||
{
|
||||
if ($from_end) {
|
||||
if ( ($p = strrpos($haystack, $needle)) === false) return $haystack;
|
||||
} else {
|
||||
if ( ($p = strpos($haystack, $needle)) === false) return $haystack;
|
||||
}
|
||||
return substr($haystack, 0, $p);
|
||||
}
|
||||
|
||||
function substring_after($haystack, $needle, $from_end = false)
|
||||
{
|
||||
if ($from_end) {
|
||||
if ( ($p = strrpos($haystack, $needle)) === false) return $haystack;
|
||||
} else {
|
||||
if ( ($p = strpos($haystack, $needle)) === false) return $haystack;
|
||||
}
|
||||
return substr($haystack, $p + strlen($needle));
|
||||
}
|
||||
|
||||
function substring_between($haystack, $left_needle, $right_needle, $from_end = false)
|
||||
{
|
||||
return substring_before(
|
||||
substring_after($haystack, $left_needle), $right_needle, $from_end
|
||||
);
|
||||
}
|
||||
|
||||
function normalize_space($str, $trim_beginning_and_end = true)
|
||||
{
|
||||
if ($trim_beginning_and_end) $str = trim($str);
|
||||
$str = str_replace("\xC2\xA0", ' ', $str);
|
||||
return preg_replace('/\s\s+/ms', ' ', $str);
|
||||
}
|
||||
|
||||
function pluralize($number, $noun, $nouns = false)
|
||||
{
|
||||
if (! $nouns) $nouns = $noun . 's';
|
||||
return number_format($number) . ' ' . ($number == 1 ? $noun : $nouns);
|
||||
}
|
||||
|
||||
function array_to_verbal_list(array $a, $and_or_or = 'and')
|
||||
{
|
||||
$c = count($a);
|
||||
if (! $c) return '';
|
||||
if ($c == 1) return $a[0];
|
||||
if ($c == 2) return $a[0] . ' ' . $and_or_or . ' ' . $a[1];
|
||||
$last = array_pop($a);
|
||||
return implode(', ', $a) . ', ' . $and_or_or . ' ' . $last;
|
||||
}
|
||||
|
||||
function strip_tags_preserve_space($str, $allowable_tags = false)
|
||||
{
|
||||
$str = preg_replace('#([^ ])<(p|br|ul|ol|li)/?>#msi', '\\1 <\\2>', $str);
|
||||
return (
|
||||
$allowable_tags ? strip_tags($str, $allowable_tags) : strip_tags($str)
|
||||
);
|
||||
}
|
||||
|
||||
function summarize(
|
||||
$text, $length, $ellipsis = '...', $encoding = 'UTF-8',
|
||||
$strict_cut = false, $strict_sentences = false
|
||||
)
|
||||
{
|
||||
if ($length == 0) return $text;
|
||||
|
||||
if ($strict_sentences) {
|
||||
$split_char = '.';
|
||||
$ellipsis = '.' . $ellipsis;
|
||||
} else {
|
||||
$split_char = ' ';
|
||||
}
|
||||
|
||||
if (mb_strlen($text, $encoding) <= $length) return $text;
|
||||
$cut_str = mb_substr($text, 0, $length + 1, $encoding);
|
||||
$split_pos = (
|
||||
$cut_str ? mb_strrpos($cut_str, $split_char, $encoding) : false
|
||||
);
|
||||
|
||||
if ($split_pos) {
|
||||
return mb_substr($text, 0, $split_pos, $encoding) . $ellipsis;
|
||||
} else {
|
||||
return ($strict_cut ? $ellipsis : $cut_str . $ellipsis);
|
||||
}
|
||||
}
|
||||
|
||||
function safe_unlink($file)
|
||||
{
|
||||
try { @unlink($file); } catch (Exception $e) { }
|
||||
}
|
||||
|
16
_site/tmp/var/www/chaospott.de/engine/default.htaccess
Normal file
16
_site/tmp/var/www/chaospott.de/engine/default.htaccess
Normal file
@ -0,0 +1,16 @@
|
||||
Options -MultiViews
|
||||
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript text/xml text/rss text/rss+xml
|
||||
|
||||
RewriteEngine On
|
||||
|
||||
RewriteRule ^([^\.]*)$ - [T=text/html]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME}.html -f
|
||||
RewriteRule ^(.*)$ $1.html [QSA,L]
|
||||
|
||||
ErrorDocument 404 /404.html
|
||||
ErrorDocument 500 /500.html
|
||||
|
37
_site/tmp/var/www/chaospott.de/engine/update.php
Normal file
37
_site/tmp/var/www/chaospott.de/engine/update.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
define('LOCK_FILE', isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '/tmp/secondcrack-updater.pid');
|
||||
|
||||
// Ensure that no other instances are running
|
||||
if (file_exists(LOCK_FILE) &&
|
||||
($pid = intval(trim(file_get_contents(LOCK_FILE)))) &&
|
||||
posix_kill($pid, 0)
|
||||
) {
|
||||
fwrite(STDERR, "Already running [pid $pid]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (file_put_contents(LOCK_FILE, posix_getpid())) {
|
||||
register_shutdown_function(
|
||||
function() {
|
||||
try { unlink(LOCK_FILE); } catch (Exception $e) {
|
||||
fwrite(STDERR, "Cannot remove lock file [" . LOCK_FILE . "]: " . $e->getMessage() . "\n");
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
fwrite(STDERR, "Cannot write lock file: " . LOCK_FILE . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$fdir = dirname(__FILE__);
|
||||
require_once($fdir . '/Post.php');
|
||||
|
||||
$config_file = realpath(dirname(__FILE__) . '/..') . '/config.php';
|
||||
if (! file_exists($config_file)) {
|
||||
fwrite(STDERR, "Missing config file [$config_file]\nsee [$config_file.default] for an example\n");
|
||||
exit(1);
|
||||
}
|
||||
require_once($config_file);
|
||||
|
||||
Updater::update();
|
||||
exit(Updater::$changes_were_written ? 2 : 0);
|
47
_site/tmp/var/www/chaospott.de/engine/update.sh
Executable file
47
_site/tmp/var/www/chaospott.de/engine/update.sh
Executable file
@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$1" == "" -o "$2" == "" ] ; then
|
||||
echo ""
|
||||
echo "Usage: update.sh SOURCE_PATH SECONDCRACK_PATH"
|
||||
echo " where SOURCE_PATH contains /posts, /templates, ..."
|
||||
echo " and SECONDCRACK_PATH contains /cache, /engine, ..."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_PATH="$1"
|
||||
SECONDCRACK_PATH="$2"
|
||||
FORCE_CHECK_EVERY_SECONDS=30
|
||||
UPDATE_LOG=/tmp/secondcrack-update.log
|
||||
|
||||
SCRIPT_LOCK_FILE="${SECONDCRACK_PATH}/engine/secondcrack-updater.pid"
|
||||
BASH_LOCK_DIR="${SECONDCRACK_PATH}/engine/secondcrack-updater.sh.lock"
|
||||
|
||||
if mkdir "$BASH_LOCK_DIR" ; then
|
||||
trap "rmdir '$BASH_LOCK_DIR' 2>/dev/null ; exit" INT TERM EXIT
|
||||
|
||||
echo "`date` -- updating secondcrack" >> $UPDATE_LOG
|
||||
php -f "${SECONDCRACK_PATH}/engine/update.php" "$SCRIPT_LOCK_FILE"
|
||||
|
||||
if [ "`which inotifywait`" != "" ] ; then
|
||||
while true ; do
|
||||
inotifywait -q -q -r -t $FORCE_CHECK_EVERY_SECONDS -e close_write -e create -e delete -e moved_from "$SOURCE_PATH"
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo "`date` -- updating secondcrack, a source file changed" >> $UPDATE_LOG
|
||||
else
|
||||
echo "`date` -- updating secondcrack, $FORCE_CHECK_EVERY_SECONDS seconds elapsed" >> $UPDATE_LOG
|
||||
fi
|
||||
|
||||
php -f "${SECONDCRACK_PATH}/engine/update.php" "$SCRIPT_LOCK_FILE"
|
||||
while [ $? -eq 2 ] ; do
|
||||
echo "`date` -- updating secondcrack, last run performed writes" >> $UPDATE_LOG
|
||||
php -f "${SECONDCRACK_PATH}/engine/update.php" "$SCRIPT_LOCK_FILE"
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
rmdir "$BASH_LOCK_DIR" 2>/dev/null
|
||||
trap - INT TERM EXIT
|
||||
else
|
||||
echo "Already running"
|
||||
fi
|
Reference in New Issue
Block a user