Compare commits

...

1271 Commits

Author SHA1 Message Date
b0b684bdb1 pages.php: use link to create hardlinks isntead of full file copy for thread moving 2024-05-22 23:55:06 +02:00
8626ab7571 Merge pull request 'Refactor ban log' (#142) from refactor-ban-log into config
Reviewed-on: leftypol/leftypol#142
2024-05-22 20:31:03 +00:00
0ce203f1d2 bans.php: always print modLog 2024-05-22 22:24:04 +02:00
9efc35e441 bans.php: simplify modLog string 2024-05-22 22:22:56 +02:00
0d38349a10 Merge pull request 'Add the About theme' (#141) from about-theme into config
Reviewed-on: leftypol/leftypol#141
2024-05-21 14:46:51 +00:00
295cde61f6 style.css: add center utility class 2024-05-21 16:43:30 +02:00
cfdbcfcad9 Add about theme 2024-05-21 16:43:26 +02:00
2030b60acf posts.sql: make default board table engine InnoDB 2024-05-14 19:40:00 +02:00
428d9e9001 functions net.php: add Tor connections to secure connections 2024-05-07 22:44:31 +02:00
7dcdbc065d faq.html catalog.html: fix top bar not being unpinned (missing hud hook) 2024-05-07 11:47:21 +02:00
47d704ed01 faq.html: fix broken style picker (due to missing hud hook) 2024-05-07 11:39:35 +02:00
9723bb8f4a faq.html: trim 2024-05-07 11:39:17 +02:00
217f52ec69 Merge pull request 'Disable login on insecure connections. Implements #134' (#136) from secure-login into config
Reviewed-on: leftypol/leftypol#136
Closes #134
2024-05-07 09:09:44 +00:00
aa99d10f1a auth.php: disallow unencrypted logins by default 2024-05-07 10:44:05 +02:00
003152095a auth.php: remove obsolete code 2024-05-07 10:32:34 +02:00
940ea3f4b5 config.php: reduce default login cookie expire timeout 2024-05-07 10:31:36 +02:00
f6cc9a2f9f auth.php: trim 2024-05-07 10:30:50 +02:00
f5aa60627e catalog.html: add bottom-hud hook on catalog template 2024-05-05 22:18:30 +02:00
909c2040da hud-pinning.js: fix inappropriate unpinning on image posting 2024-05-05 21:32:39 +02:00
86fc44d2f3 style.css: remove default top bar color re-declaration 2024-05-03 14:57:19 +02:00
1da97d77ca Fix broken top bar remaining still pinned on soome themes 2024-04-30 15:47:38 +02:00
8bc9a22920 Merge pull request 'style.css: better user options panel on mobile' (#132) from fix-options-panel-mobile into config
Reviewed-on: leftypol/leftypol#132
2024-04-27 19:50:28 +00:00
9084588fa0 style.css: better user options panel on mobile 2024-04-27 21:46:43 +02:00
3351715795 Attempt fix broken unban on serveral pages 2024-04-25 18:50:32 +02:00
6863db49ef Remove old lainchan entrypoint 2024-04-24 15:59:11 +02:00
21d0a3a585 docker: prepare compose for multiple test instances 2024-04-24 15:30:46 +02:00
2509be645d docker: remove special handling of instance-config.php from build 2024-04-24 15:30:46 +02:00
28c8ff15c1 docker: simplify composer file 2024-04-24 15:30:46 +02:00
a74a9e41e3 Merge pull request 'Store the source ip of a ban appeal' (#125) from display-appeal-src-ip into config
Reviewed-on: leftypol/leftypol#125
2024-04-24 13:04:14 +00:00
5f1f7319a3 Merge branch 'config' into display-appeal-src-ip 2024-04-24 13:03:31 +00:00
94f6a1f366 page.html: main.js cannot find the bottom-hud hook to add the stylepicker 2024-04-17 12:12:39 +02:00
159b9c9737 index.html: add missing hud bars ids 2024-04-16 00:10:05 +02:00
92a50f60cd index.html: trim 2024-04-16 00:08:04 +02:00
49457dfd9f hud-pinning: add hud pinning option 2024-04-15 23:55:42 +02:00
9799d7e515 thread.html main.js: use ids to identify hud top and bottom bars 2024-04-15 23:55:10 +02:00
8fcad42ba2 main.js: trim 2024-04-15 23:54:30 +02:00
e84480764a thread.html: trim 2024-04-15 23:54:30 +02:00
43a5a33cbd banners: move banners to static 2024-04-15 20:08:54 +02:00
bdd80b6160 banners: add united front banner 2024-04-15 19:44:58 +02:00
b942250a16 Merge pull request 'Redirect for banners' (#116) from banner-redirect into config
Reviewed-on: leftypol/leftypol#116
2024-04-13 10:58:31 +00:00
4ca2f5f3a3 docker: very aggressive CDN, media, css and js file caching on nginx site config 2024-04-13 12:53:12 +02:00
c09a85ca65 docker: fix nginx site config 2024-04-13 12:27:56 +02:00
05952a6222 docker: add banners/ directory to directories to copy over 2024-04-13 12:22:32 +02:00
295d1751b1 banners.php: make banners redirect instead of serving the image directly 2024-04-13 00:07:03 +02:00
45e4153d5b banned.html: add breakline newline after image 2024-04-10 16:59:25 +02:00
e5c8923c1c Merge pull request 'Dockerize leftypol, again' (#115) from dockerize2 into config
Reviewed-on: leftypol/leftypol#115
2024-04-10 14:58:09 +00:00
6a0613d4a8 docker: adjust php-fpm pool log config on compose 2024-04-10 16:49:20 +02:00
36419ab9a7 docker: remove leftchan references from compose 2024-04-10 16:49:20 +02:00
ac3fc9518b docker: remove unused script 2024-04-10 16:49:20 +02:00
677a1e0210 docker: downgrade to php 7.2 for leftypol 2024-04-10 16:49:20 +02:00
919a6d0d2f docker: handle leftypol not shipping with instance-config.php 2024-04-10 16:49:20 +02:00
c6f0dc5f4e docker: do not mention secrets.php in leftypol dockerfile 2024-04-10 16:49:20 +02:00
040bf21c47 docker: do not mention instance-config.php in leftypol dockerfile 2024-04-10 16:49:20 +02:00
651cc9edb4 docker: use different subnet and db container name than vanilla vichan 2024-04-10 16:49:20 +02:00
1682352b66 docker: boostrap script handle secrets.php, copy static files 2024-04-10 16:49:20 +02:00
4edb0b5563 docker: move image to alpine linux 2024-04-10 16:49:20 +02:00
ef98a2aa7e docker: remove lainchan branding from compose file 2024-04-10 16:49:20 +02:00
0d2a441eb0 docker: compose mount local-www as root directory in nginx 2024-04-10 16:49:20 +02:00
ffaad8dbb8 docker: handle secrets.php 2024-04-10 16:49:20 +02:00
745bd5fc5d docker: use less used port for compose 2024-04-10 16:49:20 +02:00
cb686abbba docker: ignore empty gitkeep directories 2024-04-10 16:49:20 +02:00
e1e6a5ce35 docker: create empty robots.txt 2024-04-10 16:49:20 +02:00
0354b1a3cd install.php: check that secrets.php is writable 2024-04-10 16:49:20 +02:00
5873987599 template.php install.php: handle cache directory being a symlink 2024-04-10 16:49:20 +02:00
06214a1e26 template.php: trim 2024-04-10 16:49:20 +02:00
df7d7e1d3c docker: extract the vichan directory and make it optionally exposable 2024-04-10 16:49:20 +02:00
6ba2c7cf42 docker-compose: use local www root 2024-04-10 16:49:20 +02:00
e76dbfd7a0 docker: reduce file permissions 2024-04-10 16:49:20 +02:00
5bf2634bf6 docker: change user to www-data 2024-04-10 16:49:19 +02:00
726de817b1 docker: change work directory to /var/www 2024-04-10 16:49:19 +02:00
20b7ed7829 docker: fix missing tmp directory 2024-04-10 16:49:19 +02:00
e3dc1a1a65 docker: split up application and dependency layers 2024-04-10 16:49:19 +02:00
faf546ab02 docker: remove "meaningless" bits from nginx configuration 2024-04-10 16:49:19 +02:00
928593dad9 docker: remove unused configuration 2024-04-10 16:49:19 +02:00
f3b2793954 banned.html: center image 2024-04-10 14:27:35 +02:00
9de120201d banned.html: fix ban dates lack of space 2024-04-10 14:12:02 +02:00
7805530e41 banned.html: adjust image size 2024-04-10 11:59:21 +02:00
2092661af4 banned.html: change ban image to stalin's purge list 2024-04-10 11:59:17 +02:00
b50578ffa9 Fix SQL error key too long on installation 2024-04-07 19:55:14 +02:00
fd890cefd7 install.php: better SQL error reporting 2024-04-07 19:55:03 +02:00
ef936d60a9 bans.php: format 2024-04-04 15:57:08 +02:00
2e6a0aa06a Merge pull request 'Add WEBP to list of supported file types' (#114) from zeke/leftypol:config into config
Reviewed-on: leftypol/leftypol#114
2024-04-04 13:31:01 +00:00
9c978fd5f8 Add WEBP to list of supported file types 2024-04-03 20:54:43 -07:00
Lorenzo Yario
46e61a71cf webp 2024-04-03 20:07:16 +02:00
cb5b465c57 post.php: do not strip orientation metadata 2024-04-03 20:00:04 +02:00
97e41d1c7f post.php: strip metadata from png and webp image file types 2024-04-03 19:53:53 +02:00
8e5b09c687 Add webp to list of recognized image file types 2024-04-03 19:41:14 +02:00
0a1412b74f post.php: fix undefined post on report 2024-04-01 22:17:22 +02:00
e496fb10a5 Handle reporting non-existing posts. Fix #96 2024-04-01 19:20:23 +02:00
5709513cb7 Merge pull request 'Fix #19 Show ban ID' (#113) from show-ban-id into config
Reviewed-on: leftypol/leftypol#113
2024-03-26 15:18:50 +01:00
1de62d4ddd Add ban id to ban page. Fix #19 2024-03-26 15:16:11 +01:00
48347ae1cd banned.html: trim 2024-03-26 15:05:26 +01:00
98ef473a9a functions.php: trim 2024-03-26 15:00:15 +01:00
e8f589f6c1 ban_appeals.html: do not display the source ip row if there is none 2024-03-15 16:44:44 +01:00
a8ff605571 Display split ban mask and appeal IP 2024-03-15 14:54:32 +01:00
0b7161a588 ban_appeals.html: trim 2024-03-15 14:48:45 +01:00
7e3a531aa5 Add source IP to ban_appeals table 2024-03-15 14:34:17 +01:00
c696ad4fa2 Add IPs of users deleting their own post to the mod log. See #109 2024-03-15 10:09:14 +01:00
cb4726e076 post.php: trim 2024-03-15 10:08:34 +01:00
b742445f50 Add overboard index support. Yet another ugly hack 2024-03-13 13:44:09 +00:00
aca9ca0d7b Merge pull request 'Hack in support for the overboard catalog. Solves #94' (#107) from overboard-catalog-hack into config
Reviewed-on: leftypol/leftypol#107
2024-03-13 12:42:22 +00:00
91e41aa522 Refactor overboard catalog support to be slightly less bad 2024-03-13 13:35:48 +01:00
6fcd4f4779 Add overboard catalog support. This is an horrenouds hack. Pray to god we manage to refactor it away. See #94 2024-03-13 12:32:46 +00:00
6ac0e47f15 Merge pull request 'Get Docker image creation working' (#97) from zeke/leftypol:config into config
Reviewed-on: leftypol/leftypol#97
2024-02-11 09:08:24 +00:00
39412b4427 Apply suggested changes 2024-02-09 11:01:07 -08:00
3191ef3105 Remove unused Dockerfile 2024-02-07 12:03:05 -08:00
17820b31c4 Fix user and group creation for docker containers 2024-02-07 10:58:34 -08:00
57a6154287 Update script with php/web container differences 2024-02-04 23:34:17 -08:00
64ba328c3b Remove extension lines (added by docker-php-ext-enable) 2024-02-04 23:29:38 -08:00
dcc936b35d Use two Dockerfiles, move Docker stuff to /docker 2024-02-01 18:05:08 -08:00
ea99ddc6f6 Reimplement overboard 2024-01-29 11:18:06 +01:00
2efd67ef85 Backport vichan 5.1.5 catalog implementation, enabling mod catalog. 2024-01-29 11:18:06 +01:00
264c10cf2a Merge pull request 'Add the edit_news link to the mod dashboard. Fixes #83' (#87) from news_in_dashboard into config
Reviewed-on: leftypol/leftypol#87
2024-01-29 11:18:06 +01:00
c559d2cd41 Merge pull request 'Update dependencies for Docker image' (#85) from zeke/leftypol:config into config
Reviewed-on: leftypol/leftypol#85
2024-01-29 11:18:06 +01:00
45f310e4e3 Add the edit_news link to the mod dashboard 2024-01-29 11:18:06 +01:00
41016b1ca2 Add missing comment doc in post.php 2024-01-29 11:18:06 +01:00
38afe37733 Update dependencies for Docker image 2024-01-29 11:18:06 +01:00
b16e891768 .gitignore more stuff 2024-01-29 11:18:06 +01:00
a4b5bf341b Refactor post.php: isolate more db access and remote REST calls into functions. 2024-01-29 11:18:06 +01:00
fd9baaea5f post.php: sanitize appeal message 2024-01-29 11:18:06 +01:00
854cc6cd23 Remove geoip dependency 2024-01-29 11:18:06 +01:00
a9211d23b5 Remove feature: upload by url 2024-01-29 11:18:01 +01:00
df2fe0e60f Minor format post.php 2024-01-16 18:05:33 +00:00
56b6d6b1aa Refactor post.php: split upload by url file downloading into a function. 2024-01-16 18:05:33 +00:00
df78f0e79f Refactor post.php: move post body's markup splitting into a separate function 2024-01-16 18:05:33 +00:00
799072d692 Refactor post.php: split upload file hashing to a function 2024-01-16 18:05:33 +00:00
8faf20f7ff Format post.php in accordance with PSR-12 2024-01-16 18:05:33 +00:00
5c0d0a8ca1 ban page: remove max-height from table rows, since it doesn't work anyway 2024-01-16 18:05:24 +00:00
1b00660d33 Format bans page fix patch 2024-01-16 18:05:16 +00:00
1adcb13cc1 Fix bans page 2024-01-16 18:04:57 +00:00
Your Name
fdaa4ebdd1 better error 2024-01-16 18:04:00 +00:00
a3a1e8e55e Rename email field to options. (hack)
Didn't worry about doing it properly with translations because this is a local fork
2024-01-16 18:04:00 +00:00
61a3aa8fe1 Describe sage option in email select
'sage' is too esoteric for noobs. Ideally we should make this a checkbox because always noko but whatever
2024-01-16 18:04:00 +00:00
d694f2aa38 Remove fight float on select boxes
I can't even find how this got it, but it's apparently been there for six years on lainchan
2024-01-16 18:04:00 +00:00
Your Name
56bbaf881f Simple anti-spam mechanism 2024-01-16 18:04:00 +00:00
Your Name
b833e2743a Simple anti-spam mechanism 2024-01-16 18:04:00 +00:00
Your Name
845ff14e52 Simple anti-spam mechanism 2024-01-16 18:04:00 +00:00
Your Name
e2bef8c2f2 Simple anti-spam mechanism 2024-01-16 18:04:00 +00:00
ea67272e87 Add various flags 2022-10-06 07:10:10 -01:00
Your Name
0cffd52b02 add colon to character class for cites 2022-08-04 09:18:31 +02:00
Your Name
fc2357e6f2 moves modifiers, as per https://github.com/vichan-devel/vichan/pull/377/files 2022-07-16 00:28:59 +02:00
Your Name
5b01f34973 mute redefinition. reference: 00349d0315 2022-07-16 00:26:59 +02:00
Your Name
f1a48042c2 add some stuff to the api, to match vichan's api at the request of a user. fixed the delete-stray-images script 2022-06-22 20:39:47 +02:00
57df86557a Update composer.lock 2022-05-22 20:20:50 -02:00
e3ea750c85 Fixes for delete-stray tool and cli.php 2022-05-22 20:00:50 -02:00
bf4fb6d0e8 Added Feature - Premade Ban Reasons
see 13ac9172e7
2022-05-22 19:42:57 -02:00
3725d27e72 Matrix report integration (#74)
Enables posting reports to a matrix room.
Co-authored-by: nonmakina <nonmakina@leftypol.org>
Co-committed-by: nonmakina <nonmakina@leftypol.org>
2022-04-03 22:06:42 +00:00
2b5365b572 use more cache. Speeds up page builds (#72)
use more cache. Speeds up page builds.
Tested as much as reasonably possible. Works well.
cuts self delete from ~8 seconds to ~1 second. and mod delete from 10-14 seconds to ~4 seconds.
Co-authored-by: nonmakina <nonmakina@leftypol.org>
Co-committed-by: nonmakina <nonmakina@leftypol.org>
2022-03-30 23:59:21 +00:00
9c70a1f880 Merge pull request 'Adds saboteur banner' (#68) from banners2022_03_01 into config
Reviewed-on: leftypol/leftypol#68
2022-03-23 17:57:11 +00:00
37edb0cf3d Merge branch 'config' into banners2022_03_01 2022-03-23 17:56:14 +00:00
6c2e958a77 Fix status.php 2022-03-01 04:55:53 -01:00
Your Name
ad0af8e082 Adds saboteur banner 2022-03-01 01:54:05 +01:00
a1f64335f9 Added multiple file select dialog for post form
Mostly 808c2072d3
2022-02-12 01:34:46 -01:00
bc7fa47aa2 Solve dynamically loaded threads not being filtered. Possibly a hack-fix.
This seems like the most appropriate simple fix, hopefully not too wasteful.
2022-01-24 03:05:48 +00:00
a1f8f4adca Update jQuery libraries
Mainly for security purposes.
2022-01-23 22:01:25 -01:00
ca1ce0103f Fix multiple issues with anti_bump_flood
- bumplocked thread with one reply, delete the reply and no post matches the query
- saged posts aren't ignored when finding last bump
- bumplocked threads should be ignored
2022-01-22 02:05:04 -01:00
231321f2c1 Fix deprecated size() in quick-post-controls.js 2022-01-19 03:55:00 -01:00
2f64d7edff Remove useless debug messages
lainchan was a mistake
2022-01-17 13:08:57 -01:00
Daniel Saunders
c388081617 $board can be NULL here, prevent indexing it
Simplest 7.4 fix ever? Possibly.
2022-01-17 12:31:42 -01:00
Sardach
15a099deb3 insignificant fix
PHP7 shows a warning when executing tools/rebuild2.php: "Declaration of case-insensitive constants is deprecated"
$group_name and $group_value really not need be case-insensitive, so i simply removed that "true".
2022-01-17 12:27:34 -01:00
e39f342008 Consider nonoko in building after posting, improve comments 2022-01-17 11:14:04 -01:00
a1b6ca71b4 Fix missing function log.php from PHP8 changes
I assume this is a better solution than adding the file to the composer.json autoload files as it's only needed for this single file.
2022-01-17 11:05:32 -01:00
a385be3f4c Update author info 2022-01-17 11:02:35 -01:00
d66b9d6208 Merge pull request 'Make compatible with PHP 8' (#67) from php8-compat into config 2022-01-17 10:42:55 +00:00
cfaea67381 Refactor rebuilding after posts, finish reply requests before rebuilding index
This provides massive improvements to perceived post times as it doesn't wait for the entire board to rebuild index before confirming to the user that the post was made
2022-01-17 07:12:13 -01:00
9bf3c9a0ae Fix redis deprecation of delete 2022-01-17 03:01:56 -01:00
2605a6ff5d Merge vichan PHP8 fixes, configure composer, fix outstanding incompatibilities 2022-01-17 02:14:22 -01:00
c9ef4e80ac Allow users to disable and clear (You)s
Credit to based anon https://leftypol.org/tech/res/6724.html#12776
2022-01-15 03:09:10 -01:00
19bbde2639 Add Redneck flag 2022-01-02 08:44:26 -01:00
c6cfa4e04d Minor adjustment to birthday CSS 2021-12-20 23:50:15 -01:00
2f84986401 Birthdady themeing 2021-12-20 23:43:06 -01:00
bf51d4ed89 Make snow off-by-default due to lag 2021-12-18 22:58:16 -01:00
b055b1101b [HACK] Hide <tinyboard> tags in CSS
See leftypol/leftypol#65
2021-12-14 10:41:18 -01:00
4efe45fe23 Enable winter snow 2021-12-13 13:32:55 -01:00
a09180ed05 Fix typo in blur-images.js 2021-12-13 13:18:10 -01:00
90e033fb4c Update RAF flag 2021-12-10 23:07:01 -01:00
18d96f5376 Add banner 2021-12-10 07:47:54 -01:00
78ab5de8f7 Add RAF flag 2021-12-10 07:40:54 -01:00
c20db2988d Add IP address link to ban appeals 2021-12-09 23:16:23 -01:00
dd1b6b0276 Update site rules 2021-12-07 00:15:32 -01:00
0b56719008 Quick hack to prevent oversized PDF thumbnails. 2021-11-28 00:28:49 +00:00
30e179552a Merge pull request 'Only add drag-drop handlers to dropzone, not the entire document' (#64) from file-drag-dropzone-only into config
Reviewed-on: leftypol/leftypol#64
2021-11-15 07:02:54 +00:00
1db5bd1a6e Only add drag-drop handlers to dropzone, not the entire document
This enables dragging text into the textbox.
2021-11-15 05:56:32 -01:00
011bb40ebe Merge pull request 'Set default values for ban form' (#62) from ban-form-defaults into config
Reviewed-on: leftypol/leftypol#62
2021-11-12 11:34:39 +00:00
badfb60161 Add default ban length of 1 hour instead of permanent ban 2021-11-12 10:26:48 -01:00
135604386a Make bans default to board of offending post 2021-11-12 10:21:39 -01:00
66097406b8 Merge pull request 'Improve page titles and social media cards' (#61) from index-page-header-seo into config
Reviewed-on: leftypol/leftypol#61
2021-11-12 06:59:34 +00:00
795b54bf61 Improve page titles and social media cards 2021-11-12 04:50:47 -01:00
9115f631ab Move logo to default location 2021-11-12 04:18:46 -01:00
9638c00f39 Move logo to config variable 2021-11-12 03:37:30 -01:00
773f0e1842 Tidy up theme.php 2021-11-12 03:37:23 -01:00
16d6448204 Merge pull request 'Move upload-selection.js call inline' (#60) from upload-selection-inline into config
Reviewed-on: leftypol/leftypol#60
2021-11-11 14:17:00 +00:00
4fcbad3fb1 Make file-selector.js inline call conditional 2021-11-11 13:07:32 -01:00
3ae859d6e6 Call upload-selection.js inline
Makes the change happen earlier, reducing content shift
2021-11-11 13:06:19 -01:00
ae65959a48 Fix ordering in previous change 2021-11-11 11:59:13 -01:00
6235c12275 Concatenate dark.css to dark_red.css to improve performance 2021-11-11 10:43:48 -01:00
b3adcfe98b Revert attempt at deferring file selector
Reverts most of c44bbde511 which failed to remove the previous file uploader leftypol/leftypol#37
2021-11-11 09:42:03 -01:00
e6212c1a51 Remove roulette oekaki hack 2021-11-11 07:10:32 -01:00
78d4fd6ee1 Make select elements consistent with forms 2021-11-05 11:51:39 -01:00
667b271a27 Rename temporary themes 2021-11-05 10:05:10 -01:00
569f5f5876 Merge pull request 'Prevent blur-images.js interfereing with regular hiding images' (#57) from blur-images-patch1 into config 2021-10-28 02:44:16 +00:00
0250d59fb7 Prevent blur-images.js interfereing with regular hiding images 2021-10-28 01:37:52 -01:00
bfb51c66a4 Merge pull request 'Add blur images option for raids' (#55) from blur-images into config 2021-10-27 20:46:38 +00:00
6aa992d6a2 Merge pull request 'Fix double-encoding on post edit form' (#54) from edit-post-double-encode into config 2021-10-27 20:46:18 +00:00
43268fba76 Merge pull request 'Various fixes for thread reply notifications' (#52) from auto-refresh-notifications into config 2021-10-27 20:45:56 +00:00
1d8828896d Merge pull request 'Add user option for custom YouTube embed proxy' (#53) from youtube-embed-proxy-options into config 2021-10-27 20:45:32 +00:00
7e61b7d077 Merge pull request 'Add PFLP, Socrates flags' (#56) from new-flags-2020-10-27 into config 2021-10-27 20:32:41 +00:00
2dc55ab236 Add PFLP, Socrates flags 2021-10-27 20:29:31 +00:00
926b377032 Correct notification text for threads 2021-10-17 21:57:12 -01:00
tmp-server
807adaff90 Fix new thread notifications breaking script
Tried to access invalid child.
2021-10-16 02:34:44 +00:00
2654af07c2 Add blur images option 2021-10-15 06:05:03 -01:00
9efcec3573 Fix double-encoding on post edit form leftypol/leftypol#31 2021-10-15 04:20:09 +00:00
59e614a8f0 Add option for custom YouTube embed proxy 2021-10-15 01:23:02 -01:00
3112d6486b Merge branch 'config' into auto-refresh-notifications 2021-10-15 00:57:34 +00:00
d5704ec4eb Use stored title instead of document.title in notifications
Prevents number of unreads being added to notificaiton thread name
2021-10-15 00:52:23 +00:00
10c772efad Fix notifications 2021-10-15 00:09:00 +00:00
d1db003472 Make all notifications show, not just the first unread 2021-10-15 00:06:24 +00:00
34f178d53e Fix notifications: replace reference to undisplayed div 2021-10-14 23:08:10 +00:00
67232c5c41 Merge pull request 'Unique IP bar fix' (#50) from uniqueIpFix2 into config
Reviewed-on: leftypol/leftypol#50
2021-10-14 22:04:07 +00:00
fabc83ebfb Separate mod auto-update settings from normal settings 2021-10-14 21:03:28 -01:00
cb1fd189a6 Merge branch 'config' into uniqueIpFix2 2021-10-14 21:47:58 +00:00
aa9341c51d Merge pull request 'Add IPv6 support for DNSBL' (#48) from ipv6-dnsbl into config
Reviewed-on: leftypol/leftypol#48
2021-10-14 08:26:37 +00:00
07f1abfc3a Merge branch 'config' into ipv6-dnsbl 2021-10-14 07:08:26 +00:00
55457cf07c Merge branch 'ipv6-dnsbl' of https://git.leftypol.org/leftypol/leftypol into ipv6-dnsbl 2021-10-14 07:05:20 +00:00
bba5e1bff3 Clean up duplicate code 2021-10-14 07:04:26 +00:00
00d8d50210 Merge branch 'config' into uniqueIpFix2 2021-10-14 06:06:00 +00:00
44e632a430 Merge pull request 'Lower maximum delay for recent post auto-update' (#51) from recent-posts-lower-times into config 2021-10-14 06:04:19 +00:00
6042d8b49a Lower maximum delay for recent post auto-update 2021-10-14 06:00:23 +00:00
Your Name
e6106e04e0 Feedback on uniqueIpFix. Moves the insertion of the bar | after Unique IPs to be inserted by the thread watcher JS script. see: https://leftypol.org/tech/res/6724.html#11998 2021-10-13 19:28:24 +02:00
220896b535 Merge pull request 'IP count bug fix' (#49) from fixIpCount2 into config
Reviewed-on: leftypol/leftypol#49

Fixes issue.
2021-10-13 17:15:17 +00:00
Your Name
bc691addff pass by reference 2021-10-13 19:12:51 +02:00
39074e10fa Merge branch 'config' into ipv6-dnsbl 2021-10-13 13:49:28 +00:00
dbca2948ae Merge pull request 'Total IPs count unique IPs' (#47) from fixIpCount into config 2021-10-13 13:45:39 +00:00
ed6fab9088 Merge branch 'config' into fixIpCount 2021-10-13 13:45:11 +00:00
aa3c8fb6e9 Merge pull request 'Move Unique IP counter to the right.' (#45) from uniqueIpFix into config 2021-10-13 13:34:56 +00:00
132b7ace54 Add IPv6 support for DNSBL
Should have used the library but didn't want to experiement and posiibly break the includes
2021-10-13 13:32:23 +00:00
Your Name
888977a96a Revert "Sum up stats that nonmakina added"
This reverts commit c384ac12f5.
2021-10-13 13:50:45 +02:00
Your Name
afdd7419b3 Removes space after bar | 2021-10-06 23:17:07 +02:00
Your Name
7ad0f7e635 Adds bar | to unique IP counter 2021-10-06 23:15:46 +02:00
Your Name
704ba15ced Lewdposter's proposed fixes 2021-10-06 23:12:21 +02:00
8fe2499e58 Merge pull request 'Adds Invidous [Proxy] embed capabilties & embed when on tor use hidden service.' (#41) from torTube into config
Reviewed-on: leftypol/leftypol#41

Adds Invidous [Proxy] embed capabilties & embed when on tor use hidden service.

When using the leftypol hidden service, the default embed is an invidious hidden service.
2021-10-06 20:45:37 +00:00
Your Name
7d2bc99953 try5 2021-10-05 23:18:36 +02:00
Your Name
88070b3c4a try4 2021-10-05 23:14:26 +02:00
Your Name
26a729e9d8 try3 2021-10-05 22:39:56 +02:00
Your Name
e642af7ac0 try2 2021-10-05 22:26:46 +02:00
Your Name
d7248c357d Automatically embeds with tor if on the hidden site. Adds clearnet invidious embed. (untested). 2021-10-05 22:15:08 +02:00
6f47518ae9 Merge pull request 'Adds Oekaki to roulette.' (#40) from enableOekaki into config
Adds Oekaki to roulette.

These are the settings that needs to change to enable oekaki. It uses somewhat of a hack due to our other settings. It works well as far as I can see.

There might be some work needed to have this work on the site.
Namely, git submodule init; git submodule update and possibly run npm install -ci; grunt --force too in the wpaint submodule.
2021-10-05 16:12:44 +00:00
Your Name
d867e97340 Removes additonal_deferred scripts 2021-10-05 18:06:58 +02:00
Your Name
6d685d00fb Adds Oekaki to roulette. It uses a hack to make it work. 2021-10-04 01:18:54 +02:00
1accda2a18 Increase banner webp convert quality to 95 2021-10-02 08:22:03 +00:00
8e2de03447 Minor flag javascript fixes 2021-10-02 05:13:09 +00:00
b518cc94c3 Generalize ignoring sticky threads on overboard catalogs 2021-10-02 04:59:12 +00:00
8acc328c91 Enable filtering by flag name 2021-10-01 05:15:54 -02:00
79156cbbe4 Enable posting from catalog without JS
Thank you based lewdposter
2021-10-01 06:03:58 +00:00
b227982390 Add catalog thumbnails for file placeholder, handle the first of multiple OP images being deleted
Thank you based lewdposter
2021-10-01 05:11:37 +00:00
99493b054d Revert obsolete foreign board top bar code 2021-10-01 04:26:39 +00:00
9c17b19ded Add Git repo link to FAQ 2021-10-01 03:48:30 +00:00
a19a283c91 Add midnight.css theme 2021-10-01 02:27:49 +00:00
73794e5719 Remove yotsuba fade from dark themes, fix temp_dark 2021-10-01 02:10:30 +00:00
f45636065d Rename sample captcha config 2021-10-01 01:22:46 +00:00
c909b31cd7 Fix cyclic threads not cycling, remove inconsistent code whitespace 2021-10-01 00:53:53 +00:00
3379b9c72e Add noindex meta tag to 'Last 50 posts' thread pages 2021-09-30 13:29:31 -02:00
21be83eb73 Add wiphala flag 2021-09-30 11:21:20 +00:00
e55784eff2 Add 404 image 2021-09-30 11:20:30 +00:00
e69e18ae26 Fix indenting of filter code 2021-09-30 10:05:47 +00:00
96babb9229 Remove banner-originals from repo 2021-09-29 14:15:02 +00:00
0acca678a7 Update 'README.md' 2021-09-29 11:49:31 +00:00
d41b1230e1 Update 'README.md' 2021-09-29 03:21:54 +00:00
f69d524a59 Add dark solarized theme 2021-09-29 03:19:03 +00:00
cb280cd5e0 Move [Watch Thread] button before replies 2021-09-28 09:39:12 +00:00
c35c6a5dbe Add board search to index page 2021-09-28 09:36:14 +00:00
191c7a5c66 Convert banners to webm/gif, add banners 2021-09-28 08:23:21 +00:00
4e4d3a0d29 Improve documentation for securimage 2021-09-28 08:21:04 +00:00
d758b5b5f2 Remove SSL badge image 2021-09-28 08:18:22 +00:00
76911be92a Update frontpage, improve meta tags 2021-09-28 08:11:41 +00:00
1f9891006a Update FAQ 2021-09-28 08:10:12 +00:00
02452955ec Update overboard config 2021-09-28 08:08:07 +00:00
2625f6ede5 Enable download with filename without JavaScript 2021-09-28 08:06:03 +00:00
bb34acedf6 Make scroller in expand-video.js passive 2021-09-28 08:04:01 +00:00
fa4f543a2d Improve broken auto-reload 2021-09-28 08:02:04 +00:00
0806e39c03 Fix post-filter, remove lainchan postcontainer 2021-09-28 07:57:24 +00:00
52cd74a01d Change 404 page 2021-09-28 07:39:41 +00:00
1864530b56 Improve citing in replies 2021-09-28 03:11:24 +00:00
46d62584d0 Remove newlines and modifiers from thread title
Parts sampled from NPFchan
2021-09-28 03:09:18 +00:00
9c7239f2d4 Improve default filters 2021-09-28 02:02:19 +00:00
37bfc3beeb Add mod auto-reload 2021-09-28 01:35:12 +00:00
5bb8505dfd Fix bug in ban appeal counter 2021-09-28 01:16:31 +00:00
bbf7ced5db Block D+ on special IP addresses 2021-09-28 01:13:40 +00:00
2dee1c1f38 Fix name typo in post edit SQL 2021-09-28 01:11:09 +00:00
9ca34d6ed5 Fix errors moving/merging with spoilers/deleted files 2021-09-28 01:07:35 +00:00
2532d08331 Bypass broken mysql version check 2021-09-28 00:52:22 +00:00
1d97b825d3 Remove instance configuration 2021-09-28 00:42:31 +00:00
nonmakina
843ab6f55e Merge pull request #348 from discomrade/ban-appeal-limit
Enforce maximum length of ban appeal
2021-07-24 17:27:01 +02:00
4a5944795c Enforce maximum length of ban appeal 2021-07-24 10:47:56 -02:00
nonmakina
52d6de5681 Merge pull request #346 from towards-a-new-leftypol/wordfilter-fbi
Reduce overreach of fbi.gov filter
2021-07-24 13:34:41 +02:00
nonmakina
5abdabe115 Merge pull request #345 from discomrade/reporttoolong-fix
Fix typos in https://github.com/towards-a-new-leftypol/leftypol_lainchan/pull/336
2021-07-24 13:33:57 +02:00
f2e398305d Reduce overreach of fbi.gov filter
The initial filter would have ruined words or links containing 'discord', including the non-English words 'discordo' and 'discordar'.
Legitimate use of the exact word 'discord', such as sowing discord, will still trigger the filter.
2021-07-24 11:21:38 +00:00
29e0906022 Fix typos in https://github.com/towards-a-new-leftypol/leftypol_lainchan/pull/336 2021-07-24 08:47:50 -02:00
nonmakina
4a4bb4e856 Merge pull request #332 from discomrade/vichan-0d7ee48
Update config.php image documentation, move bad defaults to instance-config.php
2021-07-24 10:40:08 +02:00
nonmakina
7c4d74aeee Merge pull request #343 from discomrade/vichan-sharp-theme
vichan downstream: Add 'Sharp' style theme
2021-07-24 10:38:11 +02:00
nonmakina
89c5246e3c Merge pull request #324 from towards-a-new-leftypol/remove-autoupdates
Set update-checking to false by default
2021-07-24 10:35:14 +02:00
nonmakina
3eee68e0db Merge pull request #325 from discomrade/remove-tinyboard
Change public Tinyboard and vichan links
2021-07-24 10:34:06 +02:00
nonmakina
7d23e14cb9 Merge pull request #336 from discomrade/vichan-report-length
vichan downstream: Enforce maximum report length
2021-07-24 10:32:45 +02:00
nonmakina
eee71e58a3 Merge pull request #344 from discomrade/appeals-count
Show ban appeal count on mod dashboard
2021-07-24 10:31:44 +02:00
nonmakina
9b749a6c81 Merge pull request #330 from towards-a-new-leftypol/remove-scripts-config
Remove additonal scripts
2021-07-24 10:31:03 +02:00
nonmakina
b0e3448139 Merge pull request #328 from towards-a-new-leftypol/filter-update-21-07-21
Update wordfilters
2021-07-24 10:30:35 +02:00
78b3a63311 Show ban appeal count on mod dashboard 2021-07-24 04:33:00 -02:00
Daniel Saunders
c841179934 Minor changes to form and boardlist in sharp.css 2021-07-24 02:10:56 -02:00
Daniel Saunders
4a7240eebb Color fixes (sharp.css) 2021-07-24 02:10:56 -02:00
Daniel Saunders
43aa9eee5f fuck go back 2021-07-24 02:10:56 -02:00
Daniel Saunders
75a59ece64 Fixes to sharp.css including some cross-platform font support 2021-07-24 02:10:56 -02:00
Daniel Saunders
a8b80c7037 Added sharp.css 2021-07-24 02:10:56 -02:00
f575691fc4 Fix 387ebe9c0c , extract limit to variable 2021-07-24 01:38:59 -02:00
af889e8941 Give descriptive name to report too long error 2021-07-24 01:38:59 -02:00
vholmes
ed55ea23ea Prevents reports with too many characters 2021-07-24 01:38:31 -02:00
55a9caefa1 Extract bad defaults to instance-config.php, from c9c4273d4b, updates documentation 2021-07-24 01:15:38 -02:00
819b520e37 Remove additonal scripts 2021-07-24 02:19:41 +00:00
nonmakina
bd71b3598d Merge pull request #320 from towards-a-new-leftypol/minecraft_banner
Add new banner
2021-07-23 23:56:45 +02:00
7b0564ca33 Add IPA symbols to wordfilter alias letters 2021-07-22 04:51:43 +00:00
344f8371c0 Update wordfilters
- Add 'IQ' filter
- Add 'Discord' filter
- Add exclamation points as 'i' lookalikes
2021-07-22 01:33:58 +00:00
68eaa26ddd Change public Tinyboard and vichan links 2021-07-21 21:58:39 -02:00
49ec94d11f Set update-checking to false by default.
This is an obsoleted feature.
2021-07-21 23:08:25 +00:00
towards-a-new-leftypol
b97ec18275 Add new banner 2021-07-15 05:16:27 -04:00
nonmakina
ca8f6baa36 Merge pull request #316 from nonmakina/jsFixes2
JS fixes
2021-07-11 17:54:50 +02:00
72b716269e JS fixes, for realz x2 2021-07-11 17:51:17 +02:00
nonmakina
178df81467 Merge pull request #315 from nonmakina/refactorDeferredJs
Refactor deferred js
2021-07-11 16:18:28 +02:00
baef16208c fixes quick reply 2021-07-11 16:00:39 +02:00
6701456e81 Moves post hover and others to fix loading issue. Minifies and compiles 2021-07-11 14:00:03 +02:00
4379135437 Refactor deferred js 2021-07-11 12:46:26 +02:00
nonmakina
e0cec8ee5a Merge pull request #307 from PietroCarrara/config
Whitelist /dead/
2021-07-11 11:26:45 +02:00
nonmakina
c39009f0e7 Merge pull request #313 from discomrade/banner-size
Specify fixed banner size for smoother loading
2021-07-11 11:26:07 +02:00
nonmakina
7e9afa9356 Merge pull request #308 from discomrade/defer-javascript
Allow case-by-case defering of additional JS
2021-07-11 11:25:40 +02:00
nonmakina
b992a926cc Merge branch 'config' into defer-javascript 2021-07-11 11:23:03 +02:00
nonmakina
3bae2c65a2 Merge pull request #311 from discomrade/arabic-fix
Fix combining character set, allow limit for combining characters
2021-07-11 11:07:00 +02:00
nonmakina
2584ed9d1a Merge pull request #310 from discomrade/conf-banner-change
Update banners
2021-07-11 11:05:27 +02:00
nonmakina
5581b68aed Merge pull request #309 from discomrade/demain-update
Update Demain themes
2021-07-11 11:05:14 +02:00
nonmakina
d3ff13d8ca Merge pull request #301 from discomrade/ip-maxlength
Extend maxlength of ban IP to allow IPv6 subnets
2021-07-11 11:04:51 +02:00
nonmakina
780c64e31e Merge pull request #306 from towards-a-new-leftypol/code-markup-encoding
Prevent double-encoding of HTML entities in [code]
2021-07-11 11:04:23 +02:00
nonmakina
fadc80ff2e Merge pull request #305 from towards-a-new-leftypol/recalculate-filesize
Recalculate filesize after stripping metadata
2021-07-11 11:04:02 +02:00
nonmakina
88c4e7ef47 Merge pull request #303 from towards-a-new-leftypol/thread-stats-1
Keep thread stats below new posts
2021-07-11 11:03:35 +02:00
nonmakina
040305c60c Merge pull request #300 from towards-a-new-leftypol/chud-filter
Add chud wordfilter
2021-07-11 11:03:16 +02:00
74b1859972 Specify banner size 2021-07-10 21:30:02 -02:00
8b3df89863 Fix combining character set, allow limit for combining characters 2021-07-10 01:37:31 -02:00
8a505322d6 Update pencil banner 2021-07-10 00:02:39 -02:00
2475a192a1 Replace shay banner 2021-07-10 00:01:50 -02:00
da2b2567b0 Restore download-original.js 2021-07-09 21:38:53 -02:00
c98738684a Update Demain themes 2021-07-09 09:57:13 -02:00
e93e613535 Allow select defering additional JS 2021-07-09 07:35:09 -02:00
Pietro Carrara
d112885ca5 Whitelist /dead/ 2021-07-08 17:38:39 -03:00
e418f1e3aa Prevent double-encoding of HTML entities in [code] 2021-07-06 12:41:16 +00:00
f4ae0196bd Recalculate filesize after stripping metadata 2021-07-06 11:37:54 +00:00
57bd7ec25b Keep thread stats below new posts
Courtesy of based lewdposter
Closes https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/230
2021-07-06 10:39:59 +00:00
8398c78093 Add chud wordfilter 2021-07-06 00:55:18 +00:00
nonmakina
b792bd7b07 Merge pull request #298 from towards-a-new-leftypol/revert-289-download_filename
Revert "Filename clickable to download"
2021-07-05 14:39:29 +02:00
nonmakina
07a7971822 Revert "Filename clickable to download"
This reverts commit b12f96952a.
2021-07-05 14:34:43 +02:00
nonmakina
08c4e0723d Revert "Disable download-original.js"
This reverts commit 2ae0dc8b56.
2021-07-05 14:34:43 +02:00
towards-a-new-leftypol
50546fa3d5 Merge pull request #296 from towards-a-new-leftypol/flag_fixes
Flag fixes
2021-07-04 23:12:12 +00:00
towards-a-new-leftypol
8727f1faeb Merge pull request #297 from PietroCarrara/config
Fix API
2021-07-04 23:03:28 +00:00
towards-a-new-leftypol
5a3d55f731 Order flags alphabetically 2021-07-04 18:52:00 -04:00
towards-a-new-leftypol
327ad190ea rename atheism flag 2021-07-04 18:49:08 -04:00
towards-a-new-leftypol
610e62bfa0 re-add athiesm flag (was missing) and add one new flag 2021-07-04 18:44:03 -04:00
Pietro Carrara
b4b5d4aff7 Check if file fields are set on the API 2021-07-04 19:42:45 -03:00
towards-a-new-leftypol
e118c166de permissions fix 2021-07-04 18:40:25 -04:00
Pietro Carrara
8b8d4b12b9 Merge branch 'config' of github.com:towards-a-new-leftypol/leftypol_lainchan into config 2021-07-04 19:35:39 -03:00
Pietro Carrara
beede38c6e Load board config while generating json 2021-07-04 19:33:31 -03:00
towards-a-new-leftypol
5f542c03fc Merge pull request #295 from PietroCarrara/config
Dynamic boards, API changes
2021-07-04 21:03:05 +00:00
Pietro Carrara
e14df481a6 Check fields, use config paths 2021-07-04 15:42:47 -03:00
Pietro Carrara
953baa22ac Use thumb, not thumb_path 2021-07-04 15:05:06 -03:00
Pietro Carrara
186e122b42 Use whitelist on boards 2021-07-04 13:47:16 -03:00
Pietro Carrara
6797d447f2 Merge branch 'config' of github.com:towards-a-new-leftypol/leftypol_lainchan into config 2021-07-04 12:11:49 -03:00
Pietro Carrara
f1dd6fbab7 Enhance status.php 2021-07-04 12:11:14 -03:00
Pietro Carrara
e4be20c8c3 Modify api image fields 2021-07-04 12:02:21 -03:00
8ad44a39eb Extend maxlength of IP for IPv6 subnets 2021-07-04 08:43:38 -02:00
towards-a-new-leftypol
55e6735024 Merge pull request #294 from towards-a-new-leftypol/style_select2
Style select (second attempt)
2021-07-04 02:42:58 +00:00
towards-a-new-leftypol
c64a4bf701 Merge pull request #287 from discomrade/homepage-upgrades
Homepage upgrades
2021-07-04 02:42:19 +00:00
towards-a-new-leftypol
47a9fa507e revert original author name change 2021-07-03 22:41:25 -04:00
f48a1b71c2 Merge pull request #4 from towards-a-new-leftypol/home-upgrades
Great!
2021-07-04 02:40:04 +00:00
towards-a-new-leftypol
d7a108f881 Put image under title, inside header (homepage) 2021-07-03 22:38:01 -04:00
towards-a-new-leftypol
1685e13753 retab file 2021-07-03 22:26:31 -04:00
towards-a-new-leftypol
4bec221fdb commit dev version of style-select (because PR got screwed up) 2021-07-03 22:26:25 -04:00
towards-a-new-leftypol
ac5e6fb5a9 add a bit more space between top and logo 2021-07-03 21:33:27 -04:00
towards-a-new-leftypol
96957142ac move logo to top, refactor inline css 2021-07-03 21:31:43 -04:00
towards-a-new-leftypol
f31d6c8e83 Merge pull request #280 from towards-a-new-leftypol/defer_javascript
Defer additional_javascript for hopefully faster page loads
2021-07-04 00:16:01 +00:00
9a8aa66eb7 Redirect to thread after deleting child post 2021-07-04 00:12:08 +00:00
436886e4d9 Remove stale debug outputs 2021-07-04 00:11:36 +00:00
daf702fa3e Enable image hover 2021-07-04 00:11:36 +00:00
9f3b919b44 Various fixes for image hover 2021-07-04 00:11:36 +00:00
towards-a-new-leftypol
03b00f29fc Merge branch 'config' into defer_javascript 2021-07-04 00:07:01 +00:00
0cf01da7fe Sorted, labeled style selector 2021-07-04 00:04:13 +00:00
towards-a-new-leftypol
de1f163ed2 fix parsing number from string 2021-07-03 19:58:24 -04:00
2ae0dc8b56 Disable download-original.js 2021-07-03 23:56:12 +00:00
b12f96952a Filename clickable to download 2021-07-03 23:56:12 +00:00
Pietro Carrara
1073803c74 List boards 2021-07-03 23:55:37 +00:00
Pietro Carrara
2ec45088ea List boards 2021-07-03 00:45:18 -03:00
d90ae4b789 Improve responsiveness of homepage, add description and logo 2021-06-30 05:29:29 -02:00
bef84432f8 Add logo config variable 2021-06-30 04:42:49 -02:00
a86d0f7a9d Improve variant detection 2021-06-29 06:48:07 +00:00
2a9191b52c Extend filter charset 2021-06-29 06:48:07 +00:00
0be3f8f1f8 Improve filter 2021-06-29 06:48:07 +00:00
c82ad0ed68 Set thumbnail format to WebP 2021-06-29 06:47:52 +00:00
d05d62d599 Fix thumb_ext being ignored 2021-06-29 06:47:52 +00:00
cf0a326e3d This commit never existed. 2021-06-29 06:42:57 +00:00
19251b466d Enables exif stripping. 2021-06-29 06:42:32 +00:00
towards-a-new-leftypol
f4a785100d fix document ready 2021-06-27 01:40:57 +00:00
towards-a-new-leftypol
c44bbde511 defer additional_javascript
- this required a fix to file-selector
2021-06-27 01:09:28 +00:00
6380b071aa Desaturate image preview thumbnails in dead.css 2021-06-26 07:09:39 +00:00
3a6fe72d70 Add dead.css theme 2021-06-26 07:09:39 +00:00
c1d27702ef Add custom spoiler images 2021-06-26 07:09:05 +00:00
towards-a-new-leftypol
aacc92199a Merge pull request #279 from discomrade/date-format
Add dependency for date formating in local-time.js
2021-06-26 07:00:37 +00:00
towards-a-new-leftypol
3096438faa Merge branch 'config' into date-format 2021-06-26 06:59:35 +00:00
5ef675e578 Use thread subject for page title 2021-06-26 06:57:06 +00:00
8a05aff581 Enable post_date format dependency in local-time.js 2021-06-26 04:47:13 -02:00
towards-a-new-leftypol
fc66da1d14 remove prints 2021-06-26 02:54:35 +00:00
towards-a-new-leftypol
27dfef9393 Fix overboard generation 2021-06-26 02:54:35 +00:00
towards-a-new-leftypol
959414ca46 Revert "Revert "Add SFW overboard theme""
This reverts commit b11487a8a0.
2021-06-26 02:54:35 +00:00
dd425e3ef0 Place IP notes and ban form above post history 2021-06-23 21:49:51 +00:00
8ea261f6ca Change post_time format string 2021-06-23 21:49:25 +00:00
b4ef8e8381 Change post_time format string 2021-06-23 03:53:51 -02:00
towards-a-new-leftypol
b11487a8a0 Revert "Add SFW overboard theme" 2021-06-20 17:06:40 +00:00
nonmakina
53f82b295d Merge pull request #266 from discomrade/sfwoverboard
Add SFW overboard theme
2021-06-20 14:00:15 +02:00
nonmakina
acbe91df84 Merge pull request #267 from discomrade/banners-may
Updated flags and new banners
2021-06-20 14:00:02 +02:00
nonmakina
5ea0255fea Merge pull request #268 from discomrade/flag-preview
Flag preview image
2021-06-20 13:59:50 +02:00
33bc63a354 Add margin to flag preview image 2021-06-16 02:25:20 -02:00
towards-a-new-leftypol
76cfc7f76c Lower flood limits
- 20 seconds for any OP
- 5 seconds between posts with the same ip
2021-06-15 23:42:38 -04:00
9c3bd4ce63 Add new overboards to header bar 2021-06-11 20:16:06 -02:00
98579209db Add alt overboard 2021-06-11 20:15:16 -02:00
6b2583c839 Add validation, remove redundant validation 2021-06-10 08:07:56 -02:00
056d53adf5 Update excluded board list 2021-06-10 07:16:14 -02:00
7cc76fa0ad Define excluded boards as array to simplify code 2021-06-10 06:53:23 -02:00
8938989efb Change default overboard subtitles and thread count 2021-06-10 05:25:23 -02:00
towards-a-new-leftypol
3d52266e98 add topical leftypol banner 2021-06-08 18:03:03 -04:00
towards-a-new-leftypol
a09369bfdd banners change 2021-06-07 16:34:25 -04:00
Pietro Carrara
d68c90f2be Add status.php 2021-06-06 04:34:51 +00:00
782b886252 Explicitly reference variable 2021-06-05 09:14:58 -02:00
40475ac830 Add exclude list formatting notes 2021-06-01 20:44:27 -02:00
4e0e4f720e Allow arbritary overboard creation, make catalog compatible 2021-06-01 02:39:39 -02:00
8daf9d79ef Revert "Add SFW overboard and its catalog option"
This reverts commit 19acf84cb3.
2021-06-01 02:14:48 -02:00
b2c7aa42f3 Create flag preview 2021-05-31 17:30:44 -02:00
3b05c7bc00 Correct spelling of 'atheism' 2021-05-31 11:14:07 -02:00
b09a932211 Add Eristocracy flag 2021-05-31 11:13:16 -02:00
8d4815921d Update flags 2021-05-31 09:02:11 -02:00
305e698e32 Add new banners 2021-05-31 04:21:28 -02:00
19acf84cb3 Add SFW overboard and its catalog option 2021-05-28 06:27:10 -02:00
towards-a-new-leftypol
ee8107f775 Merge pull request #264 from discomrade/filter-may-19
Consider foreign language characters in word filter dividers
2021-05-24 19:06:44 +00:00
7993602665 Add UTF-8 flag on short filters 2021-05-23 05:49:24 -02:00
k
7aabc15867 Add exception to important citation 2021-05-19 22:24:42 -02:00
k
a271a9e4b0 Allow non-English ASCII to divide match 2021-05-19 22:24:17 -02:00
towards-a-new-leftypol
d737a047f8 add comment to securimage option 2021-05-15 03:06:16 -04:00
towards-a-new-leftypol
1ac46ff57e Merge pull request #263 from towards-a-new-leftypol/securimage_config
securimage in webconfig
2021-05-15 07:02:39 +00:00
towards-a-new-leftypol
55c729f574 securimage in webconfig
Make sure securimage option (to enable captcha) can be set in web configuration,
by adding the default (false) to config.php
2021-05-15 03:01:15 -04:00
towards-a-new-leftypol
7edb471379 Merge pull request #262 from discomrade/rules-and-faq
Modify Rules and Help/FAQ
2021-05-15 06:42:02 +00:00
f13e4dfa2b Merge pull request #3 from towards-a-new-leftypol/sidebar_rules
Add links to sidebar to Faq and Rules pages
2021-05-15 06:40:56 +00:00
towards-a-new-leftypol
eaa6125f46 Add links to sidebar to Faq and Rules pages 2021-05-15 02:32:56 -04:00
3893e8e331 Remove 'Global' from rules, minor change 2021-05-14 21:41:39 -02:00
22acb3e039 Add rules and Help/FAQ 2021-05-13 02:02:39 -02:00
towards-a-new-leftypol
653dbc7cf0 Merge pull request #261 from discomrade/may-7-filters
Reduce overreach in word filter
2021-05-13 02:54:26 +00:00
f2ac2d2b8a Reduce overreach in word filter 2021-05-12 21:17:41 -02:00
towards-a-new-leftypol
30cb2951fc Merge pull request #260 from discomrade/may-7-filters
Reduce false positives in word filter
2021-05-12 04:10:57 +00:00
1f848ca437 Reduce false positives in word filter 2021-05-11 11:07:15 -02:00
towards-a-new-leftypol
38ffb75d8a Merge pull request #255 from discomrade/captcha
Add basic captcha
2021-05-09 09:41:29 +00:00
towards-a-new-leftypol
5992e57eda Merge pull request #258 from discomrade/patch-5
Allow flags to be over 11px height
2021-05-09 09:32:12 +00:00
towards-a-new-leftypol
c9eae4bd69 Merge pull request #259 from discomrade/may-7-filters
Update filters
2021-05-09 09:31:53 +00:00
towards-a-new-leftypol
c994ae7f23 Merge pull request #252 from towards-a-new-leftypol/moving_fix2
Fixes moving threads to a different board
2021-05-09 09:31:22 +00:00
6b62058172 Merge pull request #2 from towards-a-new-leftypol/discomrade_captcha
Remove duplicate block for captcha to work on dev
2021-05-08 10:57:25 +00:00
towards-a-new-leftypol
ec1041e095 Remove duplicate block for captcha to work on dev 2021-05-08 06:28:46 -04:00
993af46670 Upgrade slur filter and comments 2021-05-08 02:58:22 -02:00
8485dad4ae Remove obsoleted filter 2021-05-08 02:58:22 -02:00
f979567b10 Allow flags to be over 11px height
Submitted on behalf of Zul.
2021-05-06 00:28:25 +00:00
f0b3c0fcb6 Add automatic and manual reloading of captchas 2021-05-05 15:17:34 -02:00
11bab0a9ad Add basic captcha 2021-05-05 10:29:06 -02:00
towards-a-new-leftypol
661837a4b1 Merge pull request #250 from towards-a-new-leftypol/local_changes
Local changes
2021-05-04 22:50:43 +00:00
towards-a-new-leftypol
012a08dda6 Merge pull request #254 from discomrade/patch-3
Add filter for known bot spammer
2021-05-04 22:43:49 +00:00
df98d2e66c Fix oversight 2021-05-04 22:42:06 +00:00
16cb2ab75c Remove range limit for filename 2021-05-04 22:30:05 +00:00
a4906098a6 Increase length range of filename detection 2021-05-04 22:27:15 +00:00
68046d4a26 Add filter for known bot spammer 2021-05-04 22:23:28 +00:00
towards-a-new-leftypol
be1e0bb2be Fixes moving threads to a different board
- it seems that it still chokes on posts with missing files
- this seems to fix this and move the threads intact
- i didn't investigate fully what is going on here
2021-05-03 02:21:10 -04:00
towards-a-new-leftypol
094e102269 include example of new regex 2021-05-01 21:49:33 -04:00
towards-a-new-leftypol
95c939dd22 Changes in settings by Zul and Discomrade
- These are local changes via web interface committed
- also new wordfilter suggestions by board, with comrade's explaination
2021-05-01 21:43:59 -04:00
towards-a-new-leftypol
f7af183f86 Merge pull request #249 from nonmakina/filter2
Adds wordfilters
2021-04-28 16:08:16 +00:00
5adc4eb33e Adds ? to filter 2021-04-27 00:05:11 -05:00
3d2ea677b4 Word filters 2021-04-26 23:52:09 -05:00
towards-a-new-leftypol
c3ee0b8fb5 Merge pull request #248 from towards-a-new-leftypol/flags
add moar flags
2021-04-26 23:43:24 +00:00
towards-a-new-leftypol
f625b2e656 add moar flags 2021-04-25 01:28:52 -04:00
towards-a-new-leftypol
b68394b075 Merge pull request #247 from nonmakina/enableSearch
Enables search
2021-04-15 03:24:26 +00:00
26e510ab1a Enables search 2021-04-14 21:55:10 -05:00
towards-a-new-leftypol
28a5dc1d72 Revert "allow embeds of audio streams with ogg extension"
This reverts commit b3c881231f.
2021-04-09 03:25:14 -04:00
towards-a-new-leftypol
4d998f7a95 Remove reference to non-existant js file in config.php 2021-04-03 20:20:54 -04:00
towards-a-new-leftypol
334a88248c remove non-existant js file 2021-04-03 19:13:49 -04:00
towards-a-new-leftypol
063c11bb1f Merge pull request #243 from towards-a-new-leftypol/allow_ogg_embed
Allow ogg embed
2021-04-03 19:05:42 -04:00
towards-a-new-leftypol
1123b4009d Merge branch 'config' into allow_ogg_embed 2021-04-03 19:05:28 -04:00
towards-a-new-leftypol
2efaafd639 Merge pull request #242 from towards-a-new-leftypol/youtube_thumbs
Youtube thumbs
2021-04-03 19:04:33 -04:00
towards-a-new-leftypol
11a5344a87 Youtube thumbnail embeds the video
(as opposed to working as a link)
2021-04-03 19:02:53 -04:00
towards-a-new-leftypol
635537fd74 Fix embed url 2021-04-02 23:04:03 -04:00
towards-a-new-leftypol
b3c881231f allow embeds of audio streams with ogg extension 2021-04-02 22:06:42 -04:00
towards-a-new-leftypol
2c6628b7cd display youtube video thumbnail (with local url) in embeds 2021-04-02 20:15:26 -04:00
towards-a-new-leftypol
5216f2e189 catalog page - rewrite youtube url to be local 2021-04-02 19:39:42 -04:00
towards-a-new-leftypol
7c7e4cca70 Merge pull request #241 from towards-a-new-leftypol/revert_dark
Restore dark red theme to be the default
2021-04-02 14:31:18 -04:00
towards-a-new-leftypol
e7752273f9 remove overriding font for h1 tags (titles) from dark themes 2021-04-02 14:28:56 -04:00
towards-a-new-leftypol
3393bd649c Restore dark red theme to be the default 2021-04-02 14:18:55 -04:00
towards-a-new-leftypol
67a37ccf69 Merge pull request #236 from towards-a-new-leftypol/rm_error_banner
Remove banner that looks like a real error
2021-04-02 14:14:34 -04:00
towards-a-new-leftypol
8c67103c16 Merge pull request #237 from towards-a-new-leftypol/commit_gurochan_css_changes
Commit changes from issue 223 on github
2021-04-02 14:14:25 -04:00
towards-a-new-leftypol
afc3d158b4 Merge pull request #238 from towards-a-new-leftypol/issue_229
Commit the patch from issue 229
2021-04-02 14:14:13 -04:00
towards-a-new-leftypol
04e68d220c remove april fools wordfilters 2021-04-02 03:55:53 -04:00
d65cab7270 Important changes on this date2 2021-03-31 22:15:59 -06:00
9b2313e39c Important changes on this date2 2021-03-31 22:14:47 -06:00
73c189bdea Important changes on this date 2021-03-31 22:07:01 -06:00
towards-a-new-leftypol
314eb340e4 Set default theme to Jungle 2021-03-31 22:32:09 -04:00
towards-a-new-leftypol
f65a588760 Commit the patch from issue 229
https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/229

- also remove unused var declaration
2021-03-20 00:48:20 -04:00
towards-a-new-leftypol
6cbd1b3dab Commit changes from issue 223 on github 2021-03-20 00:37:27 -04:00
towards-a-new-leftypol
7839422a45 Remove banner that looks like a real error
- bunkerchan isn't topical anymore, so this banner is confusing now
2021-03-20 00:26:25 -04:00
towards-a-new-leftypol
81a2b2f324 Merge pull request #235 from nonmakina/banners2021March4
Banners from 93227 to 104637 (except duerte) and new flags
2021-03-04 15:58:50 -05:00
8f25717239 Banners from 93227 to 104637 (except duerte) 2021-03-04 14:52:44 -06:00
towards-a-new-leftypol
c384ac12f5 Sum up stats that nonmakina added
- fixes the "totals" row in the table on news.html
2021-02-26 20:23:27 -05:00
towards-a-new-leftypol
e0bc0e106d Merge pull request #218 from nonmakina/webmFix
Adds the proposed ffmpeg.php changes
2021-02-26 19:27:15 -05:00
towards-a-new-leftypol
ba8d243ca2 Merge pull request #234 from nonmakina/banners2021Feb
Banners from 41332 up to 93227
2021-02-26 19:26:32 -05:00
towards-a-new-leftypol
6fae2cd102 Merge pull request #233 from nonmakina/ipCounter
Hourly, daily, weekly IP counter
2021-02-26 19:25:49 -05:00
5c6d09ce1e Banners from 41332 up to 93227 2021-02-26 16:39:57 -06:00
nonmakina
a00962c6d8 Merge pull request #224 from nonmakina/youtubeEmbed2
Youtube embed
2021-02-23 00:21:54 -06:00
936b518efd remove rolling average 2021-02-21 19:57:37 -06:00
11bb4a8019 remove rolling average 2021-02-21 19:56:42 -06:00
75af4aaa47 test rolling average' 2021-02-21 19:32:11 -06:00
c1d736c713 change to week 2021-02-21 19:04:36 -06:00
cc569aa22f change to week 2021-02-21 19:03:13 -06:00
fc3854594d fix 2021-02-21 16:39:01 -06:00
f68fed678b fix 2021-02-21 16:38:00 -06:00
3c5b8193b6 more counters 2021-02-21 16:36:09 -06:00
5083f3caeb Fix 2021-02-21 16:24:16 -06:00
29433c989f Fix 2021-02-21 16:23:32 -06:00
735a9a6249 Adds more IP counters 2021-02-21 16:18:26 -06:00
towards-a-new-leftypol
e9d03ef243 Fix previous commit which overwrote some things 2021-02-20 17:46:03 -05:00
towards-a-new-leftypol
91b6a1e854 check in local changes made by zul? 2021-02-20 17:44:16 -05:00
towards-a-new-leftypol
b929ed8d55 Merge pull request #228 from xComatoast/Codetags
Codetags
2021-02-20 17:39:36 -05:00
Comatoast
a7324dae9c This will allow the use of code tags 2021-02-07 11:50:49 -08:00
Comatoast
041ed36019 Merge remote-tracking branch 'upstream/config' into frontpage2 2021-02-07 11:46:56 -08:00
nonmakina
1f5d04cfd6 Merge pull request #226 from towards-a-new-leftypol/move_merge_fixes
Improve robustness when moving / merging threads
2021-01-30 19:28:08 -06:00
towards-a-new-leftypol
02119c5c58 Improve robustness when moving / merging threads
- previously this would choke on threads where the image file is
missing
2021-01-31 01:20:45 +00:00
7a86b9f092 fixes Jquery references on loop 2021-01-29 21:39:00 -06:00
17c7fb3db0 Iterates over nodes 2021-01-29 21:30:55 -06:00
f544dde952 Re-introduces the youtube embed changes.
This reverts commit ec9d144c67.
2021-01-29 20:55:23 -06:00
towards-a-new-leftypol
ddd2a4843b Merge pull request #222 from towards-a-new-leftypol/revert-217-youtubeEmbed
Revert "Replace Youtube embed"
2021-01-29 21:10:43 -05:00
nonmakina
ec9d144c67 Revert "Replace Youtube embed" 2021-01-29 20:09:27 -06:00
towards-a-new-leftypol
4fd6506069 Merge pull request #212 from towards-a-new-leftypol/op_creation_time
Op creation time
2021-01-29 20:29:49 -05:00
towards-a-new-leftypol
25725d4eb6 Merge pull request #200 from nonmakina/pph-and-uniques
Adds PPH and Unique IP for site and for each board.
2021-01-29 20:28:46 -05:00
towards-a-new-leftypol
d9ee367ff2 Merge pull request #217 from nonmakina/youtubeEmbed
Replace Youtube embed
2021-01-27 23:14:01 -05:00
towards-a-new-leftypol
c5b62f18e9 Slightly better error message for rate limiting thread creation 2021-01-27 22:54:50 -05:00
towards-a-new-leftypol
66b6682952 OP rate limiting should only look at opening posts in the flood table 2021-01-27 22:51:33 -05:00
towards-a-new-leftypol
f71bc3337b retab config.php 2021-01-27 22:50:32 -05:00
9ee06c9e6d Adds the proposed ffmpeg.php changes 2021-01-27 20:09:18 -06:00
6b21692146 Fixes remove embed 2021-01-26 00:59:37 -06:00
816094ce96 Adds missing text and fixes js errors 2021-01-26 00:52:23 -06:00
1afb5a5f31 Adds support for embed button for youtube. Eliminates preview image fetched from youtube that was causing a leak 2021-01-26 00:44:23 -06:00
towards-a-new-leftypol
e188887731 Clean up instance-config.php
- remove commented code
- revert overwritten flood values back
2021-01-24 13:49:56 -05:00
towards-a-new-leftypol
f00faf0b62 retab inc/filters.php 2021-01-24 13:48:32 -05:00
towards-a-new-leftypol
325d442f2a Merge remote-tracking branch 'lpdev_local/thread_creation_time' into op_creation_time 2021-01-24 02:47:42 -05:00
towards-a-new-leftypol
fc08073309 print statements 2021-01-24 07:47:21 +00:00
towards-a-new-leftypol
a2619087cf Merge remote-tracking branch 'lpdev_local/thread_creation_time' into op_creation_time 2021-01-24 02:29:49 -05:00
towards-a-new-leftypol
53cb7ac5f0 Do noip stuff before other stuff (idk) 2021-01-24 07:29:12 +00:00
towards-a-new-leftypol
60070f9e0c 30 seconds betweeen each new post 2021-01-24 01:56:01 -05:00
towards-a-new-leftypol
65d82ff3f0 OP creation rate-limiting
- minimum time between OP is 30 seconds
2021-01-24 06:49:01 +00:00
towards-a-new-leftypol
4d4f87c40d commented out filters modification for flood_time 2021-01-24 03:29:18 +00:00
Comatoast
73a67be553 Ok, third time is the charm. Fix for the frontpage 2021-01-23 18:08:02 -08:00
Comatoast
b243f5ddce Fixes frontpage theme 2021-01-22 21:47:30 -08:00
Comatoast
23c55aa9f1 Merge remote-tracking branch 'upstream/config' into frontpage 2021-01-22 21:46:26 -08:00
towards-a-new-leftypol
0b86471076 Merge pull request #196 from nonmakina/fontFix
Improves readibility of text
2021-01-22 12:08:11 -05:00
221ff92826 local vars 2021-01-19 22:39:29 -06:00
614c1971f3 h2 -> h1 2021-01-19 21:49:43 -06:00
6f87892a4b Fixes style. I18s table headers 2021-01-19 21:47:53 -06:00
6cc047100a Changes count for sum 2021-01-19 21:18:58 -06:00
fabbd15c86 syntax and html errors 2021-01-19 21:10:29 -06:00
1ef960f2aa bugs 2021-01-19 20:49:15 -06:00
caadfdff2e Syntax errors 2021-01-19 20:38:18 -06:00
adb4112564 Per board pph 2021-01-19 20:27:00 -06:00
7ccc9067a9 Fixes bug and updates PPH on each post 2021-01-19 18:40:53 -06:00
Comatoast
bb6b4b868c Front Page theme fix matching default of board 2021-01-19 15:37:57 -08:00
nonmakina
22d5ee3fa6 Merge pull request #189 from dedushka1/fix-robots-txt
Allow robots
2021-01-19 17:02:20 -06:00
nonmakina
4c7fbead86 Merge pull request #195 from dedushka1/revert-mod-edit-post-page
Revert bad change that commented this out on mod post edit page
2021-01-19 17:01:34 -06:00
nonmakina
cb26f537f3 Merge pull request #190 from dedushka1/theme-deletion-bug
Fix minor bug that disallows deletion of themes
2021-01-19 16:59:50 -06:00
a1d2f0c701 Improves readibility 2021-01-19 16:57:08 -06:00
Dedushka
801d5d1459 Revert bad change that commented this out on mod post edit page 2021-01-19 14:53:10 -05:00
dedushka1
6d67ca34f0 Merge pull request #178 from nonmakina/bumplockIndicator
Implements fixes and changes to be able to view the bumplock status of a thread
2021-01-19 14:51:08 -05:00
dedushka1
4d28c956ab Merge pull request #185 from nonmakina/overboardCountFix
Adds function to count posts and images of a thread
2021-01-19 14:48:59 -05:00
Dedushka
6f2545e716 Add PPH and unique posters stats to home page 2021-01-18 23:26:53 -05:00
Dedushka
5ebfb22a5e Fix minor bug that disallows deletion of themes 2021-01-18 22:32:20 -05:00
Dedushka
5672300267 Allow robots 2021-01-18 21:46:21 -05:00
dedushka1
a6c4f5a1ec Merge pull request #183 from nonmakina/optionsFix1
Moves options to the top of the JS imports.
2021-01-18 21:39:55 -05:00
dedushka1
b26c2a0256 Merge pull request #179 from nonmakina/cytubeOnBoardList
Cytube on board list
2021-01-18 21:34:38 -05:00
dedushka1
9f309c7362 Merge pull request #181 from nonmakina/allowCompressedFiles
Adds gz and bz2 to allowed upload extensions
2021-01-18 21:32:05 -05:00
dedushka1
f914297501 Merge pull request #177 from nonmakina/postViewLimit2
Increases number of posts that are visible in the IP post history view
2021-01-18 21:05:39 -05:00
dedushka1
aee880aae8 Merge pull request #186 from nonmakina/noFuture
Removes Tomorrow stylesheet
2021-01-18 20:59:40 -05:00
nonmakina
e1ac470df0 Merge pull request #182 from nonmakina/modMassDelete
Enables mod mass deletion
2021-01-18 19:16:10 -06:00
d1d0dd2f76 Optimizes board rebuilds on deletion by IP 2021-01-18 18:44:30 -06:00
nonmakina
c9b736e1c7 Merge pull request #188 from dedushka1/config
Allow posting from catalog.
2021-01-18 17:56:48 -06:00
towards-a-new-leftypol
376d934c61 Merge pull request #180 from xComatoast/WarrantCanary
Adds a warrant canary to the repo.
2021-01-18 17:49:42 -05:00
Dedushka
1eb75f1cee Allow posting from catalog.
Addresses #134.

The catalog template has been modified to use the board array, which
is expected by the post form template. Because the overboard is a
"virtual board", we created a "fake" overboard array to supply
necessary information to the modified template.

Javascript was also added to hide form on first visit.
2021-01-18 17:30:21 -05:00
54a0c74aaf Removes Tomorrow stylesheet 2021-01-18 05:01:41 -06:00
aebc63b09a Fix filecount 2021-01-18 04:59:13 -06:00
b5ebf71a2b Fix offset 2021-01-18 04:49:46 -06:00
40ae49f82e Add offset 2021-01-18 04:35:34 -06:00
e5947b87c7 Add offset 2021-01-18 04:31:02 -06:00
1337b233e7 Fetch one, instead of all 2021-01-18 04:26:18 -06:00
568b194f21 Adds function to count posts and images of a thread 2021-01-18 04:11:47 -06:00
1998822e9c Moves options to the top of the JS imports. 2021-01-18 03:13:09 -06:00
a3dee77f47 Adds checks for mod permissions to delete posts in board 2021-01-18 01:40:04 -06:00
1bd809b9f0 If mod, bypass password on delete 2021-01-18 01:35:18 -06:00
40012ef81c Removes rebuild after each deleted post when deleting by ip. 2021-01-18 01:30:20 -06:00
4bf8ba7731 Adds gz and bz2 to allowed upload extensions 2021-01-17 22:57:46 -06:00
Comatoast
068e130a71 Adds a warrant canary to the repo. 2021-01-17 20:38:18 -08:00
b4bbe54510 Fixes path 2021-01-17 22:00:01 -06:00
4ac284d744 Adds cytube to top bar 2021-01-17 21:57:34 -06:00
2dd5826e2e Incorrect variable fix 2021-01-17 21:37:47 -06:00
1acb060694 Implements fixes and changes to be able to view the bumplock status of a thread 2021-01-17 21:31:06 -06:00
towards-a-new-leftypol
48650d8ddd Merge pull request #176 from xComatoast/modLogs
Fixed: Mod  Log Permissions
2021-01-17 21:44:50 -05:00
909c5f0a25 Increases number of posts that are visible in the IP post history view 2021-01-17 20:42:23 -06:00
Comatoast
28c68d7369 Fixed: Mod Log Permissions 2021-01-17 18:30:42 -08:00
towards-a-new-leftypol
598ca1bb1d Merge pull request #138 from nonmakina/news
adds news to front page
2021-01-17 23:11:37 +00:00
4bc9e91591 Adds stylesheet to news.html template 2021-01-17 17:08:09 -06:00
3a22d6a61d Fixes board list on homepage 2021-01-17 16:57:28 -06:00
4e520ad5a4 fixes breaking changes 2021-01-17 16:48:34 -06:00
4cea6567eb fixes breaking changes 2021-01-17 16:47:40 -06:00
75ac5dccb0 Merge remote-tracking branch 'upstream/config' into news 2021-01-17 16:44:40 -06:00
nonmakina
92d00c2aa9 Merge pull request #170 from dedushka1/add-styles
Add styles
2021-01-17 16:04:36 -06:00
Dedushka
88c5ecc67e Add updated demain stylesheets 2021-01-17 17:01:32 -05:00
dedushka1
bb2739f93c Merge pull request #1 from nonmakina/add-styles-1
Add styles 1
2021-01-17 16:57:55 -05:00
Dedushka
68080f90bf Add bunker-like CSS them, adresses #145 2021-01-17 15:53:08 -06:00
Dedushka
91efbfd418 Add styles, addresses #38 2021-01-17 15:53:08 -06:00
Dedushka
a4094a37f9 Revert "Remove secrets, require instance-config.secret.php"
This reverts commit 565b3807bd.
2021-01-17 16:50:35 -05:00
Dedushka
6208e76816 Revert "Put secrets in another file."
This reverts commit 891329946e.
2021-01-17 16:50:11 -05:00
Dedushka
b56670daa0 Add bunker-like CSS them, adresses #145 2021-01-17 16:17:37 -05:00
Dedushka
d17d35c35d Add styles, addresses #38 2021-01-17 16:10:56 -05:00
Dedushka
565b3807bd Remove secrets, require instance-config.secret.php 2021-01-17 15:40:30 -05:00
Dedushka
891329946e Put secrets in another file.
This commit makes it easier to make changes to the instance config
without worrying about overwriting secrets and database configuration.

It also mitigates some possibility of leaking secrets.
2021-01-17 15:31:48 -05:00
towards-a-new-leftypol
8d120212b7 Merge pull request #167 from towards-a-new-leftypol/myownbranch
Commit local changes made on server
2021-01-17 20:07:23 +00:00
towards-a-new-leftypol
6acff64f17 Revert "Enable memcached in the config"
This reverts commit b66ef17262.
2021-01-17 15:01:33 -05:00
towards-a-new-leftypol
0a404925ea instance config flood settings 2021-01-17 14:38:09 -05:00
towards-a-new-leftypol
b66ef17262 Enable memcached in the config 2021-01-17 14:37:43 -05:00
nonmakina
662b02a336 Merge pull request #165 from dedushka1/log-ip-privacy
Hide IPs in Moderation Logs
2021-01-17 13:32:07 -06:00
Dedushka
a037d8b5e0 Protect IPs in public moderation logs.
As reported, IPv6 addresses were not properly hidden in the public
facing moderation logs. This commit filters both IPv4 and IPv6
addresses.

We broke out into a separate function so that it can be tested with
the test suite.

A rudimentary test has been added to test the newly added
protect_ip($entry) function.
2021-01-17 13:03:17 -05:00
Dedushka
f030ce8215 Don't ignore files in inc/mod directory.
The original pathspec matches any path with "mod" in it. We modified
it here to only match directories at the top level.
2021-01-17 13:01:22 -05:00
nonmakina
64a53e16e6 Merge pull request #135 from PietroCarrara/overboard-api
Build overboard json
2021-01-12 22:03:28 -06:00
a7e2bbbd87 adds news to front page 2021-01-12 14:21:32 -06:00
Pietro Carrara
3a5081e73d Add board data on all catalogs, rename overboard 'replies' and 'images' fields to keep consistency 2021-01-12 15:46:01 -03:00
Pietro Carrara
dc63ff61ee Correctly page the overboard json 2021-01-12 09:55:08 -03:00
Pietro Carrara
0d80e600b5 Only rebuild the catalog for the overboard 2021-01-12 09:16:43 -03:00
towards-a-new-leftypol
eb5dee5283 Merge pull request #133 from PietroCarrara/api-unique-ips
Add unique_ips field to the API
2021-01-11 23:53:41 +00:00
Pietro Carrara
e57b760de8 Wrap overboard api threads inside a page 2021-01-11 20:48:22 -03:00
Pietro Carrara
2ca72c6a7c Build overboard json 2021-01-11 20:23:59 -03:00
Pietro Carrara
20135fd1db Add unique_ips field to the API 2021-01-11 15:46:57 -03:00
nonmakina
0bdbe0f927 Merge pull request #112 from nonmakina/overboardFixes
Overboard fixes
2021-01-11 10:54:02 -06:00
06542ec421 fixes 2021-01-11 10:42:51 -06:00
d8120b3b18 CR. Refactors duplicate code. Fixes boardlist link error. 2021-01-11 10:36:29 -06:00
towards-a-new-leftypol
bde8b2980c Merge pull request #130 from nonmakina/pathFixes
Path fixes
2021-01-11 10:15:49 +00:00
towards-a-new-leftypol
ae93e745df Merge pull request #131 from nonmakina/uniqueIpFix
Fixes unique IP auto-reload bug
2021-01-11 10:13:42 +00:00
towards-a-new-leftypol
ca5fde5f83 Merge pull request #119 from nonmakina/banListFix
Fixes unusuable mod ban list
2021-01-11 10:12:23 +00:00
8bbd4a014b moves br ontop of unique IP to fix auto-reload error 2021-01-11 02:08:47 -06:00
33ae50b63f stale comment 2021-01-11 02:04:05 -06:00
2d1a712a20 Adds limit to overboard catalog 2021-01-10 22:18:32 -06:00
5eea6c4ac7 fixes path for catalog. fixes syntax bugs. 2021-01-10 21:55:20 -06:00
03dc4db644 Add overboard catalog to the rebuild-all action 2021-01-10 21:28:16 -06:00
73ee83c9c6 adds catalog for overboard 2021-01-10 21:18:09 -06:00
399391116b Deletes dead code 2021-01-10 19:48:23 -06:00
13efc37bdd fixes path for image_deleted 2021-01-10 19:45:31 -06:00
93d0784a5e Sets the correct default path in the config.php, and removes the re-write in instance-config. The path set in config was incorrect, so there is no benefit in keeping it incorrect and overwriting in instance config. And now that it's correct, it's no benefit to have a duplicate setting. 2021-01-10 19:28:58 -06:00
towards-a-new-leftypol
d5a9127c83 Merge pull request #115 from nonmakina/pdfThumbnail
Turns on thumbnails for pdf and djvu filetypes
2021-01-10 11:19:17 -05:00
towards-a-new-leftypol
c9b67ec5ca Merge pull request #116 from nonmakina/fixReporting
Fixes reporting function
2021-01-10 11:15:24 -05:00
towards-a-new-leftypol
fdd91c0fd7 Merge pull request #117 from nonmakina/banners
Adds banner support and banners
2021-01-10 11:11:37 -05:00
towards-a-new-leftypol
42916c9356 Merge pull request #120 from nonmakina/uniqueIps
Adds a unique IP counter on the bottom of each thread. It counts the number of unique IPs that has posted so far
2021-01-10 11:10:25 -05:00
towards-a-new-leftypol
6d1406b2f0 Merge pull request #126 from nonmakina/originalFilename
Adds js that set an alternative link on media to download them with their original filenames
2021-01-10 11:09:27 -05:00
towards-a-new-leftypol
84f6e25adf Merge pull request #122 from nonmakina/noDeleteThread
No delete thread
2021-01-10 11:08:25 -05:00
towards-a-new-leftypol
8b8e3bc0ed Merge pull request #127 from nonmakina/txtThumbFix
Explicitly sets txt_file_thumbnail to false
2021-01-10 11:05:31 -05:00
ed9d6eb30d Explicitly sets txt_file_thumbnail to false 2021-01-09 20:05:01 -06:00
55020d2c7f Adds js that set an alternative link on media to download them with their original names 2021-01-09 19:46:41 -06:00
fd0aa9c70d Whitespace and removed error. 2021-01-09 19:26:59 -06:00
3f1ef0e0fe Removes ability to delete own threads. 2021-01-09 19:24:53 -06:00
46ecd710b5 Removes mod requirement 2021-01-09 18:20:16 -06:00
118eed2eb4 Makes board log usable 2021-01-09 18:14:33 -06:00
8cb33ade7f Fixes unusuable mod ban list 2021-01-09 18:01:58 -06:00
a2636ce0d6 Adds support to prepend foreign boards on the boardlist. Used to add the overboard. 2021-01-09 17:01:44 -06:00
dd37756f24 Fixes inline-expanding.js to allow clickable pdf thumbnails 2021-01-09 16:41:05 -06:00
9378d247b9 Removes border from banner 2021-01-09 16:27:46 -06:00
e48982cf41 Adds banner support and banners 2021-01-09 16:11:28 -06:00
9768dd58df Fixes reporting function 2021-01-09 15:54:30 -06:00
3f57632d44 Turns on thumbnails for pdf and djvu filetypes 2021-01-09 15:08:24 -06:00
8c6d284989 fix typo produced when copying changes 2021-01-09 01:25:44 -06:00
295eb11117 makes some fixes to the overboard code 2021-01-09 01:22:26 -06:00
towards-a-new-leftypol
f9a6b584e1 Merge pull request #98 from nonmakina/markup1
fixes gentoo style. Fixes redtext markup. Adds orange quoting (ie: <). Adds underlining.
2021-01-04 22:19:40 -05:00
ddc35369c5 removes red quote styling and turns it back to the default green color 2021-01-04 20:33:20 -06:00
b27a838c2a strikethrough 2021-01-04 20:23:32 -06:00
towards-a-new-leftypol
95ce162d77 Merge pull request #97 from towards-a-new-leftypol/fixes
WIP post ajax behaviour fixes
2021-01-04 21:16:36 -05:00
towards-a-new-leftypol
7ab8a576e0 Merge pull request #99 from PietroCarrara/api-messages
Add warning and ban messages to the API
2021-01-04 21:11:18 -05:00
towards-a-new-leftypol
96b457af11 Merge pull request #101 from nonmakina/spoilers
Adds spoilers to api
2021-01-04 21:11:12 -05:00
towards-a-new-leftypol
f3dcd08881 Merge pull request #94 from towards-a-new-leftypol/disable_antispam
Disable antispam for now
2021-01-04 20:46:29 -05:00
towards-a-new-leftypol
2657cb7cf0 Remove console logs 2021-01-04 20:41:19 -05:00
182ad6fea8 Fixes indenting 2021-01-04 17:46:50 -06:00
e132e1d663 Adds spoilers to api 2021-01-04 17:42:57 -06:00
Pietro Carrara
d0ca66fa49 Add warning and ban messages to the API 2021-01-04 19:06:29 -03:00
2a37ad3b5d fixes gentoo style. Fixes redtext markup. Adds orange quoting (ie: <). 2021-01-04 15:59:59 -06:00
towards-a-new-leftypol
454ad4381a Fix for ajax posting not showing you your new post
- TODO: there are console.logs that still need to be removed
- Posting was loading the new page twice - once in ajax.js and once in
auto-reload.js. auto-reload will handle this behaviour, the other is
commented out
- The new post does not immediately show up when immediately ajax
requesting the page after posting completes. Adding an epoch query
parameter did not change this. Instead of figuring out why it was easier
to add a 500ms delay before requesting the page, now it seems to work
well.
2021-01-04 03:00:16 -05:00
towards-a-new-leftypol
b256157c40 retab ajax.js 2021-01-04 02:32:45 -05:00
towards-a-new-leftypol
4e7351394a Retab auto-reload.js 2021-01-04 02:32:10 -05:00
towards-a-new-leftypol
a1f5986c21 Disable antispam for now
- some users were having issues posting
- the issues are inconsistent. we should be careful with this feature,
    perhaps even log details of what went wrong when the error for this
    is shown and analyze those logs.
2021-01-04 01:12:42 -05:00
towards-a-new-leftypol
b03d4f7c54 Merge pull request #93 from towards-a-new-leftypol/revert-91-api-spoiler
Revert "Add spoiler information to the API"
2021-01-03 22:51:09 -05:00
nonmakina
0446ade568 Revert "Add spoiler information to the API" 2021-01-03 21:40:41 -06:00
towards-a-new-leftypol
029a4408d1 Merge pull request #92 from towards-a-new-leftypol/fixes
Potential fix for an error message that mods get when banning
2021-01-03 22:31:44 -05:00
towards-a-new-leftypol
1ffd3c4740 Merge pull request #86 from nonmakina/moreJs
adds a bunch of more js modules
2021-01-03 22:10:24 -05:00
towards-a-new-leftypol
98a69a3188 Fix ban 2021-01-03 21:59:29 -05:00
towards-a-new-leftypol
38f40d3d06 retab pages.php 2021-01-03 21:59:29 -05:00
nonmakina
53dd21f5bf Merge pull request #91 from PietroCarrara/api-spoiler
Add spoiler information to the API
2021-01-03 20:59:26 -06:00
towards-a-new-leftypol
7ecd87765a Merge pull request #89 from towards-a-new-leftypol/mp3_support
allow mp3 uploads
2021-01-03 21:50:07 -05:00
Pietro Carrara
f0d7c24c97 Add spoiler information to the API
Using 1,0 rather than true,false keeps compatibility
with Clover/Kuroba's implementation of vichan's API parser
2021-01-03 20:02:48 -03:00
towards-a-new-leftypol
6011a31e03 allow mp3 uploads 2021-01-03 04:50:06 -05:00
8258ea609d removed duplicate style-select. Moved webm settings. Removed treeview. 2021-01-02 10:44:34 -06:00
5a6bc5f3fb adds a bunch of more js modules 2021-01-02 10:29:41 -06:00
towards-a-new-leftypol
708debe4e4 Merge pull request #85 from nonmakina/postFilter
Post filter
2021-01-02 02:37:31 -05:00
towards-a-new-leftypol
b09a73135a Merge pull request #84 from nonmakina/showYous
Adds (You)s
2021-01-02 02:36:04 -05:00
8e77b1d9fd Adds dependency: post-menu. 2021-01-02 01:18:21 -06:00
4f2b47fdd2 Adds post filtering 2021-01-02 01:06:55 -06:00
7785736d53 Adds (You)s 2021-01-02 00:56:43 -06:00
towards-a-new-leftypol
8ab6219db2 Merge pull request #73 from nonmakina/autoReload
Fixes jquery API breaking changes in auto-reload and thread-stats
2020-12-31 07:13:42 -05:00
towards-a-new-leftypol
271e4f1f5d chmod 644 2020-12-31 05:54:09 -05:00
towards-a-new-leftypol
971acea884 Merge pull request #69 from PietroCarrara/json-flags
Enable flags on the JSON api
2020-12-31 05:40:15 -05:00
Pietro Carrara
e4d36ba86a Enable API flags for user_flag and country_flags 2020-12-31 07:29:10 -03:00
Barbara-Pitt
77385bffcd Merge pull request #71 from nonmakina/moreFlags
Adds FARC flag and United Farm Workers flag
2020-12-31 01:29:03 -06:00
Barbara-Pitt
1201a5da47 Merge pull request #72 from nonmakina/defaultDarkRed
Changes default stylesheet from Yotsuba B to Dark Red
2020-12-31 01:25:15 -06:00
c2a2c667d6 Fixes jquery API breaking changes in auto-reload and thread-stats 2020-12-31 01:04:11 -06:00
492f1b6474 Changes default stylesheet from Yotsuba B to Dark Red 2020-12-31 00:07:25 -06:00
54e085fbdc Adds FARC flag and United Farm Workers flag 2020-12-30 23:55:19 -06:00
towards-a-new-leftypol
b7f30ed4d1 Merge pull request #67 from towards-a-new-leftypol/getchan_links
Getchan links in sidebar and at the top
2020-12-30 23:18:11 -05:00
Pietro Carrara
742390fb41 Enable flags on the JSON api 2020-12-30 20:08:47 -03:00
towards-a-new-leftypol
85e5fa2a04 Add foreign boards option to config
- this will append links to other websites at the end of the board list
- added getchan.net's /GET/ and /ref/
2020-12-30 03:39:19 -05:00
towards-a-new-leftypol
254ca6e2c1 Add sidebar section with links to GET and ref 2020-12-30 03:15:20 -05:00
towards-a-new-leftypol
7f6a152b03 retab inc/display.php 2020-12-30 03:15:03 -05:00
nonmakina
5dbf11ad88 Merge pull request #64 from towards-a-new-leftypol/flags
Flags
2020-12-29 21:48:54 -06:00
towards-a-new-leftypol
8db5a4f4da fix flag style 2020-12-29 20:43:23 -05:00
towards-a-new-leftypol
c28a59f6d8 Fix flag filenames 2020-12-29 20:32:42 -05:00
towards-a-new-leftypol
a4a1ec8f41 Retab post.php so that tabs are now 4 spaces.
- I will be doing this for any file I edit from here on in
2020-12-29 20:14:42 -05:00
towards-a-new-leftypol
eb34ba0d57 don't print START every time to the debug file (unless print_err is not commented out) 2020-12-29 20:12:43 -05:00
towards-a-new-leftypol
540ff0dc12 Remove debugging print statements I put in a long time ago from post.php 2020-12-29 20:10:49 -05:00
towards-a-new-leftypol
04933a3383 fix flag array (remove .png from filename) 2020-12-29 19:59:33 -05:00
towards-a-new-leftypol
70a8b3e516 Add flags 2020-12-29 19:55:38 -05:00
towards-a-new-leftypol
e17e080b25 flags don't need executable permissions 2020-12-29 19:50:02 -05:00
towards-a-new-leftypol
e67b8dd962 Merge pull request #58 from nonmakina/sidebarFix
Fixes the sidebar so that it doesn't use iframes.
2020-12-29 17:35:48 -05:00
nonmakina
361276b797 Merge pull request #56 from towards-a-new-leftypol/fixes
use mb_convert_encoding instead of iconv in slugify function in functions.php
2020-12-29 16:23:55 -06:00
nonmakina
433c9417c1 Merge pull request #59 from towards-a-new-leftypol/mobile_thread_enable_zoom
Allow mobile users to zoom in
2020-12-29 16:23:13 -06:00
nonmakina
525d50ff66 Adds JS support for multiple file upload (#61)
Co-authored-by: nonmakina <nonmakina@leftypol.org>
2020-12-29 17:18:21 -05:00
aedcbcfd83 Adds boardlist to homepage creation (top bar). Standardizes tabs or spaces in some files. Adds css rules for better mobile experience. 2020-12-29 02:44:47 -06:00
towards-a-new-leftypol
4f1b8e0bee Allow mobile users to zoom in 2020-12-29 02:00:55 -05:00
nonmakina
b7e71762b9 Merge pull request #1 from towards-a-new-leftypol/sidebarFix_fix
fix categories array in categories theme
2020-12-28 21:48:22 -06:00
towards-a-new-leftypol
8a9f862bcc fix categories array in categories theme 2020-12-28 22:44:51 -05:00
towards-a-new-leftypol
bc1c493620 This seems to work better with unicode values
- this seems to not break anything (that I know of)
- possibly a fix for issue 23, at least for most common cases (there
  are other iconv usages still in the code)
    https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/23
2020-12-28 20:48:57 -05:00
3ae4066f77 Fixes the sidebar so that it doesn't use iframes. 2020-12-28 14:23:00 -06:00
Barbara-Pitt
7eecea6739 Merge pull request #52 from Barbara-Pitt/config
Dockerize (#33)
2020-12-28 01:02:42 -06:00
Barbara Pitt
fa9b9186ac Merge remote-tracking branch 'upstream/config' into config 2020-12-27 17:24:16 -06:00
towards-a-new-leftypol
af25f25092 Allow MOD to edit rawhtml (#51)
Co-authored-by: towards-a-new-leftypol <paul_cockshott@protonmail.com>
2020-12-27 18:23:33 -05:00
Barbara Pitt
bb07d33611 adding docker items 2020-12-27 17:15:12 -06:00
Barbara-Pitt
9d398254f9 spoiler fix (#49)
Add spoiler and deleted image paths to instance_config
2020-12-27 18:06:07 -05:00
Barbara Pitt
b1996628ac fixing 'image deleted' 2020-12-27 17:01:37 -06:00
Barbara Pitt
9791aa8113 fixing spoiler 2020-12-27 16:59:07 -06:00
towards-a-new-leftypol
1cfe33a67f Merge pull request #48 from towards-a-new-leftypol/mod_perms
Fix issue 47 - allow users with MOD privileges to edit posts
2020-12-27 17:56:44 -05:00
towards-a-new-leftypol
72a8e82e32 Fix issue 47
https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/47
2020-12-27 17:50:31 -05:00
towards-a-new-leftypol
f466d47f42 Merge pull request #46 from towards-a-new-leftypol/myownbranch
Remove print statements, remove r9k mode, let users with MOD privilege move threads
2020-12-27 15:49:16 -05:00
towards-a-new-leftypol
cf02e82fc3 Fix issue 45 (mods should be able to move a thread)
https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/45
2020-12-27 15:43:50 -05:00
towards-a-new-leftypol
ca56ce0b57 Remove enforcing image uniqueness
- fixes issue 34:
    https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/34
2020-12-27 15:16:39 -05:00
towards-a-new-leftypol
e82012d6d6 Remove print statements
- comment out print_err function behavior (something I was using for
debugging before, but I'm keeping the function for future debugging)
2020-12-27 15:14:34 -05:00
towards-a-new-leftypol
35eb148b21 Merge pull request #44 from nonmakina/maxAttachments
Sets the maximum number of attachments per post from 1 (defualt) to 5
2020-12-27 15:01:38 -05:00
3f79f16c62 Sets the maximum number of attachments per post from 1 (defualt) to 5 2020-12-27 11:21:39 -06:00
Barbara Pitt
f86b715df6 undoing github actions 2020-12-27 03:59:16 -06:00
Barbara Pitt
d464850de1 undoing github actions 2020-12-27 03:58:02 -06:00
Barbara Pitt
6425580b00 undoing github actions 2020-12-27 03:57:23 -06:00
Barbara-Pitt
d54be24b37 Update php.yml 2020-12-27 03:49:45 -06:00
Barbara-Pitt
7e4da93330 Update php.yml 2020-12-27 03:46:50 -06:00
Barbara-Pitt
ea4adff8c9 Update php.yml 2020-12-27 03:40:57 -06:00
Barbara-Pitt
5fe6ddacb3 Update php.yml 2020-12-27 03:36:07 -06:00
Barbara-Pitt
0b02ca4424 Update php.yml 2020-12-27 03:33:14 -06:00
Barbara Pitt
dff2aaa9d0 git workflow updates 2020-12-27 03:13:52 -06:00
Barbara Pitt
ae0bd09d0e composer updates 2020-12-27 03:10:12 -06:00
Barbara Pitt
8b70517f3d github workflows update 2020-12-27 02:49:22 -06:00
Barbara Pitt
dcbd20ab3d github workflows update 2020-12-27 02:48:02 -06:00
Barbara Pitt
470223d84c Merge branch 'config' of https://github.com/Barbara-Pitt/leftypol_lainchan into config 2020-12-27 02:42:49 -06:00
Barbara Pitt
e4f0b54cd5 github workflows update 2020-12-27 02:42:30 -06:00
Barbara-Pitt
297628dffa Create php.yml
github workflow
2020-12-27 02:41:42 -06:00
Barbara-Pitt
9dbbdbe4b8 Merge pull request #43 from Barbara-Pitt/config
issue#17 - unit tests - adding test for banners.php
2020-12-27 02:33:21 -06:00
Barbara Pitt
aa1757da29 issue#17 - unit tests - adding test for banners.php 2020-12-26 20:34:23 -06:00
towards-a-new-leftypol
e3b3c469b7 Merge pull request #42 from Barbara-Pitt/config
issue#16 - adding dependency management
2020-12-26 18:56:08 -05:00
Barbara Pitt
a25cdddb2b untracking vendor (.gitginore) 2020-12-26 16:54:45 -06:00
Barbara Pitt
d9749ea66d untracking vendor 2020-12-26 16:54:03 -06:00
Barbara Pitt
1d2533442c issue#16 - adding dependency management 2020-12-26 16:43:41 -06:00
towards-a-new-leftypol
889d9c759d Merge pull request #41 from Barbara-Pitt/config
issue#35 - lookahead regex bug on quotes and crossboard quotes
2020-12-26 17:39:05 -05:00
Barbara Pitt
9ccfb6f33d issue#35 - lookahead regex bug on quotes and crossboard quotes 2020-12-26 16:23:59 -06:00
towards-a-new-leftypol
7e661c79dd Merge pull request #40 from Barbara-Pitt/config
issue # 39 - spoiler images not working
2020-12-26 17:08:30 -05:00
Barbara Pitt
a5d933bcc2 issue # 39 - spoiler images not working 2020-12-26 16:04:39 -06:00
towards-a-new-leftypol
51a8d62aca Merge pull request #32 from Barbara-Pitt/config
issue#26 - more themes
2020-12-26 16:53:32 -05:00
Barbara Pitt
3080fdd5b2 issue#26 - more themes 2020-12-26 03:47:17 -06:00
towards-a-new-leftypol
adb0c6067f Merge pull request #30 from Barbara-Pitt/config
issue#21 - fixing catalog stickies
2020-12-26 01:09:55 -05:00
Barbara Pitt
430c5e0766 issue#21 - fixing catalog stickies 2020-12-25 23:49:02 -06:00
towards-a-new-leftypol
c3e83ec0ee Merge pull request #29 from towards-a-new-leftypol/myownbranch
Myownbranch
2020-12-26 00:30:10 -05:00
towards-a-new-leftypol
bb7f9a29c9 Enable different filetypes 2020-12-25 21:04:43 -05:00
towards-a-new-leftypol
d09ae6e588 commit local changes renaming gulag to meta in the navbar 2020-12-25 20:38:25 -05:00
towards-a-new-leftypol
0f1d7f3894 Referer match false 2020-12-25 20:37:01 -05:00
towards-a-new-leftypol
64413e8bae Commit local change to instance-config.php (no functional changes) 2020-12-25 17:07:47 -05:00
towards-a-new-leftypol
cebf9f2876 Merge remote-tracking branch 'github/config' into config 2020-12-24 14:51:44 -05:00
towards-a-new-leftypol
3023317764 Merge pull request #28 from Barbara-Pitt/config
issue#5 - adding always noko in config
2020-12-24 14:41:45 -05:00
Barbara Pitt
735b2fe07b issue#5 - adding always noko in config 2020-12-24 13:04:24 -06:00
towards-a-new-leftypol
2f105e7d85 Merge pull request #14 from Barbara-Pitt/config
activated dark and dark red themes
2020-12-23 20:42:11 -05:00
Barbara Pitt
a682a756c9 undoing stylesheet change + moving theme changes to instance config 2020-12-23 18:39:05 -06:00
Barbara Pitt
709a47a88e adding basic mobile support 2020-12-23 18:23:06 -06:00
towards-a-new-leftypol
644460e079 commit local instance-config.php changes 2020-12-23 19:16:53 -05:00
towards-a-new-leftypol
1a24115485 commit stylesheet change 2020-12-23 19:14:27 -05:00
Barbara Pitt
9b11495e99 activated dark and dark red themes 2020-12-23 13:25:43 -06:00
towards_a_new_leftypol
3e9c52cec4 WIP 2020-12-22 01:35:54 -05:00
towards_a_new_leftypol
f75d42d9c4 WIP 2020-12-22 01:35:50 -05:00
towards_a_new_leftypol
195a3914d1 lots of print statements 2020-12-22 01:35:35 -05:00
towards_a_new_leftypol
4b61aaabbf retab 2020-12-22 01:35:24 -05:00
towards_a_new_leftypol
f7fcb010ce remove ffmpeg_path from cfg 2020-12-22 01:35:06 -05:00
towards_a_new_leftypol
1760f98a0c print statements and relax rules in config 2020-12-22 01:34:51 -05:00
towards_a_new_leftypol
6bb0d4bbee don't ignore instance-config 2020-12-22 01:34:36 -05:00
towards_a_new_leftypol
c9c4273d4b first commit of config file 2020-12-22 01:34:23 -05:00
towards_a_new_leftypol
3a2ff71f60 antinous fix one 2020-12-22 01:34:14 -05:00
towards_a_new_leftypol
e373746cc5 autoformat ffmpeg.php 2020-12-22 01:34:04 -05:00
towards_a_new_leftypol
cd9515397c Print statements everywhere 2020-12-22 01:33:07 -05:00
Appleman1234
05a0274f1f Merge pull request #174 from gamer551/master
#173 flood bump
2019-11-16 00:24:28 +10:00
gamer551
e6e00582f2 anti bump flood (#173) 2019-11-15 17:26:58 +04:00
gamer551
cc8b8bf369 anti bump flood (#173) 2019-11-15 17:25:09 +04:00
Benjamin Southall
049c325ef3 Added missing brackets for catalog lock handling 2019-09-19 05:50:48 +10:00
Benjamin Southall
c68af19e11 Fixes delete board regression thanks, as per 31e27a51c2 2019-08-31 01:51:56 +10:00
Benjamin Southall
2b741c7477 Rebuild themes after stickying or locking post, so that catalog gets rebuilt 2019-08-26 05:38:22 +10:00
Benjamin Southall
eefa9e3790 Fixes Where are ip notes displayed #168, typographical error. 2019-08-18 07:38:02 +10:00
Benjamin Southall
bbf201bc7b Merge branch 'master' of github.com:lainchan/lainchan 2019-08-17 23:55:30 +10:00
Benjamin Southall
a632d6a299 Fix cross board linking support for board aliases. Note this doesn't have overboard support yet 2019-08-17 23:55:02 +10:00
Appleman1234
9147862d7e Merge pull request #166 from sardach/patch-1
add missing '
2019-08-12 18:35:30 +10:00
Sardach
41915f120b add missing '
:P
2019-08-12 02:38:36 -05:00
Benjamin Southall
2d569c386f Change default configuration for vimeo embedding , Fixes Update Vimeo embedding #154 2019-08-11 10:22:09 +10:00
Benjamin Southall
917c05ae1a Add apple touch icon support and configuration option 2019-08-11 10:18:28 +10:00
Benjamin Southall
22cc429cf9 Fixes Video expanding doesn't work #164, this is probably because the logic always assumed settings menu would have body as parent and with a pagewrap div it doesn't anymore. This now works without options.js enabled 2019-08-11 09:35:11 +10:00
Benjamin Southall
44f99c5f0c Fixes You look like a bot (reCaptcha window doesn't appear) #159, straight implementation of upstream https://github.com/vichan-devel/vichan/pull/241, the template changes which the previous commit forgot 2019-08-10 20:54:52 +10:00
Benjamin Southall
7dba466f73 Fixes You look like a bot (reCaptcha window doesn't appear) #159, straight implementation of upstream https://github.com/vichan-devel/vichan/pull/241, but I bumped the jquery version. 2019-08-10 20:39:17 +10:00
Benjamin Southall
a5650df053 Based on #157 and #158, revert back to existence checks and length rather than default empty array initialization for ease of reading 2019-08-10 12:01:07 +10:00
Benjamin Southall
878b9aa420 Fixes count(): Parameter must be an array or an object that implements Countable #158 by replacing count with existence check for var,name and then using length 2019-08-10 12:00:06 +10:00
Benjamin Southall
82335ef2f5 Fixes Recent posts show nothing #157, because I forgot the length check. Reverts to use not because it is simpler than using default empty array and length 2019-08-10 11:58:12 +10:00
Benjamin Southall
d900279707 Fixes count(): Parameter must be an array or an object that implements Countable as well as PHP 7.3 regression in users from upstream 3a41c24e6e5bcea2f4b9f328ddf5ff0cb8a8b2e8 2019-08-08 21:20:48 +10:00
Benjamin Southall
3527e5703b Fixes Specified key was too long; max key length is 1000 bytes #156 and #93 by changing field lengths to less than 255 or 195 2019-08-08 21:13:17 +10:00
Benjamin Southall
bd73afc32a Committing optimized lain_bainer1.png which reduces its file silze by 89 kilobytes, while maintaining the integrity of the image. Inspired by PR #152 2019-06-02 16:48:26 +10:00
Benjamin Southall
a68d9bb120 Add support for gopher url:// markup as hyperlinks 2019-04-21 20:20:21 +10:00
Benjamin Southall
1e3a255b93 Update IRC theme to use newer KiwiIRC client in iframe 2019-04-06 03:52:48 +10:00
Benjamin Southall
59e8120375 As per vichan upstream move locked board check to after openBoard call in handle_post. Unlike upstream , the board being locked doesn't stop reports or deletions being processed for that board, just new posts 2019-03-22 04:08:02 +10:00
Benjamin Southall
b83106d832 Fixing #140 so semirand can be rebuilt. 2019-02-26 11:24:19 +10:00
Benjamin Southall
83ee85c7dc Add preliminary support for other types of databases (e.g PostgreSQL) in database wrapper, by changing hardcoded mysql settings to feature flag 2019-02-26 11:02:40 +10:00
Benjamin Southall
2bb2a6d3d7 Change capcode binding from int to string, needed for newer PHP support 2019-02-26 11:01:19 +10:00
Benjamin Southall
e62f8912fc Moving imagecreatefrombmp to polyfill 2019-02-26 10:59:18 +10:00
Benjamin Southall
242ad5fec5 Handle mcrypt_create_iv deprectation by using randombytes in newer PHP versions 2019-02-26 10:58:36 +10:00
Benjamin Southall
dece1287c4 Only set thread if we can get thread when warning, and fix theme uninstallation 2019-02-26 10:57:12 +10:00
Benjamin Southall
a3695ef2a8 Add imagecreatefrombmp and other relevant functions to polyfill.php because they have builtins in newer PHP 2019-02-26 10:54:45 +10:00
Benjamin Southall
5b89b6e27f Bump name and page size in SQL schema 2019-02-26 10:53:46 +10:00
Benjamin Southall
06f23a5988 Fix board legacy alias 2019-02-26 10:52:53 +10:00
Benjamin Southall
22b17a391f Disable snowstorm javascript autostart by default 2019-02-26 10:50:10 +10:00
Benjamin Southall
2f024d8b83 Initial post.php refactor into handler functions 2019-02-26 10:48:01 +10:00
Benjamin Southall
b52804fa65 Fix board parameter passing to search.php 2019-02-26 10:47:07 +10:00
Benjamin Southall
15234ed711 Remove pagewrap from page template. 2019-02-26 10:38:11 +10:00
Benjamin Southall
4b9061b21c Add support for overboards to RSS theme / extension. 2019-02-26 10:34:05 +10:00
Benjamin Southall
3bd497d6c4 Fixed typographical error in staff application form. 2019-02-26 10:32:43 +10:00
Benjamin Southall
151bbe7b53 Casting to make bans work with newer PHP, as per vichan 2019-02-26 10:28:15 +10:00
Benjamin Southall
75f419b948 Allow user to set the boardlist to point to catalog links instead of regular index page in Options. 2019-02-26 10:22:54 +10:00
Benjamin Southall
5e86f53b88 Loader for snow / snow storm javascript 2019-02-26 10:21:45 +10:00
Benjamin Southall
681292ef10 Switch 404 background image to local copy in static instead of external URL 2019-02-26 10:14:12 +10:00
Benjamin Southall
e6c07544da Twig update to latest Twig 1.x legacy as per vichan 2019-02-26 10:11:12 +10:00
Benjamin Southall
4ecd84f81d Merge branch 'master' of github.com:lainchan/lainchan 2019-02-26 06:47:26 +10:00
Benjamin Southall
6960140e66 Increase reason length when deleting reports 2019-02-26 06:46:36 +10:00
Michael Walker
85b6d63b8d Merge pull request #147 from AshtonHarding/master
We haven't updated the irc server. Let's do that.
2018-11-08 18:17:24 +00:00
Ashton Harding
389b826179 We haven't updated the irc server. Let's do that. 2018-11-08 12:06:11 -06:00
Benjamin Southall
cca756bf92 Add missing moderation templates 2018-04-20 06:48:31 +09:00
Appleman1234
402b001247 Merge pull request #134 from pat-90/master
Gurochan stylesheet update
2017-10-21 21:17:21 +09:00
pat-90
ad310fc721 Overhaul
Overhaul bringing making it more like gurochan
2017-10-21 22:07:54 +10:30
Benjamin Southall
a82a3698ad Add empty boards_alias to inc/config, should fix #133 2017-10-21 19:16:31 +09:00
pat-90
3af7b22a08 saaaaaaaaaa
aa
2017-10-04 10:58:06 +10:30
pat-90
f85e18f1ed Update gurochan.css 2017-10-04 09:03:08 +10:30
pat-90
c9745e7110 Merge pull request #1 from lainchan/master
Merge pull request #131 from pat-90/master
2017-10-04 08:28:43 +10:30
Appleman1234
a9a0b39360 Merge pull request #131 from pat-90/master
gurochan stylesheet
2017-10-02 08:26:06 +09:00
pat-90
438a47b9f2 div.banner a 2017-09-30 04:24:26 +09:30
pat-90
5645fd5f47 Update gurochan.css 2017-09-29 04:25:41 +09:30
pat-90
3c0dbdc615 gurochan.css
lainchan theme based on gurochan
2017-09-29 01:54:28 +09:30
Appleman1234
fcd982e9c8 Merge pull request #130 from sichan/master
Update post.php
2017-09-24 08:07:53 +09:00
Master Splinter
3501aab7a9 Update post.php
It was logged as 0.html when link_for is called with $post
2017-09-23 23:26:44 +03:00
Benjamin Southall
5f70dcd124 Fixed attachment of threadwatcher to topbar and move threadwatcher dialog from bottom of page where it was overlapped by bottom bar, to top of the page. 2017-09-14 08:25:37 +09:00
Benjamin Southall
b4a28e9fa9 Fixing deletion of events from calendar theme 2017-09-11 07:29:05 +09:00
Benjamin Southall
b0db28237b Updating default for DNS blacklists , replaces pull request 128 2017-09-04 07:09:48 +09:00
Benjamin Southall
d2429e05d1 Add warning without ban, joke capcode support, SC editor support, home link support, table for calender theme / extension, removing boardalias duplicate citations in markup and other features 2017-09-03 23:39:43 +09:00
Benjamin Southall
2fecc4a6a8 Add tinymce WYSIWIG post editor (experimental) 2017-09-03 23:18:46 +09:00
Benjamin Southall
8346795054 Add summernote WYSIWIG post editor (experimental) 2017-09-03 23:18:05 +09:00
Benjamin Southall
6fbc2a2a8b Add quill WYSIWIG post editor (experimental) 2017-09-03 23:17:37 +09:00
Benjamin Southall
02266e082e Add sceditor WYSIWIG post editor support 2017-09-03 23:15:56 +09:00
Benjamin Southall
0b3872dc93 Add greendark CSS style 2017-09-03 23:13:47 +09:00
Benjamin Southall
0bc5a876b4 Add megaq and update compact-boardlist and general boardlist / top bar alias support 2017-09-03 23:02:16 +09:00
Benjamin Southall
998386fe8a Add megaq and update compact-boardlist and general boardlist / top bar alias support 2017-09-03 23:02:05 +09:00
Benjamin Southall
a2a8b58612 Changes to local-time.js storage boolean checks 2017-09-03 23:00:37 +09:00
Benjamin Southall
5e78bae4ff Adjustments to main CSS, including stuff for new warning functionality and adjustment to Firefox top bar spacing 2017-09-03 22:56:46 +09:00
Benjamin Southall
af7f8fbcc2 Adjust Firefox top bar spacing 8ch cyber CSS style 2017-09-03 22:55:34 +09:00
Benjamin Southall
43d5359b37 Adjust Firefox top bar spacing mono.e.lain CSS style 2017-09-03 22:54:55 +09:00
Benjamin Southall
c9ffa4890c Remove background color from boardlist dark css style 2017-09-03 22:54:22 +09:00
Benjamin Southall
dee919b76c Remove borders for fauxx css style 2017-09-03 22:52:39 +09:00
Benjamin Southall
6182d7ac5e Add fonts and comment out borders for tsuki CSS style 2017-09-03 22:50:12 +09:00
Benjamin Southall
82f0e1f3ab Add style-select.js for moving CSS theme selections to Options for Public Ban list theme 2017-09-03 22:42:23 +09:00
Benjamin Southall
b949d0157d Updates to rules, and moving upload file limits to FAQ theme instead. 2017-09-03 22:35:51 +09:00
Benjamin Southall
b316476684 Add ukko4 theme to catalog theme 2017-09-03 22:34:58 +09:00
Benjamin Southall
b2ea634e15 Remove duplicate title from basic theme 2017-09-03 22:34:11 +09:00
Benjamin Southall
7859d7c951 Add new questions to FAQ theme 2017-09-03 22:33:18 +09:00
Benjamin Southall
e90b5dd470 Update nowplaying selector for radio theme 2017-09-03 22:31:01 +09:00
Benjamin Southall
e470eba5f9 Attempt to fix multibyte padding in stats tool 2017-09-03 22:23:55 +09:00
Benjamin Southall
b43d937c9c Add mobile default javascript 2017-09-03 22:20:30 +09:00
Benjamin Southall
22bbc4147e Add staff application theme, calendar theme and ukko4 theme 2017-09-03 22:19:32 +09:00
Appleman1234
f0d73f9952 Merge pull request #112 from michaldaniel/master
Added greybird.css to stylesheets
2017-06-25 06:04:52 +09:00
Michał Daniel
4a0c9a4d85 Makes that format-text inline important 2017-06-24 21:05:37 +02:00
Michał Daniel
41cc49a8c2 fieldset border style
Basic settings support?
2017-06-24 21:03:36 +02:00
Michał Daniel
20f26ecf90 Changes to form styling, don't break on resize
Added float left and clear both to textarea.
2017-06-24 21:01:26 +02:00
Michał Daniel
3e3b0b8c95 User 'lain' font for h1 and #bans title 2017-06-24 20:24:26 +02:00
Michał Daniel
bf04995748 New graybird.css style
Based on minimal_lain.css, fixes multiple issues with minimal_lain and introduces new stylings for all pages and elements.
2017-06-24 20:04:24 +02:00
Benjamin Southall
22b8dc6312 Partial merge of 736e982945 [SECURITY] Lessen security impact 2017-06-08 08:13:57 +09:00
Benjamin Southall
24bc0d2d2f local-time.js changes from 65f39b8a07 and c21eeff605 2017-06-08 08:12:18 +09:00
Benjamin Southall
d9b7252397 Merge pull request from vichan-devel/vichan#230 from antedeguemon/master Fixed XSS in post edit page and modsearch, this is a partial merge of just modsearch, we already fixed the edit post escaping earlier. 2017-06-08 08:11:18 +09:00
Benjamin Southall
490efdc062 Merge pull request from vichan-devel/vichan#220 from kekukin/patch-1 Fixed uninstall error for themes. 2017-06-08 08:09:10 +09:00
Benjamin Southall
103fd27032 Merge pull request from vichan-devel/vichan##202 from pngcrypt/master table fix nntpchan install.sql fix from 6049979daf 2017-06-08 08:06:39 +09:00
Benjamin Southall
967a969373 Merge pull request from vichan-devel/vichan#200 from seisatsu/patch-2 Fix typo in max_images comment , Adding early 404 staged from 40fe35fedc 2017-06-08 07:44:27 +09:00
Benjamin Southall
990816da11 Merge pull request from vichan-devel/vichan#205 from Montrosos/patch-1 Included header.html for better boardlist 2017-06-08 07:41:34 +09:00
Benjamin Southall
166914898a Merge pull request from vichan-devel/vichan#211 from tlm-2501/patch-1 Change Configuration Basics link to point to the archived tinyboard website 2017-06-08 07:39:08 +09:00
Appleman1234
05058773f1 Merge pull request #110 from joakimoa/master
v1.4 bugfixes, improvements and a refresh hotkey.
2017-06-08 06:33:46 +09:00
Joakim Almgren
41bb60c934 v1.4 better support for different stylesheets, better scrolling, refresh hotkey 2017-06-07 21:28:53 +02:00
Appleman1234
68f3916fed Merge pull request #109 from joakimoa/master
customisable keyboard navigation + bugfix in user-js.js
2017-06-07 07:13:40 +09:00
Joakim Almgren
cc559d0b1e v1.2 navigates posts and files, highlights with generic color 2017-06-06 23:42:25 +02:00
Joakim Almgren
27a1c19ddb commented out example function 2017-06-06 16:28:07 +02:00
Joakim Almgren
5fd29d8323 minor cleanup 2017-06-06 16:27:20 +02:00
Joakim Almgren
ce62a34b7a v1.1 added customizeable keybinds 2017-06-06 00:59:15 +02:00
Joakim Almgren
04c5e2371c keyboard navigation, jk, e 2017-06-05 21:37:52 +02:00
Benjamin Southall
2e5eb4fdec Update gitignore to exclude twemoji images and exclude fonts used in CSS stylesheets 2017-06-01 07:38:15 +09:00
Benjamin Southall
a4f37fdf2b Add missing post_control template and configuration values for thread merge functionality 2017-06-01 07:37:42 +09:00
Benjamin Southall
39be872353 Make compact-boardlist user toggleable from Options side menu 2017-06-01 07:36:30 +09:00
Benjamin Southall
18bcadfe90 Commit twemoji used for unicode fallback, note this is a modified version of https://github.com/twitter/twemoji that extends the v1 interface to work with Unicode 9.0 and Emoji 4.0 because the v1 interface allows for local image hosting instead of CDN and allowed image size variant specifier. The regex changes for Unicode 10 and Emoji 5.0 from upstream still need to be merged. The actual images are excluded from the lainchan repository, you can download the originals and resize them yourself from the url in this commit. 2017-06-01 07:35:22 +09:00
Benjamin Southall
8adae94906 Add support for client side configurable board list aliasing. 2017-06-01 07:20:30 +09:00
Benjamin Southall
23d079313c Add antibot to post form in attempt to ensure posting from overboards is not incorrectly flagged as spam by the tinyboard antispam engine 2017-06-01 07:18:19 +09:00
Benjamin Southall
4b4921cf53 Change formatting for Unique IPs summary information. 2017-06-01 07:16:54 +09:00
Benjamin Southall
16e35bc5b1 Add lainchan.jp to Rule 6. 2017-06-01 07:15:59 +09:00
Benjamin Southall
3e1f5738fb Adding glitch class to h1 to enable glitch CSS effect on test CSS theme 2017-06-01 07:15:01 +09:00
Benjamin Southall
6f7dc038f3 Fix typographical error in Recent extension / theme used on the front page 2017-06-01 07:06:34 +09:00
Benjamin Southall
9e57b5c30d Add merge thread functionality as a moderator feature (shadow threading and leaving OP is not yet supported) and board filter to Recent Posts iinterface. 2017-05-11 21:45:38 +09:00
Benjamin Southall
e6992804d1 Add mp3 placeholder image 2017-05-11 21:29:10 +09:00
Benjamin Southall
c9ece2d968 Add antibot to Element constructor in yukko themes, in the hope that posting from overboards as a normal user is not incorrectly blocked as spam / request looks automated. 2017-05-11 21:10:24 +09:00
Benjamin Southall
cefd46ec2a Adding glitch class to h1 for glitch effect when using test CSS theme 2017-05-11 21:05:20 +09:00
Benjamin Southall
4c604fdf7e Merge branch 'master' of https://github.com/lainchan/lainchan 2017-05-11 20:58:16 +09:00
Benjamin Southall
ca4aa67acb CSS changes, namely the options dialog themes for several CSS styles, thanks to crash_override, glitch art and improvement to test CSS theme, and the removal of various incorrect background colors for top and bottom bars. 2017-05-11 20:57:47 +09:00
Appleman1234
54d9d5b80f Merge pull request #106 from sometoby/autofocus-mod-login
Autofocus username field on mod login page
2017-05-11 13:38:24 +09:00
Tobias Umbach
e4bcd58c19 Autofocus username field on mod login page 2017-05-09 15:17:43 +02:00
Benjamin Southall
7043eec8ad Add new fields for pdf_file_thumbail and autotagging / IP note generation of deleted posts to config.php for Deleting posts as mod does not work #104 2017-05-05 05:49:14 +09:00
Benjamin Southall
1e294a5cd7 Add balloon image for heart.js and loadballon.js 2017-05-04 14:06:25 +09:00
Benjamin Southall
465c4f7562 Add videojs-contrib-hls.js for HLS streaming support. 2017-05-04 14:04:59 +09:00
Benjamin Southall
1d1b15e143 Add support for floating balloons used in the birthday celebrations 2017-05-04 14:04:22 +09:00
Benjamin Southall
cca271aec3 submodule sha nonsense update 2017-05-04 14:03:33 +09:00
Benjamin Southall
3344be60b4 On post submission manually update / reload the page for auto-reload.js. 2017-05-04 14:00:06 +09:00
Benjamin Southall
4cdf575515 use data-board value for form submission for board so that quick posting / replies works from ukko, ukko2, ukko3 and other overboad extensions / themes 2017-05-04 13:58:38 +09:00
Benjamin Southall
3980c34ea1 Fix thread-stats.js to attach to correct location and count correctly. 2017-05-04 13:56:19 +09:00
Benjamin Southall
07a158fd38 Remove additional unecessary logging 2017-05-04 13:50:24 +09:00
Benjamin Southall
7882227492 Change radio theme / extension to use bump in voice over link text 2017-05-04 13:49:47 +09:00
Benjamin Southall
eaced8531a Attempt to get dynamic data setup for stream based on format working 2017-05-04 13:48:09 +09:00
Benjamin Southall
d36a488245 Add 4th zine to Zine theme / extension 2017-05-04 13:46:59 +09:00
Benjamin Southall
9de786f327 Make fontsize for top bar smaller for cyberpunk / cyberia theme 2017-05-04 13:45:58 +09:00
Benjamin Southall
69fefaadc3 Updating lainchanjp CSS theme, downstream forks use this at your own risk 2017-05-04 13:42:44 +09:00
Benjamin Southall
62c0d8c6b6 Changes to recent.css in order to adapt to news being on the front page and still have float alignment for the other sections. Also changed font size to something smaller 2017-05-04 13:27:26 +09:00
Benjamin Southall
ac3ddd5101 Adding footer margin / padding so that canary is fully visible, and changing remove button so it is not grey on grey 2017-05-04 13:26:07 +09:00
Benjamin Southall
a90732eb95 Remove duplicate font declaration for Tsuki CSS style / theme 2017-05-04 13:23:17 +09:00
Benjamin Southall
7a4e74533f Add test.css e.g. test css theme and animate.css which it depends on 2017-05-04 13:20:50 +09:00
Benjamin Southall
bd9d2bd44f Merge branch 'master' of https://github.com/lainchan/lainchan 2017-05-04 10:20:16 +09:00
Appleman1234
455bc946fa Merge pull request #102 from KiTTYsh/master
Use random_bytes() to generate IV where available (PHP 7.x)
2017-05-04 10:20:11 +09:00
Kitty Cat
e780032e3e Use random_bytes() to generate IV where available (PHP 7.x) 2017-05-03 20:28:54 -04:00
Benjamin Southall
c3bbb9fe6d Removed dead symlinks. 2017-05-04 09:15:15 +09:00
Benjamin Southall
7e97946dc7 Merge branch 'master' of https://github.com/lainchan/lainchan 2017-04-30 13:12:47 +09:00
Benjamin Southall
359a50169a Adding support for format selection for Stream theme / extension, as well as the ability to change CSS theme from stream page 2017-04-30 13:12:05 +09:00
Benjamin Southall
b2d2edc404 Fix typographical error in closing paragraph tag in radio extension / theme 2017-04-30 13:09:29 +09:00
Appleman1234
86f65afd14 Merge pull request #96 from f0x52/master
minimal lain stylesheet
2017-04-29 09:02:39 +09:00
Appleman1234
e644020f06 Add changes by Difficile from IRC
Add changes by Difficile from IRC, ensuring top bar has matching background color to the rest of the page.
2017-04-29 09:01:27 +09:00
Appleman1234
d7afd900c4 Merge pull request #100 from horija/patch-1
sectoor.de is dead apparently
2017-04-29 03:45:29 +09:00
Hollick
54f8da322d sectoor.de is dead apparently
Well not saying this is the best fix or blacklist server. but it's the only I found that worked for me. I just read about some dnsbl so I'm no expert on it. 

Sectoor.de might go back to the living though.
2017-04-28 19:18:08 +02:00
Benjamin Southall
165938b30d Fix top bar on front page font-size as part of Recent theme / extension 2017-04-28 15:27:42 +09:00
Benjamin Southall
9d5e98a9a3 Implemented fix for Invalid link_for call referencing deleted thread when op is deleted #98 2017-04-28 15:08:02 +09:00
Benjamin Southall
040803bbc2 Fix auto-reload.js incorrect reply loading when the thread is just the opening post. 2017-04-28 14:11:21 +09:00
Benjamin Southall
bdaf941d34 Merge Fix thumbnail scaling in recent theme from vichan-devel/vichan#146 2017-04-28 01:37:01 +09:00
Benjamin Southall
18a208e873 Fixed go to bottom link from upstream vichan-devel/vichan commit 175b54b7f05129c130b0abec9f8db4af38495969 2017-04-28 01:23:45 +09:00
Benjamin Southall
9a5d521397 Add CSS theme selection dropdown and theme changing support to other pages provided by extensions/ themes. Radio theme is always cyberia themed however. 2017-04-28 01:16:56 +09:00
Benjamin Southall
cfd036c7aa Updates to radio theme / extension in order to support channel selection dropdown and the various other new radio features. Uses both twig variables and JavaScript in attempt to failback correctly when javascript isn't loaded. Adding support for the Options css theme selector from radio page. 2017-04-28 01:14:58 +09:00
Benjamin Southall
1f3effba04 Fix ukko scroll to post is too high / incorrect bug because of post_controls being display block on ukko threads. Add ordering by sticky to ukko2 and ukko3 forms for overboards 2017-04-28 01:12:38 +09:00
Benjamin Southall
f2b73e1dff Add page wrapper div in order to restrict page width and center content 2017-04-26 00:11:59 +09:00
Benjamin Southall
9ac3381891 Updating local radio m3u playlists though we currently link to externally hosted ones. 2017-04-25 22:55:22 +09:00
Benjamin Southall
f4af336760 Add support for Ukko2 and Ukko3 included boards overboards to Catalog theme / extension 2017-04-25 13:49:48 +09:00
Benjamin Southall
936c087637 Add aditional overboard themes that are similar to ukko but only include certain boards instead of excluding certain boards. In order for them to work ['overboards'] needs to be configured correctly. 2017-04-25 00:49:34 +09:00
Benjamin Southall
19c0f384a5 Add ['overboard_post_form'] to allow overboard post forms. Adjustments to ukko theme to support this 2017-04-25 00:47:14 +09:00
Benjamin Southall
aa8eb39dab Changes to add recent news to the Recent Posts Theme for the front page 2017-04-25 00:09:35 +09:00
Benjamin Southall
4139277cff Updates to Radio theme / extension in order to have MP3, OGG playlists and Audio sources as configurable. 2017-04-25 00:04:36 +09:00
Benjamin Southall
1e13d730b4 Updates to FAQ, based on recent events (server wipe) 2017-04-25 00:03:19 +09:00
Benjamin Southall
4c7e4881e4 Add bitcoin fields (Receiving address and QR code file location) to Donate theme / extension 2017-04-24 23:54:56 +09:00
Benjamin Southall
e69657065e Fix top and bottom bar on various CSS themes to have same backgroud color as page on both mobile and desktop. Change imgur links to local static links for Content Security Policy. 2017-04-23 21:14:08 +09:00
Benjamin Southall
b68e749876 Fix mod_view_board for ukko / overboard theme / extension. Add support for boards_alias to mod_view_board and initial preliminary support to markup for crossboard citations 2017-04-23 20:01:34 +09:00
Benjamin Southall
afd749415b Add data-board to post container in order to allow quick-post-controls.js to work with overboard's / ukko theme 2017-04-23 16:29:16 +09:00
Benjamin Southall
ac07ce6220 Update copyright year in page footer. 2017-04-19 23:27:58 +09:00
Benjamin Southall
ea418e2741 Merge branch 'master' of https://github.com/lainchan/lainchan 2017-04-19 07:11:33 +09:00
Benjamin Southall
ed162554db Add ['boards_alias'] in order to have Unicode icons in top bar that route to non unicode board names intelligently. 2017-04-19 07:09:02 +09:00
f0x52
045825e64b minimal lain stylesheet 2017-04-18 18:53:14 +02:00
Appleman1234
687024ab60 Merge pull request #95 from f0x52/master
issue #94, mod edit form
2017-04-18 05:49:46 +09:00
f0x52
77e8dfc02a escaping on all fields 2017-04-17 22:30:14 +02:00
f0x52
f69f306430 issue #94, mod edit form 2017-04-17 22:15:45 +02:00
Benjamin Southall
82e7228393 Invalid unique key in install.sql #93 Reduced board and name varchar length to 125 (1000/8 = 125) 2 columns , 4 bytes each column in pages table schema. 2017-04-17 03:15:59 +09:00
Benjamin Southall
e170624b22 Remove extra static epub thumbnail file with incorrect name. 2017-04-17 03:14:11 +09:00
Benjamin Southall
46ce8c7024 Fix typographical error in epub placeholder image 2017-04-14 23:43:01 +09:00
Benjamin Southall
e3302d0723 Implemented mods can't access random from dashboard #88. Please note this doesn't use mod custom_pages functionality provided by vichan (because the that only works if your overboard has name that doesn't look like other boards), and requires ['overboards'] to be set as an array of board uri's which are overboards, with the correct values for type (theme type e.g. ukko, rand or semirand) title, subtitle, thread_limit and exclude in array of for each board uri 2017-04-11 03:08:20 +09:00
Benjamin Southall
56dadd6c5b #90 Adding tsuki CSS 2017-04-11 00:43:49 +09:00
Appleman1234
6dd8258163 Merge pull request #91 from sometoby/catalog-lock-indicator
Show whether threads are locked on the catalog page
2017-04-09 03:11:45 +09:00
Flisk
dfe7e51d9c Show locked status of threads on catalog page 2017-04-08 15:17:30 +02:00
Benjamin Southall
c6686f1658 Adding images from Recent theme to static directory 2017-04-07 21:27:44 +09:00
Benjamin Southall
54279249a4 Add additional valid inputs for multi-url file upload for ['spam']['valid_inputs'] 2017-04-07 19:42:39 +09:00
Benjamin Southall
a247a3950b Make exception handler PHP5 / PHP7 agnostic. 2017-03-24 18:49:04 +09:00
Benjamin Southall
08f5412458 Add isempty check for POST variable for multi file upload via URL 2017-03-23 01:10:53 +09:00
Benjamin Southall
45954b5144 Add support for multiurl file upload fields to valid input whitelist for spam filter. 2017-03-20 21:04:39 +09:00
Benjamin Southall
47273d6887 Adding support for multiple file upload using URLs, previously only one URL was supported. Also removes duplicate slack reporting merge. 2017-03-20 20:19:03 +09:00
Benjamin Southall
5ee7954f95 Initial implementation of Better post form #32. Still need to add language specification to code tag insertion,markdown support and latex support. 2017-03-14 01:59:27 +09:00
Benjamin Southall
332cc15810 Deleting all posts by IP (D++) doesn't seem to work properly #87 Changing query inside the while loop to query2 in order to delete all posts, not just the first post. 2017-03-13 23:34:15 +09:00
Benjamin Southall
0cc6eb2f79 Feature Req: on/off button for auto-reload js #1 Fix insertafter selector so that new post gets autoloaded with the correct formatting and spacing. 2017-03-13 19:02:22 +09:00
Benjamin Southall
bc9e94d3d1 Feature Req: on/off button for auto-reload js #1 Fix incorrect insertAfter selector which prevented page from being updated when auto-reloaded and caused new post count to climb incorrectly in title of page 2017-03-11 17:52:39 +09:00
Benjamin Southall
baacee3fd3 Initial Implementation of Feature Req: on/off button for auto-reload js #1, configurable in localstorage using options menu 2017-03-10 15:37:36 +09:00
Benjamin Southall
3ef22877cc Initial implementation of Thread stats for mods #33, Implemented using Twig without persistent storage, and display at end of thread. 2017-03-10 11:34:46 +09:00
Benjamin Southall
3f236c3f25 Thumbnails for PDFs / other things #6 When locale fails to be loaded fallback on C.UTF-8 instead of C, so that boards with unicode characters in the name are not stripped by escape_shell_args 2017-03-09 13:58:41 +09:00
Benjamin Southall
d4e460c5e9 Initial implementation of Feature Req: board-independent file size management #4. Using ['board_specific'][['uri']]['max_filesize'] as maximum file size if avaliable otherwise using config['max_filesize'] as default 2017-03-05 02:18:28 +09:00
Benjamin Southall
44e8b9615c Initial implementation for Thumbnails for PDFs / other things #6, requires ['pdf_file_thumbnail'] is set to true and using convert from imagemagick. If ['pdf_file_thumbnail'] is false then it uses standard configured static file icon 2017-03-05 01:41:52 +09:00
Benjamin Southall
d76a981dfb Implements pull request #86 without the padding because margin-top is already set by media-query for screens <= 600px 2017-03-03 17:04:04 +09:00
Benjamin Southall
ef22020403 Display post moderation fields by default 2017-03-03 16:01:17 +09:00
Benjamin Southall
db64e74f7d Force file link from file information to always open in a new tab. 2017-03-03 15:54:21 +09:00
Benjamin Southall
eafb464a77 Center the image of Lain in Basic Theme 2017-03-03 15:52:11 +09:00
Benjamin Southall
65d96528d7 Update stream theme, link to newer video.js, add defined checks for stream now playing feeds and add meta viewport for CSS on mobile devices 2017-03-03 15:48:53 +09:00
Benjamin Southall
4b83baa6cc Updated FAQ Theme contents 2017-03-03 15:45:35 +09:00
Benjamin Southall
7d0c867544 Adding snow / snow storm javascript 2017-03-03 15:44:16 +09:00
Benjamin Southall
b8dec91885 Add fireworks javascript and CSS 2017-03-03 15:39:28 +09:00
Benjamin Southall
93e3b76b97 Change code hightlighting to highlight.js from google-code prettify.js 2017-03-03 15:34:45 +09:00
Benjamin Southall
d23355ce48 Add additonal brackets to min_body post length check in order to ensure operation precedence 2017-03-03 15:25:30 +09:00
Benjamin Southall
590178e77d Add meta viewport tag to various themes / extensions for CSS on mobile devices to make use of 2017-03-03 15:20:07 +09:00
Benjamin Southall
eb968a7d01 Update included version of prettify.js, despite the fact we use highlight.js for code highlighting now 2017-03-03 15:09:52 +09:00
Benjamin Southall
fc3956a7fc Change post hover behaviour to show actual post, rather than last post in thread. 2017-03-03 15:07:27 +09:00
Benjamin Southall
1164bf56ef Add overboard support to image-hover functionality. 2017-03-03 15:04:23 +09:00
Benjamin Southall
a75427254a Add support to pm_snippet to maintaining spolier tags, so that spoilers are not revealed by Recent Theme on frontpage 2017-03-03 14:58:35 +09:00
Benjamin Southall
7245722254 Add mininum post length configuration value to combat spam. Note that the posts with 0 length are still allowed in order to allow image only posts for /layer/. Fix paths for spoiler and deleted images. Change flood filters so that moderators are not restricted by them. 2017-03-03 12:26:00 +09:00
Benjamin Southall
e01a6d19f3 Add JSON interface to Recents Posts functionality, e.g. mod_recent_posts 2017-03-02 11:40:27 +09:00
Benjamin Southall
35c0152f6d #87 Attempt to change the error message associated when using deletebyip e.g D++ with autotagging of deletions enabled. 2017-03-02 11:36:29 +09:00
Benjamin Southall
e93e954bad Fix relative path to temporary directory for Tesseract OCR 2017-03-02 11:26:51 +09:00
Benjamin Southall
cb6a6eb5e3 When reporting posts return to the reported post, instead of generating a new page 2017-03-02 11:25:45 +09:00
Benjamin Southall
735e12b414 Don't remove post selection checkbox for reporting when hiding threads 2017-03-02 11:20:04 +09:00
Benjamin Southall
c59a5edb49 Don't remove mentioned post links from post-hover popups. 2017-03-02 11:18:14 +09:00
Benjamin Southall
cd56fec0e8 Added check for post time being empty string, in order to handle the case that occurs when a deleted post is deleted a second time. 2017-01-18 12:13:11 +09:00
Benjamin Southall
8135c800e4 Add autotagging feature for deletion. E.g. automatically generate an IP note when a post is deleted by moderator action. 2017-01-17 22:56:46 +09:00
Benjamin Southall
c777b88521 Add min_body configuration option for post too short check 2017-01-17 22:55:46 +09:00
Benjamin Southall
ecc28576ae Orient images using EXIF in Firefox and increase margin between top bar and content 2017-01-17 22:55:02 +09:00
Benjamin Southall
358769deb5 Update URL for EXIF information for Image Identification menu 2017-01-17 22:53:56 +09:00
Benjamin Southall
b121ccbe7f Merge branch 'master' of https://github.com/lainchan/lainchan 2017-01-17 22:52:55 +09:00
Benjamin Southall
b2d8e2df22 Remove outdated bitcoin address from the README 2017-01-17 22:52:15 +09:00
Appleman1234
32aa3e3d8f Merge pull request #85 from rlt3/fix_catalog_sorting
Fixed catalog.html option values so mixItUp will sort threads
2017-01-13 12:52:02 +09:00
rlt3
b70ef95b39 Fixed option values on catalog.html so mixItUp will actually sort threads. 2017-01-12 13:37:43 -05:00
Benjamin Southall
307af0246b Added FAQ theme 2016-12-19 08:47:30 +09:00
Benjamin Southall
f91739389f Merge branch 'master' of https://github.com/lainchan/lainchan 2016-12-16 05:27:46 +09:00
Benjamin Southall
a1b0ffdfdc Added support for anonymous name generator to be a function in addition to being an array of names 2016-12-16 05:25:26 +09:00
Appleman1234
f32153b99e Merge pull request #81 from lainchan/clean_prod_vichan_update
Adding catalog.json and threads.json support to ukko theme for mega.
2016-12-16 02:28:54 +09:00
Benjamin Southall
ccfa70ad78 Add support for catalog.json and threads.json to ukko theme. 2016-12-16 02:23:21 +09:00
Benjamin Southall
7e40653e26 Added CSS stylesheet for delete theme, after the checkbox for post selection had been made visible again 2016-12-16 02:22:19 +09:00
Appleman1234
f5ea58426d Merge pull request #79 from lainchan/clean_prod_vichan_update
Merge vichan changes from upstream and changes directly applied to the site.
2016-12-15 18:25:42 +09:00
Benjamin Southall
da450d7088 Changes to report notification callback to Slack HTTP endpoint 2016-12-14 06:11:54 +09:00
Benjamin Southall
4503de147b Remove linking to OP as part of post hover. 2016-12-14 06:06:05 +09:00
Benjamin Southall
49311e5e4a Add support for ignoring URLs when using word filters 2016-12-14 05:47:08 +09:00
Benjamin Southall
00e429a22f Changing wording of post filtering when action is not set from throttled to blocked at user request. 2016-12-14 05:42:12 +09:00
Benjamin Southall
14bb931567 Remove superflous extra error handling from merge of upstream vichan 2016-12-13 03:13:16 +09:00
Benjamin Southall
7e406d2280 Changes to css for homepage slogan changes. 2016-12-13 02:58:55 +09:00
Benjamin Southall
b2df573207 Removing duplicate page numbers and Catalog link from index page template 2016-12-13 01:09:25 +09:00
Benjamin Southall
025bb70a58 Dashboard simplification 2016-12-11 08:14:23 +09:00
Benjamin Southall
2172abf9dd Fix copyright on page templates 2016-12-11 08:04:18 +09:00
Benjamin Southall
10cae1981c Updated maximum file size on rules page 2016-12-10 18:40:11 +09:00
Benjamin Southall
809455d05d Fix board filter listing in the search form 2016-12-10 18:39:18 +09:00
Benjamin Southall
197cd5028c Adding board name to title of catalog theme 2016-12-10 18:33:52 +09:00
Benjamin Southall
8c620bb55d Add cssleft configuration parameter to donate theme 2016-12-10 18:32:18 +09:00
Benjamin Southall
006821f5d4 Migrated irc theme from webchat to kiwiirc and adding additional configuration options to the theme. 2016-12-10 18:24:58 +09:00
Benjamin Southall
72a207b4c0 Changed message and CSS on the recent page / e.g. the recent theme. Cyberpunk is DUCK. 2016-12-10 18:23:18 +09:00
Benjamin Southall
b85104821e Adding separate videojs RTMP URL configuration variable to stream theme 2016-12-10 18:18:27 +09:00
Benjamin Southall
cf0587d9f0 Add JSON API to Ukko Overboard Theme 2016-12-10 18:15:11 +09:00
Benjamin Southall
a1a83f50ba Add stream theme / extension to Lainchan 2016-10-08 15:29:06 +09:00
Benjamin Southall
f469416073 Remove debugging from RSS extension 2016-10-08 01:47:53 +09:00
Benjamin Southall
bb34304614 Add enable per board feature and only include new threads feature for RSS theme / extension 2016-10-08 00:48:55 +09:00
Benjamin Southall
e5aa42860d Add other donation fields to donate theme / extension 2016-10-08 00:47:55 +09:00
Benjamin Southall
03075e7a8c Make slack report notifier, donate page, irc page and radio page use configuration variables instead of hard coding values. 2016-10-02 01:15:34 +09:00
Benjamin Southall
c58e37ce39 Merged lainchan with vichan master at 25/9/2016 0bd63149b7 @czaks czaks committed on GitHub 2 days ago 2016-09-25 16:34:47 +09:00
Marcin Łabanowski
0bd63149b7 Merge pull request #198 from seisatsu/patch-1
Rebuild index when mod deletes a thread.
2016-09-23 09:24:05 +02:00
Michael D. Reiley
ec5dc28d55 Rebuild index when mod deletes a thread.
The index does not properly rebuild when a mod deletes a thread, resulting in a ghost thread remaining in the index until the next rebuild. This fix was originally contributed to Uboachan's codebase by Mannosuke.
2016-09-22 23:03:11 -07:00
czaks
e09105cc79 Merge branch 'master' of github.com:vichan-devel/Tinyboard 2016-08-19 23:15:47 +02:00
czaks
a5e7b3da6f nntpchan: work around php nonsense 2016-08-19 23:15:42 +02:00
Marcin Łabanowski
9dedb7829d Merge pull request #196 from majestrate/master
patch for nntpchan stream
2016-08-19 22:08:33 +02:00
Jeff Becker
57be2cdf41 patch for nntpchan stream 2016-08-19 16:05:50 -04:00
czaks
0b19051891 fix a notice; increase waiting time for dns 2016-08-15 04:13:26 +02:00
czaks
a779b96370 second iteration of nntpchan implementation 2016-08-15 00:56:06 +02:00
czaks
1c24c69999 Merge branch 'master' of github.com:vichan-devel/Tinyboard 2016-08-14 16:24:25 +02:00
czaks
5e335a8564 preliminary inbound nntpchan support 2016-08-14 16:24:17 +02:00
Marcin Łabanowski
a209216656 Merge pull request #195 from ptchan-foss/master
Fixed report syslog message
2016-08-12 19:21:35 +02:00
ptchan-foss
8548a4ff70 Fixed report syslog message 2016-08-12 18:18:54 +01:00
Marcin Łabanowski
7bec8a0a85 Merge pull request #191 from nekomiko482/patch-1
BSD md5 output format compatibility fix
2016-07-08 05:45:18 +02:00
nekomiko482
a55760299c Fixes incompatibility with BSD's md5 output format.
fixes #190
2016-07-07 12:53:40 +03:00
czaks
11cecf8452 Revert "[BUG] Image reject repost board option now also affects YT embeds"
This reverts commit b476b66007.
2016-06-21 05:03:44 +02:00
czaks
8f4aa27329 fix file-selector.js dependencies 2016-06-19 02:40:24 +02:00
czaks
fed9065cf1 skip non-image files in recent themes; fixes vichan-devel/vichan#185 2016-06-19 02:23:24 +02:00
czaks
356f46237c fix install.sql after a bad merge 2016-06-19 02:15:49 +02:00
czaks
e230f1472c don`t ocr non-images 2016-06-10 12:41:53 +02:00
fatchan
c9ef21bff9 Better solution to prevent ID wrapping. Also no longer text-selectable. Much cleaner. 2016-06-09 11:23:32 +02:00
Duane Moody
f23d11be60 Prevent poster IDs from wordwrapping
Poster IDs still linebreak between "ID:" and the ID, this corrects that without having to replace the space inbetween with an &nbsp; nonbreaking space.
2016-06-09 11:23:08 +02:00
fatchan
4f3cc7f316 Whoops 2016-06-09 11:22:57 +02:00
fatchan
f27c26907d Remove hardcoded 8chan links in catalog RSS 2016-06-09 11:22:47 +02:00
fatchan
aa0d92a2b4 Force post-hover.js to show OP's on hover. 2016-06-09 11:20:39 +02:00
fatchan
04f42b3802 CSS hover instead of javascript mouseover. Need to use important because the dark/light text determined by IDToRGB is added inline and takes priority over stylesheets. 2016-06-09 11:20:23 +02:00
fatchan
cdd963e79e fix flag spacing 2016-06-09 11:18:34 +02:00
czaks
d2bb4a776f fail gracefully on no thumbnail 2016-06-09 11:15:45 +02:00
czaks
8a46c7a0d5 tesseract OCR support for spamfilters 2016-06-09 11:09:10 +02:00
czaks
36d762514c Merge branch 'master' of github.com:vichan-devel/Tinyboard 2016-06-09 04:51:17 +02:00
czaks
94c91db097 fix news deletion; thanks MrFreeman 2016-06-09 04:51:05 +02:00
Marcin Łabanowski
6a7be4a058 Merge pull request #182 from fatchan/master
Move the 'Go back and rebuild again' to the top of the rebuilt page s…
2016-05-31 16:08:50 +02:00
fatchan
d285a79667 Move the 'Go back and rebuild again' to the top of the rebuilt page so you dont have to scroll 2016-05-31 23:28:55 +10:00
czaks
52fe9bc873 fix sane_strategy for advanced build. should fix the ajax.js problem. 2016-05-15 15:53:30 +02:00
czaks
4fe2da2fcd post-filter & ukko: final solution i think 2016-05-09 13:02:21 +02:00
czaks
018dd48a66 post-filter + ukko fixes 2016-05-09 11:58:46 +02:00
czaks
4479fc7681 thread-watcher and favorites in catalog and ukko 2016-05-09 11:18:35 +02:00
czaks
1cff10fd95 ukko & fix-re-de-su: fix reporting and deleting from ukko actually 2016-05-09 11:08:24 +02:00
czaks
ccc9cff23d ukko: post filters and reporting 2016-05-09 10:59:50 +02:00
czaks
bb9aaad899 i forgot about a queue and a lock implementation 2016-05-08 15:37:49 +02:00
czaks
f24e0f9814 optimize out openboard when we don`t need it. a big performance improvement too 🏎
also, don't call dnsbl for local ip addresses
2016-05-08 14:02:17 +02:00
czaks
12e6aba5d4 (2/2) advanced build. implement a daemon that will build static pages.
implement a queue and a lock. fix notice in bans. and it even works!

the daemon is basic right now, it could work in a mode that it will defer building certain
pages until a certain time.
2016-05-08 13:23:41 +02:00
czaks
e265375475 fixup 2016-05-08 10:59:36 +02:00
czaks
b6f0317bde advanced build (1/2): a small refactor of index generating procedure; generation strategies 2016-05-08 10:54:30 +02:00
czaks
644f227ab3 fix "Undefined variable: pid"; thanks fpdl and MrFreeman 2016-05-08 03:09:20 +02:00
czaks
a5e22f6d63 split route and controller parts from smart build 2016-05-08 02:50:44 +02:00
czaks
deef54fe13 introduce smart_build_helper 2016-05-07 02:16:54 +02:00
czaks
ce9f9eec25 settings dialog refinements: now you can resize it 2016-05-06 17:11:12 +02:00
czaks
3f405b3484 what if IP address contained bad characters? (highly local) 2016-05-06 16:53:28 +02:00
czaks
3571670b98 fix catalog link someone? 2016-05-06 16:51:34 +02:00
czaks
a5bd39dc4a mod dashboard html: link to page editor 2016-05-06 16:49:35 +02:00
Fredrick Brennan
505adffcdc Cyclical threads ♺ 2016-05-06 16:39:20 +02:00
czaks
ab02a42725 maybe we can try to load Parsedown, after all we can silence the error 2016-05-06 16:27:43 +02:00
8chan
d788131202 Allow a board called news to exist 2016-05-06 16:26:17 +02:00
czaks
91c02c3ec4 board pages: add a migration 2016-05-06 16:21:43 +02:00
czaks
d726eaf195 we don't have a htmlpurifier yet ;_; 2016-05-06 16:07:21 +02:00
Fredrick Brennan
95b1e103cb Edit static pages commit 2016-05-06 16:03:55 +02:00
8chan
7911c374e8 Public action logs commit (log.php)
Note: In a previous commit, I began making inc/mod/auth.php more modular with the check_login() function. Including it does NOT check mod login by default anymore like it does on vichan. You have to call check_login(). I've finally included it in inc/functions.php. If you have any custom pages that use inc/mod/auth.php, just including functions.php is enough now.

===================================
Also: backports 351375185e5 (early 404)
2016-05-06 15:44:26 +02:00
8chan
6dd1420f91 Add event to quote backlinks 2016-05-06 15:15:17 +02:00
8chan
ce3ce4f1b6 Fix *0 secure tripcodes caused by accidentally feeding + signs to crypt() 2016-05-06 15:14:55 +02:00
8chan
7831da83fc New event: rebuildpost, allows you to bind events to ?/edit 2016-05-06 15:13:27 +02:00
Fredrick Brennan
b476b66007 [BUG] Image reject repost board option now also affects YT embeds 2016-05-06 15:12:08 +02:00
czaks
2fa37278db boardlist goes before #top 2016-05-06 15:09:25 +02:00
czaks
6e33de568d hide-threads.js: add div.file to fields to hide; thanks fpdl 2016-05-06 15:03:53 +02:00
czaks
8496b021a9 comment out global reports 2016-05-06 14:57:07 +02:00
Fredrick Brennan
65ea7b78c5 Catalog: click to scroll thread 2016-05-06 14:53:17 +02:00
sourcerect
3515fdabe7 Fix tab freeze when inlining
Fixes ctrlcctrlv/infinity#451
2016-05-06 14:49:30 +02:00
czaks
aa98ca337e i think this lump of code deserves a version bump; v5.1.0 here 2016-05-06 14:36:14 +02:00
czaks
126ee42b9d better rules for stripping combined chars, based on 45c0d327619 by @ctrlcctrlv 2016-05-06 14:34:42 +02:00
Forkless
d069a4c9fd Added option for hiding IDs. 2016-05-06 14:32:53 +02:00
czaks
33ef3f9b01 synchronize catalog_link 2016-05-06 14:14:22 +02:00
Bui
33ef1d2123 add active page classes to body; czaks: go to bottom @ thread: fixes 2016-05-06 14:05:16 +02:00
8n-tech
6644ff666a Also improved some CSS and HTML aspects of the thread layout.
Signed-off-by: 8n-tech <8n-tech@users.noreply.github.com>
2016-05-06 13:51:15 +02:00
8chan
7a7574bdca SECURITY / XSS : ?/edit allowed arbitrary HTML to be added by any user thru addition of <tinyboard raw html>1</tinyboard>
This allowed ANY user with ?/edit privilege to also have raw_html regardless of whether they had $config['mod']['rawhtml']

Now, any changes to <tinyboard> markup modifiers via ?/edit are not allowed. They are removed at read time, and before write they are removed again and the ones in the database (which should be clean...) are inserted instead.

Please immediately apply this patch to your instance if you are running any version of 8chan/infinity.
2016-05-06 12:43:25 +02:00
8chan
6da7f4d25a No more country flags in <title> 2016-05-06 12:40:37 +02:00
8chan
ae4eb4d3d9 RSS 2016-05-06 12:40:07 +02:00
8chan
632d0a76d0 Display placeholder if no file in catalog/theme.php; czaks: fix the code a bit 2016-05-06 12:37:00 +02:00
anonfagola
cb97029d0d Update catalog.html
Changed title from being - "Catalog /board/" to "/board/ - Catalog"
2016-05-06 12:27:21 +02:00
czaks
3f29170f1b debrand 8chan; btw. the previous commit was [SECURITY] i think? 2016-05-06 12:23:18 +02:00
8chan
ce62673a2c OpenGraph information in thread pages https://en.wikipedia.org/wiki/Facebook_Platform#Open_Graph_protocol 2016-05-06 12:18:31 +02:00
8chan
aa0d3395b1 Show first 256 chars of body in <title> 2016-05-06 12:17:51 +02:00
8chan
b6f3d44080 Go to bottom link 2016-05-06 12:16:01 +02:00
czaks
293543878a backport parts of 2d6d449bd2d72, in particular html classes 2016-05-06 12:14:28 +02:00
Bui
6c334a3b44 lol spaces 2016-05-06 11:45:52 +02:00
Bui
d46bf4e2f2 add id to thread links 2016-05-06 11:45:37 +02:00
czaks
02c3c28a16 main.js: a bit more sane code 2016-05-05 15:37:50 +02:00
czaks
6991ca270e fix bad merge 2016-05-05 13:53:52 +02:00
8chan
129eb154b3 Merge 2016-05-05 13:45:36 +02:00
Zixaphir
633c223282 Fix trailing comma 2016-05-05 13:43:32 +02:00
Zixaphir
cad8019068 Prevent images from hovering off-page
This entirely affects the "imageHoverFollowCursor" option.
2016-05-05 13:43:17 +02:00
Pashe
5f043d0a29 Have image-hover.js use data-fullimage instead of the API 2016-05-05 13:43:04 +02:00
8chan
913420e040 Image hover backported from 8chan X 2016-05-05 13:42:54 +02:00
czaks
130b32d08b remove image hover, so we can import the whole 8chan history of that file 2016-05-05 13:42:38 +02:00
Fredrick Brennan
2712235f15 Make js/options/favs.js actually usable
I pretty much had to rework this completely to get it into a usable state

Reference ctrlcctrlv/infinity#424
2016-05-05 13:36:26 +02:00
Harry Hackett
6cb3039b71 Create fav.js 2016-05-05 13:35:02 +02:00
Fredrick Brennan
71fde35938 Oops forgot a file 2016-05-05 13:33:14 +02:00
Mark Taiwan
c2e3ff162f Added missing curly brackets in post-filter.js 2016-05-05 13:22:59 +02:00
8chan
7cf3fccda5 Fix menu brokenness if user post deletion disabled 2016-05-05 13:22:36 +02:00
8n-tech
e64b01b690 Javascript ammendments, dio_ on Windows.
Signed-off-by: 8n-tech <8n-tech@users.noreply.github.com>
2016-05-05 13:22:11 +02:00
8chan
6b04b3c671 Fix post deletion 2016-05-05 13:21:09 +02:00
8chan
5f10badee9 Make no-animated-gif.js trigger on new_post 2016-05-05 13:12:10 +02:00
8chan
8412299fa5 Fix hide-threads.js interaction in no-animated-gif.js 2016-05-05 13:11:54 +02:00
Ringstaart
4e635229b4 Replace capital X by clearly superior ASCII ×
There's no reason to use a malformed letter when an ASCII character of a proper cross is available. This is an important issue, and I care about it very much.
2016-05-05 13:08:30 +02:00
8chan
f02226449a Fix own post (You) 2016-05-05 13:06:25 +02:00
Fredrick Brennan
cac428b30c Add some missing i18n tags 2016-05-05 13:03:31 +02:00
8chan
5267098cb8 Make bottom watchlist-toggle work 2016-05-05 13:01:24 +02:00
8chan
fd2e9df30c This script was breaking boards.html 2016-05-05 13:01:00 +02:00
Pashe
01446aad12 thread-watcher.js: fix background and border 2016-05-05 13:00:47 +02:00
Pashe
6f301505e3 thread-watcher.js: change display format 2016-05-05 13:00:33 +02:00
7185
0b1c67574a Fix selector in inline.js
Should make >>>/crossboard/links (and expanding links) work again
2016-05-05 12:59:25 +02:00
Fredrick Brennan
8943bb0bb3 Rewrite report system due to flooding 2016-05-05 12:57:52 +02:00
8chan
95a9b7b72b Completely rewrite fix-report-delete-submit.js, add report/delete to menu 2016-05-05 12:52:17 +02:00
Forkless
4e39262223 Moved the Options tab stuff to be setup after the document is ready. 2016-05-05 12:45:25 +02:00
Forkless
81daf934fb Fix for the js being shitty inside the compiled main.js. 2016-05-05 12:45:07 +02:00
Forkless
f6b4b2ac18 Removed redundant setting.
Bugfix.
2016-05-05 12:44:48 +02:00
Forkless
1663efcf9d Fix for update to comment toolbar (should work now) 2016-05-05 12:43:57 +02:00
Fredrick Brennan
1b0f5fd24c Revert "Comment toolbar update and Thread stats addition" 2016-05-05 12:42:41 +02:00
ForklessAnon
69a6631742 Added option to disable/ignore keybinds. 2016-05-05 12:36:28 +02:00
ForklessAnon
86ddb4ecbb Update formatting toolbar to include user definable settings and customized options. 2016-05-05 12:35:58 +02:00
Markerov
9265ebea43 initial commit 2016-05-05 12:35:45 +02:00
marktaiwan
59ee8a990f post-filter.js: prevent extra space characters
prevent extra spaces in comment caused by joining strings with leading
or trailing space.
2016-05-05 12:33:44 +02:00
8chan
4e27112147 Fix filter for users with emoji in thier names 2016-05-05 12:33:23 +02:00
marktaiwan
a9b29c7232 Bugfix: convert it to string 2016-05-05 12:33:02 +02:00
marktaiwan
513c8f7b68 post-filter.js catalog support
Removes hidden threads from catalog page
Shift click on catalog to hide thread
Improved word matching for simple comment and subject filter.
2016-05-05 12:32:27 +02:00
marktaiwan
dc725641c3 minor options template adjustment 2016-05-05 12:32:00 +02:00
marktaiwan
8f6ea6dd94 post-filter.js restructure
- Changed how filters are stored. Have included code to migrate from
previous version
- Added support for 'subject' and 'comment' in the options panel
- Added regex support in the options panel
2016-05-05 12:31:11 +02:00
marktaiwan
f84d0b9027 Changed 'hide post' button behavior 2016-05-05 12:30:54 +02:00
8chan
b469855126 use onready in post-menu.js 2016-05-05 12:30:18 +02:00
marktaiwan
af91ddf637 Split post menu into own function 2016-05-05 12:29:11 +02:00
8chan
e3dbca5616 Add one click [-]/[+] to post-filter.js 2016-05-05 12:28:52 +02:00
marktaiwan
84bc3b0f7b I forgot how to jQuery 2016-05-05 12:16:55 +02:00
marktaiwan
3e579ee1d4 Bugfix: reset multifile container width
#371
2016-05-05 12:16:17 +02:00
marktaiwan
deefe7225d Bugfix: scroll to thumbnail on multipost close
Indroduced in 7364e85
2016-05-05 12:15:51 +02:00
8chan
5176377045 Fix many features for Internet Explorer 9 and 10
Please don't use "dataset" in scripts anymore, it doesn't work in IE9 or 10. Instead use $.data
2016-05-05 12:15:26 +02:00
marktaiwan
88f6088a42 fix Relative Time and Image Throttler 2016-05-05 12:14:22 +02:00
Markerov
7160cd650e merge relative-time into local-time 2016-05-05 12:12:53 +02:00
Markerov
c3146e1794 image throttler
initial commit
2016-05-05 12:11:12 +02:00
topkek
63491b0b9a Scroll to thumbnail when shrinking an expanded image 2016-05-05 12:10:09 +02:00
Markerov
fd2b41c1f0 Fix bug with inline expansion with Unanimate Gif
Issue #273
2016-05-05 12:09:55 +02:00
Markerov
bc2257be08 scroll to thumb
scroll up to image if its top is out of view when shrunk.
Requires jQuery
2016-05-05 12:09:41 +02:00
Markerov
4767a63178 renamed 'this.childNodes[0]' to thumb 2016-05-05 12:09:10 +02:00
8chan
99ee2e36ba Don't expand webm or YouTube videos on js/expand-all-images.js 2016-05-05 12:06:27 +02:00
Markerov
a723ff8e66 Display inline image when it starts loading,
Rewrote inline-expanding.js to display full image as soon as it starts
loading.
Modified expand-all-images.js to work with the new change
Moved max-width to style.css
2016-05-05 12:05:45 +02:00
marktaiwan
26130c43ea fix menu UI for Firefox 2016-05-05 12:03:24 +02:00
marktaiwan
c8eaebce9a reset thread timer on new filter 2016-05-05 12:03:05 +02:00
marktaiwan
709a248d10 Clear empty thread/board from filter list 2016-05-05 12:02:50 +02:00
marktaiwan
2808b1b8b2 post-filter
Adds a dropdown menu to each post that allows for filtering by:
- post
- post and all replies to it
- poster ID
- poster ID and all replies to it
- name
- tripcode

In the options panel, adds a new tab for adding/removing name and
tripcode filters.
2016-05-05 12:02:34 +02:00
8chan
dd27026618 Show stickies at top of catalog 2016-05-05 12:01:16 +02:00
8chan
e8b530a783 Shift-click to hide threads in catalog 2016-05-05 12:00:21 +02:00
8chan
01207dfcbb Catalog script fix for hiding threads with short IDs 2016-05-05 11:59:59 +02:00
8chan
b056124e49 Catalog: don't show hidden threads 2016-05-05 11:59:16 +02:00
8chan
4f96263e3b Upgrade jQuery mixitup, preserve settings, no animations 2016-05-05 11:59:00 +02:00
8chan
e2016340e1 Fix expand-too-long error with new <p> markup 2016-05-05 11:56:41 +02:00
czaks
cd01191072 those parts are extraneous 2016-05-05 11:45:29 +02:00
8chan
3eb755ee7e Move login check in inc/mod/auth.php to a function
This allows pages like create.php to not include inc/mod/pages.php while still being able to use the mod auth functions (like generating salts and passwords)
2016-05-05 11:40:52 +02:00
8chan Admin
93f748e6a8 Security: capitalization of mods username is significant 2016-05-05 11:39:12 +02:00
czaks
d310abc95c Merge branch 'master' of github.com:vichan-devel/vichan 2016-05-05 10:54:09 +02:00
czaks
186ad5ca86 bsd fixup 2016-05-05 10:53:44 +02:00
czaks
abe4bdd6ae fixup 2016-05-05 10:52:58 +02:00
czaks
19b70663d7 remove magic_quotes check; it`s 2016 after all 2016-05-05 10:29:13 +02:00
czaks
4c827cf105 fix some nonsense 2016-05-05 10:22:34 +02:00
czaks
c4b98e94ce [SECURITY] harden for imagetragick (we aren`t hit by the bug, but we were passing uncommon filetypes, like JPEG2000, directly to imagemagick) 2016-05-05 10:17:14 +02:00
czaks
77176faece enable javascript in mod panel 2016-05-05 09:56:54 +02:00
czaks
38bf3276e4 update copyright years; remove a link to tinyboard (website is dead) 2016-05-05 09:39:23 +02:00
czaks
89fe3db556 ... 2016-05-05 09:25:47 +02:00
czaks
985c113190 ... 2016-05-05 09:18:36 +02:00
czaks
8dac72e924 update installer 2016-05-05 09:16:09 +02:00
czaks
a42256b296 locale cache: fix a bug when perms are done wrong 2016-05-05 08:43:34 +02:00
czaks
36b78e5f98 fix for editor highlighting 2016-05-05 08:40:13 +02:00
czaks
295f597699 Merge branch 'master' of github.com:vichan-devel/vichan 2016-05-05 08:22:47 +02:00
czaks
dcf5d699bd simplify the md5 execution logic 2016-05-05 08:22:19 +02:00
czaks
9768161327 simplify the code a bit 2016-05-05 07:51:55 +02:00
czaks
c898f97493 Merge branch 'master' of https://github.com/vichan-devel/vichan 2016-05-05 06:45:08 +02:00
czaks
7c3126866c ease the migration process for the previous security patch (by introducing another migration); restore php 5.4 compatibility (introducing a polyfill system) 2016-05-05 06:43:22 +02:00
Marcin Łabanowski
2caad90755 Merge pull request #177 from 27chan/master
Fix default theme and add Font Awesome Icons in recent.html
2016-04-30 04:09:24 +02:00
27chan
199931dc1a Fix default theme and add Font Awesome Icons 2016-04-29 18:00:33 -03:00
27chan
f7a47f1b9e New theme northboard_cb
For circleboard by kotiakrobaatti
2016-04-29 15:40:01 -03:00
Marcin Łabanowski
e0a4b479f9 Merge pull request #176 from 27chan/master
Update Font Awesome
2016-04-28 07:09:38 +02:00
27chan
48726950d9 Update Font Awesome
Update Font Awesome to 4.6.1
2016-04-27 14:25:51 -03:00
czaks
caaf741691 [SECURITY] keep up with modern password hashing standards 2016-04-22 05:35:43 +02:00
czaks
c53f13bf90 Merge branch 'master' of https://github.com/vichan-devel/vichan 2016-02-09 12:37:03 +01:00
Matthieu
028fd3df15 Added: RSS theme 2016-01-26 00:51:39 +01:00
Matthieu
d2de4419bd Added: config option to hide email in post. (prevent emailfag but let the possibility to sage and noko) 2016-01-26 00:50:55 +01:00
czaks
fe66c51a19 ... (minor fix for locales) 2015-03-10 13:13:18 +01:00
1436 changed files with 119767 additions and 33836 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
**/.git
**/.gitignore
/local-instances
**/.gitkeep

44
.gitignore vendored
View File

@ -7,6 +7,8 @@
/*/config.php
/*.html
/*.xml
/vendor/*
/vendor
# include some files though
!/templates/*.html
@ -18,6 +20,9 @@
# instance-config
/inc/instance-config.php
# captcha-config
/inc/captchaconfig.php
# .installed
/.installed
@ -39,6 +44,7 @@ Thumbs.db
*.orig
*~
~*/
php_errors.log
# tmp filesystem
/tmp/cache/*
@ -49,6 +55,7 @@ Thumbs.db
#vichan custom
favicon.ico
/static/spoiler.png
/local-instances
piwik/
jwplayer/
@ -59,10 +66,37 @@ tf/
[._]s[a-w][a-z]
# special boards
all/
mod/
random/
/all/
/mod/
/random/
# Banners
banners/*
!banners/lain-bottom.png
static/banners/*
#Fonts
stylesheets/fonts
#Images from twemoji
js/twemoji/16x16/
#Boards
AKM/
alt/
anime/
dead/
draw/
edu/
games/
hobby/
leftypol/
leftypol_archive/
meta/
music/
overboard/
roulette/
roulette_archive/
sfw/
siberia/
siberia_archive/
tech/
vi/

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "js/wPaint"]
path = js/wPaint
url = https://github.com/vichan-devel/wPaint.git
branch = master
[submodule "inc/lib/parsedown"]
path = inc/lib/parsedown
url = https://github.com/vichan-devel/parsedown
branch = master

17
403.php
View File

@ -1,17 +0,0 @@
<title>403</title>
</head>
<!-- <body style="background: black"> -->
<body style="background-image:url(/static/system.gif)">
<center><img height=480 width=640 src="/static/403.jpg"/>
<marquee scrollamount="40"><h1><p style="font-family: sans-serif; font-size:30px; color: black;">WHOOPS</p></h1></marquee>
<p style="color: blue;background:black">this isn't for you</p>
<p style="color: red;background:black">it's a 403</p>
<br /> <br />
<param name="movie" value="/static/congrats.swf">
</center>
<audio autoplay loop>
<source src="/static/cyberia.ogg" />
</audio>
</body>
</html>

21
404.html Normal file
View File

@ -0,0 +1,21 @@
<html>
<head>
<title>404 - Page Not Found</title>
<style type="text/css">
body {
background: #1E1E1E;
color: #999999;
}
</style>
</head>
<body>
<center>
<h1>Page not found</h1>
<img style="width:750px;height:420px" src="/static/404.webp"/>
<br/>
<p>It may have been pruned, moved, merged, removed, or never existed.</p>
</center>
</body>
</html>

32
404.php
View File

@ -1,32 +0,0 @@
<title>404</title>
<style type="text/css">
body {
margin: 0 !important;
padding: 0px !important;
overflow-x:hidden!important;
background-size: cover !important;
background-color: #222 !important;
background-image:
url(https://gs1.wac.edgecastcdn.net/8019B6/data.tumblr.com/tumblr_mc0xu6C22f1qbj9bko1_500.gif);
background-repeat: no-repeat !important;
background-position: 0!important;
background-attachment: fixed !important;
background-size: cover !important;
}
</style>
</head>
<body>
<center><!--<img src="/static/lain_2_090.jpg"/>-->
<marquee scrollamount="40"><h1><p style="font-family: sans-serif; font-size:30px; color: white;">WHOOPS</p></h1></marquee>
<p style="color: blue;background:black">There's nothing here</p>
<p style="color: red;background:black">it's a 404</p>
<br /> <br />
<audio autoplay loop>
<source src="/static/duvet.ogg" type="audio/ogg" />
<source src="/static/duvet.mp3" type="audio/mpeg" />
</audio>
</center>
</body>
</html>

29
Dockerfile Normal file
View File

@ -0,0 +1,29 @@
FROM php:8.1.8-fpm
COPY . /code
RUN docker-php-ext-install pdo pdo_mysql
RUN apt-get update -y && apt-get install -y libpng-dev libjpeg-dev libonig-dev
RUN docker-php-ext-install mbstring
RUN apt-get update -y && apt-get install -y libmcrypt-dev
# RUN docker-php-ext-install -j$(nproc) mcrypt
RUN docker-php-ext-install iconv
RUN apt-get update -y && apt-get install -y imagemagick
RUN apt-get update -y && apt-get install -y graphicsmagick
RUN apt-get update -y && apt-get install -y gifsicle
# RUN docker-php-ext-configure gd
# --with-jpeg=/usr/include
# --with-png-dir=/usr \
RUN docker-php-ext-install gd
RUN apt-get update -y \
&& apt-get install -y libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev git \
&& pecl install memcached \
&& echo extension=memcached.so >> /usr/local/etc/php/conf.d/memcached.ini \
&& apt-get remove -y build-essential libmemcached-dev libz-dev \
&& apt-get autoremove -y \
&& apt-get clean \
&& rm -rf /tmp/pear \
&& curl -sS https://getcomposer.org/installer -o composer-setup.php \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& docker-php-ext-install bcmath \
&& cd /code && composer install

View File

@ -1,97 +1,89 @@
Lainchan - A fork of vichan
leftypol - vichan/lainchan based imageboard software
========================================================
About
------------
Lainchan is a fork of [vichan](http://github.com/vichan-devel/vichan),
a great imageboard package, actively building on it and adding a lot of features and other
The leftypol imageboard is a fork of [lainchan](http://github.com/lainchan/lainchan), a fork of [vichan](http://github.com/vichan-devel/vichan), actively building on it and adding features, bug-fixes and other
improvements.
We highly recommend you read the [vichan GitHub wiki](http://github.com/vichan-devel/vichan/wiki) for a basic guide to features.
Requirements
------------
1. PHP >= 5.4 (we still try to keep compatibility with php 5.3 as much as possible)
PHP 7.0 is explicitly supported.
2. MySQL/MariaDB server
3. [mbstring](http://www.php.net/manual/en/mbstring.installation.php)
4. [PHP GD](http://www.php.net/manual/en/intro.image.php)
5. [PHP PDO](http://www.php.net/manual/en/intro.pdo.php)
1. PHP >= 5.4 (we do not actively check if this is still supported)
PHP 8.0 is explicitly supported. PHP 7.x should be compatable.
2. MySQL/MariaDB server >= 5.5.3
3. [Composer](https://getcomposer.org/) (To install various packages)
4. [mbstring](http://www.php.net/manual/en/mbstring.installation.php)
5. [PHP GD](http://www.php.net/manual/en/intro.image.php)
6. [PHP PDO](http://www.php.net/manual/en/intro.pdo.php)
We try to make sure lainchan is compatible with all major web servers and
operating systems. lainchan does not include an Apache ```.htaccess``` file nor does
This should be compatible with all major web servers and
operating systems. This code does not include an Apache ```.htaccess``` file nor does
it need one.
### Recommended
1. MySQL/MariaDB server >= 5.5.3
2. ImageMagick (command-line ImageMagick or GraphicsMagick preferred).
3. [APC (Alternative PHP Cache)](http://php.net/manual/en/book.apc.php),
1. ImageMagick (command-line ImageMagick or GraphicsMagick preferred).
2. [APC (Alternative PHP Cache)](http://php.net/manual/en/book.apc.php),
Redis,
[XCache](http://xcache.lighttpd.net/) or
[Memcached](http://www.php.net/manual/en/intro.memcached.php)
Contributing
------------
You can contribute to lainchan by:
* Developing patches/improvements/translations and using GitHub to submit pull requests
You can contribute to leftypol, and upstream imageboard softwares, by:
* Developing patches/improvements/translations and using this repo to submit pull requests
* Providing feedback and suggestions
* Writing/editing documentation
If you need help developing a patch, please join our IRC channel.
> irc.freenode.net @ #lainchan-dev
If you need help developing a patch, please reply to the sticky on our [/tech/](https://leftypol.org/tech/) board.
Installation
-------------
1. Download and extract lainchan to your web directory or get the latest
1. Download and extract leftypol to your web directory or get the latest
development version with:
git clone git://github.com/lainchan/lainchan.git
git clone git://git.leftypol.org/leftypol/leftypol.git
2. Navigate to ```install.php``` in your web browser and follow the
2. run ```composer install``` inside the directory
3. Navigate to ```install.php``` in your web browser and follow the
prompts.
3. lainchan should now be installed. Log in to ```mod.php``` with the
4. leftypol should now be installed. Log in to ```mod.php``` with the
default username and password combination: **admin / password**.
Please remember to change the administrator account password.
See also: [Configuration Basics](http://tinyboard.org/docs/?p=Config).
See also: [Configuration Basics](https://web.archive.org/web/20121003095922/http://tinyboard.org/docs/?p=Config).
Upgrade
-------
To upgrade from any version of Tinyboard or vichan:
This probably will break if you try and upgrade from vichan or the older (<= August 2021) leftypol versions. Ask us for migration advice if you intend to do so.
To upgrade from this repo:
Either run ```git pull``` to update your files, if you used git, or
backup your ```inc/instance-config.php```, replace all your files in place
(don't remove boards etc.), then put ```inc/instance-config.php``` back and
finally run ```install.php```.
To migrate from a Kusaba X board, use http://github.com/vichan-devel/Tinyboard-Migration
To migrate from a Kusaba X board, use http://github.com/vichan-devel/Tinyboard-Migration (untested)
Support
--------
If you find a bug, please report it.
If you need assistance with installing, configuring, or using lainchan, you may
If you need assistance with installing, configuring, or using leftypol, you may
find support from a variety of sources:
* If you're unsure about how to enable or configure certain features, make
sure you have read the comments in ```inc/config.php```.
* You can join lainchan's IRC channel for support
[irc.freenode.net #lainchan](irc://irc.freenode.net/lainchan)
* For support, reply to the sticky on our [/tech/](https://leftypol.org/tech/) board.
### Tinyboard support
vichan, and by extension lainchan, is based on a Tinyboard, so both engines have very much in common. These
links may be helpful for you as well:
vichan, and by extension lainchan and leftypol, is based on a Tinyboard, so both engines have very much in common. These links may be helpful for you as well:
* Tinyboard documentation can be found [here](https://web.archive.org/web/20121016074303/http://tinyboard.org/docs/?p=Main_Page).
Donations
---------
Do you like our work? You can motivate us financially to do better ;)
* Bitcoin: 18CshTkxW6HRFoBhXo9mLJcjkReMmjvuq9
You can also ask us to develop some feature specially for you <3. Join our IRC
channel and ask for a quote (there are a few of us, who work with the codebase
and are skilled enough to develop such features pretty quickly).
CLI tools
-----------------
There are a few command line interface tools, based on Tinyboard-Tools. These need
@ -104,13 +96,13 @@ at the power users. You won't be able to run these from shared hosting accounts
Localisation
------------
Wanting to have lainchan in your language? You can contribute your translations to vichan at this URL:
Wanting to have leftypol in your language? You can contribute your translations to vichan at this URL:
https://www.transifex.com/projects/p/tinyboard-vichan-devel/
Oekaki
------
lainchan makes use of [wPaint](https://github.com/websanova/wPaint) for oekaki. After you pull the repository, however, you will need to download wPaint separately using git's `submodule` feature. Use the following commands:
leftypol makes use of [wPaint](https://github.com/websanova/wPaint) for oekaki. After you pull the repository, however, you will need to download wPaint separately using git's `submodule` feature. Use the following commands:
```
git submodule init
@ -123,12 +115,12 @@ WebM support
------------
Read `inc/lib/webm/README.md` for information about enabling webm.
lainchan API
leftypol API
----------
lainchan provides by default a 4chan-compatible JSON API, just like vichan. For documentation on this, see:
leftypol provides by default a 4chan-compatible JSON API, just like vichan. For documentation on this, see:
https://github.com/vichan-devel/vichan-API/ .
License
--------
See [LICENSE.md](http://github.com/lainchan/lainchan/blob/master/LICENSE.md).
See LICENSE.md.

47
b.php
View File

@ -1,47 +0,0 @@
<?php
// This script assumes there is at least one normal (non-priority)
// banner!
// Get the files in a directory, returns null if the directory does
// not exist.
function getFilesInDirectory($dir) {
if (! is_dir($dir)) {
return null;
}
return array_diff(scandir($dir), array('.', '..'));
}
// Serve a random banner and exit.
function serveRandomBanner($dir, $files) {
$name = $files[array_rand($files)];
// snags the extension
$ext = pathinfo($name, PATHINFO_EXTENSION);
// send the right headers
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1
header('Pragma: no-cache'); // HTTP 1.0
header('Expires: 0'); // Proxies
header("Content-type: image/" . $ext);
header("Content-Disposition: inline; filename=" . $name);
// readfile displays the image, passthru seems to spits stream.
readfile($dir.$name);
exit;
}
// Get all the banners
$bannerDir = "banners/";
$priorityDir = "banners_priority/";
$banners = getFilesInDirectory($bannerDir);
$priority = getFilesInDirectory($priorityDir);
// If there are priority banners, serve 1/3rd of the time.
if($priority !== null && count($priority) !== 0 && rand(0,2) === 0) {
serveRandomBanner($priorityDir, $priority);
}
serveRandomBanner($bannerDir, $banners);
?>

View File

@ -1,6 +1,5 @@
<?php
require_once 'inc/functions.php';
require_once 'inc/bans.php';
require_once 'inc/bootstrap.php';
checkBan();
//If the user is not banned, show the "not banned" page.

View File

@ -1,22 +1,8 @@
<html>
<head>
<title>Lainchan Banners</title>
</head>
<body>
<?php
function listBannersInDir($dir) {
if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "<a href=\"$dir/$entry\"><img src=\"$dir/$entry\" alt=\"$entry\" style=\"width:348px;height:128px\"></a> ";
}
}
closedir($handle);
}
}
listBannersInDir("banners_priority");
listBannersInDir("banners");
?>
</body>
</html>
$files = scandir(__dir__ . '/static/banners/', SCANDIR_SORT_NONE);
$files = array_diff($files, ['.', '..']);
$filename = $files[array_rand($files)];
header("Location: /static/banners/$filename", true, 307);
header('Cache-Control: no-cache');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

0
bg.php Executable file → Normal file
View File

0
c.php Executable file → Normal file
View File

32
captcha.php Normal file
View File

@ -0,0 +1,32 @@
<?php
require_once 'inc/functions.php';
require_once 'inc/lib/securimage/securimage.php';
if(!isset($config['securimage']) || !$config['securimage']){
error('Securimage captcha not enabled.'); //TODO error image
}
$image=new Securimage(array('config_file'=>__DIR__ . '/inc/captchaconfig.php'));
$image->show();
$code=$image->getCode(false, true);
$ip=$_SERVER['REMOTE_ADDR'];
$query=prepare('INSERT INTO captchas(ip, code, time) VALUES(:ip, :code, NOW())');
$query->bindValue(':ip', $ip);
$query->bindValue(':code', $code);
$query->execute() or error(db_error($query));
$query=prepare('SELECT count(*) from captchas where ip=:ip');
$query->bindValue(':ip', $ip);
$query->execute() or error(db_error($query));
$count=$query->fetch()[0];
if($count>10){
$query=prepare('DELETE from captchas where ip=:ip ORDER BY time asc LIMIT 1');
$query->bindValue(':ip', $ip);
$query->execute()or error(db_error($query));
}

48
composer.json Normal file
View File

@ -0,0 +1,48 @@
{
"name": "leftypol/leftypol",
"description": "leftypol imageboard",
"type": "project",
"require": {
"twig/twig": "^1.44.2",
"lifo/ip": "^1.0",
"gettext/gettext": "^1.0",
"mrclay/minify": "^2.1.6"
},
"autoload": {
"classmap": ["inc/"],
"files": [
"inc/bootstrap.php",
"inc/display.php",
"inc/template.php",
"inc/database.php",
"inc/events.php",
"inc/api.php",
"inc/mod/auth.php",
"inc/lock.php",
"inc/queue.php",
"inc/polyfill.php",
"inc/error.php",
"inc/functions.php",
"inc/functions/net.php"
]
},
"license": "Tinyboard + vichan",
"authors": [
{
"name": "tinyboard contributors",
"homepage": "https://github.com/savetheinternet/Tinyboard"
},
{
"name": "vichan contributors",
"homepage": "https://github.com/vichan-devel/vichan/"
},
{
"name": "lainchan contributors",
"homepage": "https://github.com/lainchan/lainchan/"
},
{
"name": "leftypol contributors",
"homepage": "https://git.leftypol.org/leftypol/leftypol/"
}
]
}

330
composer.lock generated Normal file
View File

@ -0,0 +1,330 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "346d80deda89b0298a414b565213f312",
"packages": [
{
"name": "gettext/gettext",
"version": "v1.1.5",
"source": {
"type": "git",
"url": "https://github.com/php-gettext/Gettext.git",
"reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-gettext/Gettext/zipball/1bdf755a1b49f0614d6fc29f446df567eb62cd5c",
"reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Gettext": ""
},
"files": [
"Gettext/translator_functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"AGPL-3.0"
],
"authors": [
{
"name": "Oscar Otero",
"email": "oom@oscarotero.com",
"homepage": "http://oscarotero.com",
"role": "Developer"
}
],
"description": "PHP - JS gettext conversor",
"homepage": "https://github.com/oscarotero/Gettext",
"keywords": [
"JS",
"gettext",
"i18n",
"translation"
],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/oscarotero/Gettext/issues",
"source": "https://github.com/php-gettext/Gettext/tree/v1.1.5"
},
"time": "2014-10-22T15:53:45+00:00"
},
{
"name": "lifo/ip",
"version": "v1.1",
"source": {
"type": "git",
"url": "https://github.com/lifo101/ip.git",
"reference": "b6a36dab288d7aea155698808bfc6649799fe413"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lifo101/ip/zipball/b6a36dab288d7aea155698808bfc6649799fe413",
"reference": "b6a36dab288d7aea155698808bfc6649799fe413",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Lifo\\IP\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jason Morriss",
"email": "lifo2013@gmail.com"
}
],
"description": "IP address helper PHP library for working with IPv4 and IPv6 addresses",
"keywords": [
"IP",
"ip address",
"ipv4",
"ipv6"
],
"support": {
"issues": "https://github.com/lifo101/ip/issues",
"source": "https://github.com/lifo101/ip/tree/master"
},
"time": "2020-04-02T11:09:10+00:00"
},
{
"name": "mrclay/minify",
"version": "2.3.3",
"source": {
"type": "git",
"url": "https://github.com/mrclay/minify.git",
"reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mrclay/minify/zipball/1928e89208d28e91427b2f13b67acdbd8cd01ac9",
"reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9",
"shasum": ""
},
"require": {
"ext-pcre": "*",
"php": ">=5.2.1"
},
"require-dev": {
"tubalmartin/cssmin": "~2.4.8"
},
"suggest": {
"tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)"
},
"type": "library",
"autoload": {
"classmap": [
"min/lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Stephen Clay",
"email": "steve@mrclay.org",
"role": "Developer"
}
],
"description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers",
"homepage": "http://code.google.com/p/minify/",
"support": {
"email": "minify@googlegroups.com",
"issues": "http://code.google.com/p/minify/issues/list",
"source": "https://github.com/mrclay/minify/tree/2.x",
"wiki": "http://code.google.com/p/minify/w/list"
},
"time": "2017-11-03T21:04:01+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-10-20T20:35:02+00:00"
},
{
"name": "twig/twig",
"version": "v1.44.6",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ae39480f010ef88adc7938503c9b02d3baf2f3b3",
"reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"psr/container": "^1.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.44-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
},
"psr-4": {
"Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Twig Team",
"role": "Contributors"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v1.44.6"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2021-11-25T13:31:46+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

40
docker-compose.yml Normal file
View File

@ -0,0 +1,40 @@
services:
#nginx webserver + php 8.x
web:
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- "9091:80"
depends_on:
- leftypol-db
volumes:
- ./local-instances/1/www:/var/www/html
- ./docker/nginx/leftypol.conf:/etc/nginx/conf.d/default.conf
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf
links:
- php
php:
build:
context: .
dockerfile: ./docker/php/Dockerfile
volumes:
- ./local-instances/1/www:/var/www
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
#MySQL Service
leftypol-db:
image: mysql:8.0.35
container_name: leftypol-db
restart: unless-stopped
tty: true
ports:
- "3306:3306"
environment:
MYSQL_DATABASE: vichan
MYSQL_ROOT_PASSWORD: password
command: "--default-authentication-plugin=mysql_native_password"
volumes:
- ./local-instances/1/mysql:/var/lib/mysql

16
docker/doc.md Normal file
View File

@ -0,0 +1,16 @@
The `php-fpm` process runs containerized.
The php application always uses `/var/www` as it's work directory and home folder, and if `/var/www` is bind mounted it
is necessary to adjust the path passed via FastCGI to `php-fpm` by changing the root directory to `/var/www`.
This can achieved in nginx by setting the `fastcgi_param SCRIPT_FILENAME` to `/var/www/$fastcgi_script_name;`
The default docker compose settings are intended for development and testing purposes.
The folder structure expected by compose is as follows
```
<vichan-project>
└── local-instances
└── 1
├── mysql
└── www
```
The vichan container is by itself much less rigid.

8
docker/nginx/Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM nginx:1.25.3-alpine
COPY . /code
RUN adduser --system www-data \
&& adduser www-data www-data
CMD [ "nginx", "-g", "daemon off;" ]
EXPOSE 80

View File

@ -0,0 +1,65 @@
upstream php-upstream {
server php:9000;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name leftypol;
root /var/www/html;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.html index.php;
charset utf-8;
location ~ ^([^.\?]*[^\/])$ {
try_files $uri @addslash;
}
# Expire rules for static content
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|webp|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
log_not_found off;
# Public cache, never changes until max-age expires, max-age of 1 month, can still be served while being
# revalidated or if the server is erroring for 1 day.
add_header Cache-Control "public, immutable, max-age=2592000, stale-while-revalidate=86400, stale-if-error=86400";
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
log_not_found off;
# Public cache, max-age of 1 year, can still be served while being revalidated or if the server is erroring for 1 day.
add_header Cache-Control "public, max-age=31536000, stale-while-revalidate=86400, stale-if-error=86400";
}
location ~* \.(html)$ {
expires -1;
}
location @addslash {
return 301 $uri/;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
client_max_body_size 2G;
location ~ \.php$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Request-Id $x_request_id;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Forwarded-Request-Id $x_request_id;
fastcgi_pass php-upstream;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/$fastcgi_script_name;
fastcgi_read_timeout 600;
include fastcgi_params;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
}

35
docker/nginx/nginx.conf Normal file
View File

@ -0,0 +1,35 @@
# This and proxy.conf are based on
# https://github.com/dead-guru/devichan/blob/master/nginx/nginx.conf
user www-data;
worker_processes auto;
# daemon off;
# error_log /var/log/nginx/error.log warn;
error_log /dev/stdout warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#access_log /var/log/nginx/access.log;
# Switch logging to console out to view via Docker
access_log /dev/stdout;
error_log /dev/stdout warn;
sendfile on;
keepalive_timeout 5;
gzip on;
gzip_http_version 1.0;
gzip_vary on;
gzip_comp_level 6;
gzip_types text/xml text/plain text/css application/xhtml+xml application/xml application/rss+xml application/atom_xml application/x-javascript application/x-httpd-php;
gzip_disable "MSIE [1-6]\.";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-available/*.conf;
}

40
docker/nginx/proxy.conf Normal file
View File

@ -0,0 +1,40 @@
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=czone:4m max_size=50m inactive=120m;
proxy_temp_path /var/tmp/nginx;
proxy_cache_key "$scheme://$host$request_uri";
map $http_forwarded_request_id $x_request_id {
"" $request_id;
default $http_forwarded_request_id;
}
map $http_forwarded_forwarded_host $forwardedhost {
"" $host;
default $http_forwarded_forwarded_host;
}
map $http_x_forwarded_proto $fcgi_https {
default "";
https on;
}
map $http_x_forwarded_proto $real_scheme {
default $scheme;
https https;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
real_ip_header X-Forwarded-For;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 172.18.0.0;
set_real_ip_from 192.168.0.0/24;
set_real_ip_from 127.0.0.0/8;
real_ip_recursive on;

87
docker/php/Dockerfile Normal file
View File

@ -0,0 +1,87 @@
# Based on https://github.com/dead-guru/devichan/blob/master/php-fpm/Dockerfile
FROM composer AS composer
FROM php:7.2-fpm-alpine
RUN apk add --no-cache \
zlib \
zlib-dev \
libpng \
libpng-dev \
libjpeg-turbo \
libjpeg-turbo-dev \
libwebp \
libwebp-dev \
libcurl \
curl-dev \
imagemagick \
graphicsmagick \
gifsicle \
ffmpeg \
bind-tools \
gettext \
gettext-dev \
icu-dev \
oniguruma \
oniguruma-dev \
libmcrypt \
libmcrypt-dev \
lz4-libs \
lz4-dev \
imagemagick-dev \
pcre-dev \
$PHPIZE_DEPS \
&& docker-php-ext-configure gd \
--with-webp-dir=/usr/include/webp \
--with-jpeg-dir=/usr/include \
&& docker-php-ext-install -j$(nproc) \
gd \
curl \
bcmath \
opcache \
pdo_mysql \
gettext \
intl \
mbstring \
&& pecl update-channels \
&& pecl install -o -f igbinary \
&& pecl install redis \
&& pecl install imagick \
$$ docker-php-ext-enable \
igbinary \
redis \
imagick \
&& apk del \
zlib-dev \
libpng-dev \
libjpeg-turbo-dev \
libwebp-dev \
curl-dev \
gettext-dev \
oniguruma-dev \
libmcrypt-dev \
lz4-dev \
imagemagick-dev \
pcre-dev \
$PHPIZE_DEPS \
&& rm -rf /var/cache/*
RUN rmdir /var/www/html \
&& install -d -m 744 -o www-data -g www-data /var/www \
&& install -d -m 700 -o www-data -g www-data /var/tmp/vichan \
&& install -d -m 700 -o www-data -g www-data /var/cache/gen-cache \
&& install -d -m 700 -o www-data -g www-data /var/cache/template-cache
# Copy the bootstrap script.
COPY ./docker/php/bootstrap.sh /usr/local/bin/bootstrap.sh
COPY --from=composer /usr/bin/composer /usr/local/bin/composer
# Copy the actual project (use .dockerignore to exclude stuff).
COPY . /code
# Install the compose depedencies.
RUN cd /code && composer install
WORKDIR "/var/www"
CMD [ "bootstrap.sh" ]
EXPOSE 9000

79
docker/php/bootstrap.sh Executable file
View File

@ -0,0 +1,79 @@
#!/bin/sh
set -eu
function set_cfg() {
if [ ! -f "/var/www/inc/$1" ]; then
echo "INFO: Resetting $1"
touch "/var/www/inc/$1"
chown www-data "/var/www/inc/$1"
chgrp www-data "/var/www/inc/$1"
chmod 600 "/var/www/inc/$1"
else
echo "INFO: Using existing $1"
fi
}
if ! mountpoint -q /var/www; then
echo "WARNING: '/var/www' is not a mountpoint. All the data will remain inside the container!"
fi
if [ ! -w /var/www ] ; then
echo "ERROR: '/var/www' is not writable. Closing."
exit 1
fi
# Link the entrypoints from the exposed directory.
ln -nfs \
/code/tools/ \
/code/walls/ \
/code/*.php \
/code/LICENSE.* \
/code/404.html \
/code/install.sql \
/var/www/
# Static files accessible from the webserver must be copied.
cp -ur /code/static /var/www/
cp -ur /code/stylesheets /var/www/
# Ensure correct permissions are set, since this might be bind mount.
chown www-data /var/www
chgrp www-data /var/www
# Initialize an empty robots.txt with the default if it doesn't exist.
touch /var/www/robots.txt
# Link the cache and tmp files directory.
ln -nfs /var/tmp/vichan /var/www/tmp
# Link the javascript directory.
ln -nfs /code/js /var/www/
# Link the html templates directory and it's cache.
ln -nfs /code/templates /var/www/
ln -nfs -T /var/cache/template-cache /var/www/templates/cache
chown -h www-data /var/www/templates/cache
chgrp -h www-data /var/www/templates/cache
# Link the generic cache.
ln -nfs -T /var/cache/gen-cache /var/www/tmp/cache
chown -h www-data /var/www/tmp/cache
chgrp -h www-data /var/www/tmp/cache
# Create the included files directory and link them
install -d -m 700 -o www-data -g www-data /var/www/inc
for file in /code/inc/*; do
file="${file##*/}"
if [ ! -e /var/www/inc/$file ]; then
ln -s /code/inc/$file /var/www/inc/
fi
done
# Copy an empty instance configuration if the file is a link (it was linked because it did not exist before).
set_cfg 'instance-config.php'
# Link the composer dependencies.
ln -nfs /code/vendor /var/www/
# Start the php-fpm server.
exec php-fpm

15
docker/php/www.conf Normal file
View File

@ -0,0 +1,15 @@
[www]
access.log = /proc/self/fd/2
; Ensure worker stdout and stderr are sent to the main error log.
catch_workers_output = yes
user = www-data
group = www-data
listen = 127.0.0.1:9000
pm = static
pm.max_children = 16
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

View File

@ -171,7 +171,7 @@ class AntiBot {
public function hash() {
global $config;
// This is the tricky part: create a hash to validate it after
// First, sort the keys in alphabetical order (A-Z)
$inputs = $this->inputs;
@ -220,63 +220,3 @@ function _create_antibot($board, $thread) {
return $antibot;
}
function checkSpam(array $extra_salt = array()) {
global $config, $pdo;
if (!isset($_POST['hash']))
return true;
$hash = $_POST['hash'];
if (!empty($extra_salt)) {
// create a salted hash of the "extra salt"
$extra_salt = implode(':', $extra_salt);
} else {
$extra_salt = '';
}
// Reconsturct the $inputs array
$inputs = array();
foreach ($_POST as $name => $value) {
if (in_array($name, $config['spam']['valid_inputs']))
continue;
$inputs[$name] = $value;
}
// Sort the inputs in alphabetical order (A-Z)
ksort($inputs);
$_hash = '';
// Iterate through each input
foreach ($inputs as $name => $value) {
$_hash .= $name . '=' . $value;
}
// Add a salt to the hash
$_hash .= $config['cookies']['salt'];
// Use SHA1 for the hash
$_hash = sha1($_hash . $extra_salt);
if ($hash != $_hash)
return true;
$query = prepare('SELECT `passed` FROM ``antispam`` WHERE `hash` = :hash');
$query->bindValue(':hash', $hash);
$query->execute() or error(db_error($query));
if ((($passed = $query->fetchColumn(0)) === false) || ($passed > $config['spam']['hidden_inputs_max_pass'])) {
// there was no database entry for this hash. most likely expired.
return true;
}
return $hash;
}
function incrementSpamHash($hash) {
$query = prepare('UPDATE ``antispam`` SET `passed` = `passed` + 1 WHERE `hash` = :hash');
$query->bindValue(':hash', $hash);
$query->execute() or error(db_error($query));
}

View File

@ -32,18 +32,22 @@ class Api {
'images' => 'images',
'sticky' => 'sticky',
'locked' => 'locked',
'cycle' => 'cyclical',
'bump' => 'last_modified',
'embed' => 'embed',
'board' => 'board',
);
$this->threadsPageFields = array(
'id' => 'no',
'bump' => 'last_modified'
'bump' => 'last_modified',
'board' => 'board',
);
$this->fileFields = array(
'thumbheight' => 'tn_h',
'thumbwidth' => 'tn_w',
'file_id' => 'id',
'type' => 'mime',
'extension' => 'ext',
'height' => 'h',
'width' => 'w',
'size' => 'fsize',
@ -87,12 +91,41 @@ class Api {
}
private function translateFile($file, $post, &$apiPost) {
global $config;
$this->translateFields($this->fileFields, $file, $apiPost);
$apiPost['filename'] = @substr($file->name, 0, strrpos($file->name, '.'));
$dotPos = strrpos($file->file, '.');
$apiPost['ext'] = substr($file->file, $dotPos);
$apiPost['tim'] = substr($file->file, 0, $dotPos);
$apiPost['md5'] = base64_encode(hex2bin($post->filehash));
if (isset ($file->thumb) && $file->thumb) {
$apiPost['spoiler'] = $file->thumb === 'spoiler';
}
if (isset ($file->hash) && $file->hash) {
$apiPost['md5'] = base64_encode(hex2bin($file->hash));
}
else if (isset ($post->filehash) && $post->filehash) {
$apiPost['md5'] = base64_encode(hex2bin($post->filehash));
}
$apiPost['file_path'] = $config['uri_img'] . $file->file;
// Pick the correct thumbnail
if (isset($file->thumb) && $file->thumb === 'spoiler') {
// Spoiler
$apiPost['thumb_path'] = $config['root'] . $config['spoiler_image'];
} else if (!isset($file->thumb) || $file->thumb === 'file') {
// Default file format image
$thumbFile = $config['file_icons']['default'];
if (isset($file->extension) && isset($config['file_icons'][$file->extension])) {
$thumbFile = $config['file_icons'][$file->extension];
}
$apiPost['thumb_path'] = $config['root'] . sprintf($config['file_thumb'], $thumbFile);
} else {
// The file's own thumbnail
$apiPost['thumb_path'] = $config['uri_thumb'] . $file->thumb;
}
}
private function translatePost($post, $threadsPage = false) {
@ -104,16 +137,27 @@ class Api {
if (isset($config['poster_ids']) && $config['poster_ids']) $apiPost['id'] = poster_id($post->ip, $post->thread, $board['uri']);
if ($threadsPage) return $apiPost;
// Handle country field
if (isset($post->body_nomarkup) && $this->config['country_flags']) {
// Load board info
if (isset($post->board)) {
openBoard($post->board);
}
// Handle special fields
if (isset($post->body_nomarkup) && ($this->config['country_flags'] || $this->config['user_flag'])) {
$modifiers = extract_modifiers($post->body_nomarkup);
if (isset($modifiers['flag']) && isset($modifiers['flag alt']) && preg_match('/^[a-z]{2}$/', $modifiers['flag'])) {
$country = strtoupper($modifiers['flag']);
if (isset($modifiers['flag']) && isset($modifiers['flag alt']) && preg_match('/^[1-9a-z_-]{2,}$/', $modifiers['flag'])) {
$country = strtolower($modifiers['flag']);
if ($country) {
$apiPost['country'] = $country;
$apiPost['country_name'] = $modifiers['flag alt'];
}
}
if (isset($modifiers['warning message'])) {
$apiPost['warning_msg'] = $modifiers['warning message'];
}
if (isset($modifiers['ban message'])) {
$apiPost['ban_msg'] = $modifiers['ban message'];
}
}
if ($config['slugify'] && !$post->thread) {
@ -121,21 +165,13 @@ class Api {
}
// Handle files
// Note: 4chan only supports one file, so only the first file is taken into account for 4chan-compatible API.
if (isset($post->files) && $post->files && !$threadsPage) {
$file = $post->files[0];
$this->translateFile($file, $post, $apiPost);
if (sizeof($post->files) > 1) {
$extra_files = array();
foreach ($post->files as $i => $f) {
if ($i == 0) continue;
$extra_file = array();
$this->translateFile($f, $post, $extra_file);
$apiPost['files'] = [];
foreach ($post->files as $f) {
$file = array();
$this->translateFile($f, $post, $file);
$extra_files[] = $extra_file;
}
$apiPost['extra_files'] = $extra_files;
$apiPost['files'][] = $file;
}
}
@ -152,6 +188,13 @@ class Api {
$apiPosts['posts'][] = $this->translatePost($p, $threadsPage);
}
// Count unique IPs
$ips = array($thread->ip);
foreach ($thread->posts as $p) {
$ips[] = $p->ip;
}
$apiPosts['posts'][0]['unique_ips'] = count(array_unique($ips));
return $apiPosts;
}

View File

@ -1,86 +1,84 @@
<?php
require 'inc/lib/IP/Lifo/IP/IP.php';
require 'inc/lib/IP/Lifo/IP/BC.php';
require 'inc/lib/IP/Lifo/IP/CIDR.php';
use Lifo\IP\CIDR;
class Bans {
static public function range_to_string($mask) {
list($ipstart, $ipend) = $mask;
if (!isset($ipend) || $ipend === false) {
// Not a range. Single IP address.
$ipstr = inet_ntop($ipstart);
return $ipstr;
}
if (strlen($ipstart) != strlen($ipend))
if (strlen($ipstart) != strlen($ipend)) {
return '???'; // What the fuck are you doing, son?
}
$range = CIDR::range_to_cidr(inet_ntop($ipstart), inet_ntop($ipend));
if ($range !== false)
if ($range !== false) {
return $range;
}
return '???';
}
private static function calc_cidr($mask) {
$cidr = new CIDR($mask);
$range = $cidr->getRange();
return array(inet_pton($range[0]), inet_pton($range[1]));
}
public static function parse_time($str) {
if (empty($str))
return false;
if (($time = @strtotime($str)) !== false)
return $time;
if (!preg_match('/^((\d+)\s?ye?a?r?s?)?\s?+((\d+)\s?mon?t?h?s?)?\s?+((\d+)\s?we?e?k?s?)?\s?+((\d+)\s?da?y?s?)?((\d+)\s?ho?u?r?s?)?\s?+((\d+)\s?mi?n?u?t?e?s?)?\s?+((\d+)\s?se?c?o?n?d?s?)?$/', $str, $matches))
return false;
$expire = 0;
if (isset($matches[2])) {
// Years
$expire += $matches[2]*60*60*24*365;
$expire += (int)$matches[2]*60*60*24*365;
}
if (isset($matches[4])) {
// Months
$expire += $matches[4]*60*60*24*30;
$expire += (int)$matches[4]*60*60*24*30;
}
if (isset($matches[6])) {
// Weeks
$expire += $matches[6]*60*60*24*7;
$expire += (int)$matches[6]*60*60*24*7;
}
if (isset($matches[8])) {
// Days
$expire += $matches[8]*60*60*24;
$expire += (int)$matches[8]*60*60*24;
}
if (isset($matches[10])) {
// Hours
$expire += $matches[10]*60*60;
$expire += (int)$matches[10]*60*60;
}
if (isset($matches[12])) {
// Minutes
$expire += $matches[12]*60;
$expire += (int)$matches[12]*60;
}
if (isset($matches[14])) {
// Seconds
$expire += $matches[14];
$expire += (int)$matches[14];
}
return time() + $expire;
}
static public function parse_range($mask) {
$ipstart = false;
$ipend = false;
if (preg_match('@^(\d{1,3}\.){1,3}([\d*]{1,3})?$@', $mask) && substr_count($mask, '*') == 1) {
// IPv4 wildcard mask
$parts = explode('.', $mask);
@ -101,51 +99,52 @@ class Bans {
list($ipv4, $bits) = explode('/', $mask);
if ($bits > 32)
return false;
list($ipstart, $ipend) = self::calc_cidr($mask);
} elseif (preg_match('@^[:a-z\d]+/\d+$@i', $mask)) {
list($ipv6, $bits) = explode('/', $mask);
if ($bits > 128)
if ($bits > 128) {
return false;
}
list($ipstart, $ipend) = self::calc_cidr($mask);
} else {
if (($ipstart = @inet_pton($mask)) === false)
return false;
} elseif (($ipstart = @inet_pton($mask)) === false) {
return false;
}
return array($ipstart, $ipend);
}
static public function find($ip, $board = false, $get_mod_info = false) {
global $config;
$query = prepare('SELECT ``bans``.*' . ($get_mod_info ? ', `username`' : '') . ' FROM ``bans``
' . ($get_mod_info ? 'LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`' : '') . '
WHERE
(' . ($board !== false ? '(`board` IS NULL OR `board` = :board) AND' : '') . '
(`ipstart` = :ip OR (:ip >= `ipstart` AND :ip <= `ipend`)))
ORDER BY `expires` IS NULL, `expires` DESC');
if ($board !== false)
$query->bindValue(':board', $board, PDO::PARAM_STR);
$query->bindValue(':ip', inet_pton($ip));
$query->execute() or error(db_error($query));
$ban_list = array();
while ($ban = $query->fetch(PDO::FETCH_ASSOC)) {
if ($ban['expires'] && ($ban['seen'] || !$config['require_ban_view']) && $ban['expires'] < time()) {
self::delete($ban['id']);
} else {
if ($ban['post'])
if ($ban['post']) {
$ban['post'] = json_decode($ban['post'], true);
}
$ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
$ban_list[] = $ban;
}
}
return $ban_list;
}
@ -153,16 +152,18 @@ class Bans {
$query = query("SELECT ``bans``.*, `username` FROM ``bans``
LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`
ORDER BY `created` DESC") or error(db_error());
$bans = $query->fetchAll(PDO::FETCH_ASSOC);
$bans = $query->fetchAll(PDO::FETCH_ASSOC);
if ($board_access && $board_access[0] == '*') $board_access = false;
if ($board_access && $board_access[0] == '*') {
$board_access = false;
}
$out ? fputs($out, "[") : print("[");
$end = end($bans);
foreach ($bans as &$ban) {
$ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
foreach ($bans as &$ban) {
$ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
$hide_message = false;
foreach ($hide_regexes as $regex) {
@ -174,7 +175,7 @@ class Bans {
if ($ban['post'] && !$hide_message) {
$post = json_decode($ban['post']);
$ban['message'] = $post->body;
$ban['message'] = isset($post->body) ? $post->body : 0;
}
unset($ban['ipstart'], $ban['ipend'], $ban['post'], $ban['creator']);
@ -186,7 +187,7 @@ class Bans {
$ban['single_addr'] = true;
}
if ($filter_staff || ($board_access !== false && !in_array($ban['board'], $board_access))) {
$ban['username'] = '?';
$ban['username'] = '?';
}
if ($filter_ips || ($board_access !== false && !in_array($ban['board'], $board_access))) {
@list($ban['mask'], $subnet) = explode("/", $ban['mask']);
@ -208,24 +209,25 @@ class Bans {
}
}
$out ? fputs($out, "]") : print("]");
$out ? fputs($out, "]") : print("]");
}
}
static public function seen($ban_id) {
$query = query("UPDATE ``bans`` SET `seen` = 1 WHERE `id` = " . (int)$ban_id) or error(db_error());
rebuildThemes('bans');
}
static public function purge() {
$query = query("DELETE FROM ``bans`` WHERE `expires` IS NOT NULL AND `expires` < " . time() . " AND `seen` = 1") or error(db_error());
query("UPDATE ``bans`` SET `seen` = 1 WHERE `id` = " . (int)$ban_id) or error(db_error());
rebuildThemes('bans');
}
static public function purge() {
query("DELETE FROM ``bans`` WHERE `expires` IS NOT NULL AND `expires` < " . time() . " AND `seen` = 1") or error(db_error());
rebuildThemes('bans');
}
static public function delete($ban_id, $modlog = false, $boards = false, $dont_rebuild = false) {
global $config;
if ($boards && $boards[0] == '*') $boards = false;
if ($boards && $boards[0] == '*') {
$boards = false;
}
if ($modlog) {
$query = query("SELECT `ipstart`, `ipend`, `board` FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
@ -234,50 +236,55 @@ class Bans {
return false;
}
if ($boards !== false && !in_array($ban['board'], $boards))
error($config['error']['noaccess']);
if ($boards !== false && !in_array($ban['board'], $boards)) {
error($config['error']['noaccess']);
}
$mask = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
modLog("Removed ban #{$ban_id} for " .
(filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : $mask));
}
query("DELETE FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
if (!$dont_rebuild) rebuildThemes('bans');
if (!$dont_rebuild) {
rebuildThemes('bans');
}
return true;
}
static public function new_ban($mask, $reason, $length = false, $ban_board = false, $mod_id = false, $post = false) {
global $mod, $pdo, $board;
if ($mod_id === false) {
$mod_id = isset($mod['id']) ? $mod['id'] : -1;
}
$range = self::parse_range($mask);
$mask = self::range_to_string($range);
$query = prepare("INSERT INTO ``bans`` VALUES (NULL, :ipstart, :ipend, :time, :expires, :board, :mod, :reason, 0, :post)");
$query->bindValue(':ipstart', $range[0]);
if ($range[1] !== false && $range[1] != $range[0])
if ($range[1] !== false && $range[1] != $range[0]) {
$query->bindValue(':ipend', $range[1]);
else
} else {
$query->bindValue(':ipend', null, PDO::PARAM_NULL);
}
$query->bindValue(':mod', $mod_id);
$query->bindValue(':time', time());
if ($reason !== '') {
$reason = escape_markup_modifiers($reason);
markup($reason);
$query->bindValue(':reason', $reason);
} else
} else {
$query->bindValue(':reason', null, PDO::PARAM_NULL);
}
if ($length) {
if (is_int($length) || ctype_digit($length)) {
$length = time() + $length;
@ -288,31 +295,30 @@ class Bans {
} else {
$query->bindValue(':expires', null, PDO::PARAM_NULL);
}
if ($ban_board)
if ($ban_board) {
$query->bindValue(':board', $ban_board);
else
} else {
$query->bindValue(':board', null, PDO::PARAM_NULL);
}
if ($post) {
$post['board'] = $board['uri'];
$query->bindValue(':post', json_encode($post));
} else
} else {
$query->bindValue(':post', null, PDO::PARAM_NULL);
$query->execute() or error(db_error($query));
if (isset($mod['id']) && $mod['id'] == $mod_id) {
modLog('Created a new ' .
($length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent') .
' ban on ' .
($ban_board ? '/' . $ban_board . '/' : 'all boards') .
' for ' .
(filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : $mask) .
' (<small>#' . $pdo->lastInsertId() . '</small>)' .
' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
}
$query->execute() or error(db_error($query));
$ban_len = $length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent';
$ban_board = $ban_board ? "/$ban_board/" : 'all boards';
$ban_ip = filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : $mask;
$ban_id = $pdo->lastInsertId();
$ban_reason = $reason ? 'reason: ' . utf8tohtml($reason) : 'no reason';
modLog("Created a new $ban_len ban on $ban_board for $ban_ip (<small># $ban_id </small>) with $ban_reason");
rebuildThemes('bans');
return $pdo->lastInsertId();

3
inc/bootstrap.php Normal file
View File

@ -0,0 +1,3 @@
<?php
@define('TINYBOARD', 'xD');
require_once('vendor/autoload.php');

View File

@ -118,11 +118,15 @@ class Cache {
switch ($config['cache']['enabled']) {
case 'memcached':
case 'redis':
if (!self::$cache)
self::init();
self::$cache->delete($key);
break;
case 'redis':
if (!self::$cache)
self::init();
self::$cache->del($key);
break;
case 'apc':
apc_delete($key);
break;

View File

@ -0,0 +1,90 @@
<?php
/**
Securimage sample config file (rename to config.inc.php to activate)
Place your custom configuration in this file to make settings global so they
are applied to the captcha image, audio playback, and validation.
Using this file is optional but makes settings managing settings easier,
especially when upgrading to a new version.
When a new Securimage object is created, if config.inc.php is found in the
Securimage directory, these settings will be applied *before* any settings
passed to the constructor (so options passed in will override these).
This file is especially useful if you use a custom database or session
configuration and is easier than modifying securimage.php directly.
Any class property from securimage.php can be used here.
*/
return array(
/**** CAPTCHA Appearance Options ****/
'image_width' => 275, // width of captcha image in pixels
'image_height' => 100, // height of captcha image in pixels
'code_length' => 6, // # of characters for captcha code
'image_bg_color' => '#770000', // hex color for image background
'text_color' => '#DDDD64', // hex color for captcha text
'line_color' => '#DDDD64', // hex color for lines over text
'noise_color' => '#DDDD64', // color of random noise to draw under text
'num_lines' => 5, // # of lines to draw over text
'noise_level' => 0.5, // how much random noise to add (0-10)
'perturbation' => 0.75, // distoration level
'use_random_spaces' => true,
'use_random_baseline' => true,
'use_text_angles' => true,
'use_random_boxes' => false,
'use_transparent_text' => false,
'wordlist_file' => 'words/words.txt', // text file for word captcha
'use_wordlist' => false, // true to use word list
'wordlist_file_encoding' => null, // character encoding of word file if other than ASCII (e.g. UTF-8, GB2312)
// example UTF-8 charset (TTF file must support symbols being used
// 'charset' => "абвгдeжзийклмнопрстуфхцчшщъьюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ",
'charset' => "2345689abdfgkmnpqsuwxyz", // capitals are more effort to type, removed confusable characters like o,O,0,1,l
// 'ttf_file' => './AHGBold.ttf', // TTF file for captcha text
//'captcha_type' => Securimage::SI_CAPTCHA_WORDS, // Securimage::SI_CAPTCHA_STRING || Securimage:: SI_CAPTCHA_MATHEMATIC || Securimage::SI_CAPTCHA_WORDS
//'display_value' => 'ABC 123', // Draws custom text on captcha
/**** Code Storage & Database Options ****/
// true if you *DO NOT* want to use PHP sessions at all, false to use PHP sessions
'no_session' => true,
// the PHP session name to use (null for default PHP session name)
// do not change unless you know what you are doing
'session_name' => null,
// change to true to store codes in a database
'use_database' => true,
// database engine to use for storing codes. must have the PDO extension loaded
// Values choices are:
// Securimage::SI_DRIVER_MYSQL, Securimage::SI_DRIVER_SQLITE3, Securimage::SI_DRIVER_PGSQL
'database_driver' => Securimage::SI_DRIVER_MYSQL,
'database_host' => 'localhost', // database server host to connect to
'database_user' => 'lainchan', // database user to connect as
'database_pass' => '', // database user password
'database_name' => 'lainchan', // name of database to select (you must create this first or use an existing database)
'database_table' => 'captcha_codes', // database table for storing codes, will be created automatically
// Securimage will automatically create the database table if it is not found
// change to true for performance reasons once database table is up and running
'skip_table_check' => false,
/**** Audio Options ****/
//'audio_path' => __DIR__ . '/audio/en/',
//'audio_use_noise' => true,
//'audio_noise_path' => __DIR__ . '/audio/noise/',
//'degrade_audio' => true,
'no_exit'=>true,
'log_file'=>'/dev/null', //This should be placed somewhere sensible.
);

File diff suppressed because it is too large Load Diff

108
inc/controller.php Normal file
View File

@ -0,0 +1,108 @@
<?php
// This file contains the controller part of vichan
// don't bother with that unless you use smart build or advanced build
// you can use those parts for your own implementations though :^)
defined('TINYBOARD') or exit;
function sb_board($b, $page = 1) { global $config, $build_pages; $page = (int)$page;
if ($page < 1) return false;
if (!openBoard($b)) return false;
if ($page > $config['max_pages']) return false;
$config['try_smarter'] = true;
$build_pages = array($page);
buildIndex("skip");
return true;
}
function sb_api_board($b, $page = 0) { $page = (int)$page;
return sb_board($b, $page + 1);
}
function sb_thread($b, $thread, $slugcheck = false) { global $config; $thread = (int)$thread;
if ($thread < 1) return false;
if (!preg_match('/^'.$config['board_regex'].'$/u', $b)) return false;
if (Cache::get("thread_exists_".$b."_".$thread) == "no") return false;
$query = prepare(sprintf("SELECT MAX(`id`) AS `max` FROM ``posts_%s``", $b));
if (!$query->execute()) return false;
$s = $query->fetch(PDO::FETCH_ASSOC);
$max = $s['max'];
if ($thread > $max) return false;
$query = prepare(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL", $b));
$query->bindValue(':id', $thread);
if (!$query->execute() || !$query->fetch(PDO::FETCH_ASSOC) ) {
Cache::set("thread_exists_".$b."_".$thread, "no", 3600);
return false;
}
if ($slugcheck && $config['slugify']) {
global $request;
$link = link_for(array("id" => $thread), $slugcheck === 50, array("uri" => $b));
$link = "/".$b."/".$config['dir']['res'].$link;
if ($link != $request) {
header("Location: $link", true, 301);
die();
}
}
if ($slugcheck == 50) { // Should we really generate +50 page? Maybe there are not enough posts anyway
global $request;
$r = str_replace("+50", "", $request);
$r = substr($r, 1); // Cut the slash
if (file_exists($r)) return false;
}
if (!openBoard($b)) return false;
buildThread($thread);
return true;
}
function sb_thread_slugcheck($b, $thread) {
return sb_thread($b, $thread, true);
}
function sb_thread_slugcheck50($b, $thread) {
return sb_thread($b, $thread, 50);
}
function sb_api($b) { global $config, $build_pages;
if (!openBoard($b)) return false;
$config['try_smarter'] = true;
$build_pages = array(-1);
buildIndex();
return true;
}
function sb_ukko() {
rebuildTheme("ukko", "post-thread");
return true;
}
function sb_catalog($b) {
if (!openBoard($b)) return false;
rebuildTheme("catalog", "post-thread", $b);
return true;
}
function sb_recent() {
rebuildTheme("recent", "post-thread");
return true;
}
function sb_sitemap() {
rebuildTheme("sitemap", "all");
return true;
}

View File

@ -69,19 +69,23 @@ function sql_open() {
try {
$options = array(
PDO::ATTR_TIMEOUT => $config['db']['timeout'],
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
);
if ($config['db']['type'] == "mysql")
$options[PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = true;
if ($config['db']['persistent'])
$options[PDO::ATTR_PERSISTENT] = true;
$pdo = new PDO($dsn, $config['db']['user'], $config['db']['password'], $options);
if ($config['debug'])
$debug['time']['db_connect'] = '~' . round((microtime(true) - $start) * 1000, 2) . 'ms';
if (mysql_version() >= 50503)
query('SET NAMES utf8mb4') or error(db_error());
else
query('SET NAMES utf8') or error(db_error());
if ($config['db']['type'] == "mysql"){
if (mysql_version() >= 50503)
query('SET NAMES utf8mb4') or error(db_error());
else
query('SET NAMES utf8') or error(db_error());
}
return $pdo;
} catch(PDOException $e) {
$message = $e->getMessage();
@ -95,15 +99,10 @@ function sql_open() {
}
}
// 5.6.10 becomes 50610
// 5.6.10 becomes 50610 HACK: hardcoded to be above critical value 50803 due to laziness
function mysql_version() {
global $pdo;
$version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
$v = explode('.', $version);
if (count($v) != 3)
return false;
return (int) sprintf("%02d%02d%02d", $v[0], $v[1], $v[2]);
// TODO delete all references of this function everywhere
return 80504;
}
function prepare($query) {

View File

@ -5,395 +5,418 @@
*/
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
// You cannot request this file directly.
exit;
}
/*
joaoptm78@gmail.com
http://www.php.net/manual/en/function.filesize.php#100097
joaoptm78@gmail.com
http://www.php.net/manual/en/function.filesize.php#100097
*/
function format_bytes($size) {
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
function doBoardListPart($list, $root, &$boards) {
global $config;
$body = '';
foreach ($list as $key => $board) {
if (is_array($board))
$body .= ' <span class="sub" data-description="' . $key . '">[' . doBoardListPart($board, $root, $boards) . ']</span> ';
else {
if (gettype($key) == 'string') {
$body .= ' <a href="' . $board . '">' . $key . '</a> /';
} else {
$title = '';
if (isset ($boards[$board])) {
$title = ' title="'.$boards[$board].'"';
}
$body .= ' <a href="' . $root . $board . '/' . $config['file_index'] . '"'.$title.'>' . $board . '</a> /';
}
}
}
$body = preg_replace('/\/$/', '', $body);
return $body;
global $config;
$body = '';
foreach ($list as $key => $board) {
if (is_array($board))
$body .= ' <span class="sub" data-description="' . $key . '">[' . doBoardListPart($board, $root, $boards) . ']</span> ';
else {
if (gettype($key) == 'string') {
$body .= ' <a href="' . $board . '">' . $key . '</a> /';
} else {
$title = '';
if (array_key_exists($board,$config['boards_alias'])){
$actual_board = $config['boards_alias'][$board];
if (isset ($boards[$actual_board])) {
$title = ' title="'.$boards[$actual_board].'"';
}
$body .= ' <a href="' . $root . $actual_board . '/' . $config['file_index'] . '"'.$title.'>' . $board . '</a> /';
}
else
{
if (isset ($boards[$board])) {
$title = ' title="'.$boards[$board].'"';
}
$body .= ' <a href="' . $root . $board . '/' . $config['file_index'] . '"'.$title.'>' . $board . '</a> /';
}
}
}
}
$body = preg_replace('/\/$/', '', $body);
return $body;
}
function createBoardlist($mod=false) {
global $config;
if (!isset($config['boards'])) return array('top'=>'','bottom'=>'');
$xboards = listBoards();
$boards = array();
foreach ($xboards as $val) {
$boards[$val['uri']] = $val['title'];
}
global $config;
if (!isset($config['boards'])) return array('top'=>'','bottom'=>'');
$xboards = listBoards();
$boards = array();
foreach ($xboards as $val) {
$boards[$val['uri']] = $val['title'];
}
$body = doBoardListPart($config['boards'], $mod?'?/':$config['root'], $boards);
$body = doBoardListPart($config['boards'], $mod?'?/':$config['root'], $boards);
if ($config['boardlist_wrap_bracket'] && !preg_match('/\] $/', $body))
$body = '[' . $body . ']';
$body = trim($body);
if ($config['boardlist_wrap_bracket'] && !preg_match('/\] $/', $body))
$body = '[' . $body . ']';
$body = trim($body);
// Message compact-boardlist.js faster, so that page looks less ugly during loading
$top = "<script type='text/javascript'>if (typeof do_boardlist != 'undefined') do_boardlist();</script>";
return array(
'top' => '<div class="boardlist">' . $body . '</div>' . $top,
'bottom' => '<div class="boardlist bottom">' . $body . '</div>'
);
// Message compact-boardlist.js faster, so that page looks less ugly during loading
$top = "<script type='text/javascript'>if (typeof do_boardlist != 'undefined') do_boardlist();</script>";
return array(
'top' => '<div class="boardlist">' . $body . '</div>' . $top,
'bottom' => '<div class="boardlist bottom">' . $body . '</div>'
);
}
function loginForm($error=false, $username=false, $redirect=false) {
global $config;
die(Element('page.html', array(
'index' => $config['root'],
'title' => _('Login'),
'config' => $config,
'body' => Element('login.html', array(
'config'=>$config,
'error'=>$error,
'username'=>utf8tohtml($username),
'redirect'=>$redirect
)
)
)));
global $config;
die(Element('page.html', array(
'index' => $config['root'],
'title' => _('Login'),
'config' => $config,
'body' => Element('login.html', array(
'config'=>$config,
'error'=>$error,
'username'=>utf8tohtml($username),
'redirect'=>$redirect
)
)
)));
}
function pm_snippet($body, $len=null) {
global $config;
if (!isset($len))
$len = &$config['mod']['snippet_length'];
// Replace line breaks with some whitespace
$body = preg_replace('@<br/?>@i', ' ', $body);
// Strip tags
$body = strip_tags($body);
// Unescape HTML characters, to avoid splitting them in half
$body = html_entity_decode($body, ENT_COMPAT, 'UTF-8');
// calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body);
$body = mb_substr($body, 0, $len);
// Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
global $config;
if (!isset($len))
$len = &$config['mod']['snippet_length'];
// Replace line breaks with some whitespace
$body = preg_replace('@<br/?>@i', ' ', $body);
// Strip tags but leave span tags which contain spoiler
$body_with_spoiler_tags = strip_tags($body,'<span>');
// Check for spoiler tags
$spoiler = preg_match("/spoiler/", $body_with_spoiler_tags);
// Strip tags
$body = strip_tags($body);
// Unescape HTML characters, to avoid splitting them in half
$body = html_entity_decode($body, ENT_COMPAT, 'UTF-8');
// calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body);
$body = mb_substr($body, 0, $len);
if ($spoiler){
$value = "<span class=\"spoiler\">" . utf8tohtml($body) . "</span>";
}
else {
$value = utf8tohtml($body);
}
// Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
}
function capcode($cap) {
global $config;
if (!$cap)
return false;
$capcode = array();
if (isset($config['custom_capcode'][$cap])) {
if (is_array($config['custom_capcode'][$cap])) {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap][0], $cap);
if (isset($config['custom_capcode'][$cap][1]))
$capcode['name'] = $config['custom_capcode'][$cap][1];
if (isset($config['custom_capcode'][$cap][2]))
$capcode['trip'] = $config['custom_capcode'][$cap][2];
} else {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap], $cap);
}
} else {
$capcode['cap'] = sprintf($config['capcode'], $cap);
}
return $capcode;
global $config;
if (!$cap)
return false;
$capcode = array();
if (isset($config['custom_capcode'][$cap])) {
if (is_array($config['custom_capcode'][$cap])) {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap][0], $cap);
if (isset($config['custom_capcode'][$cap][1]))
$capcode['name'] = $config['custom_capcode'][$cap][1];
if (isset($config['custom_capcode'][$cap][2]))
$capcode['trip'] = $config['custom_capcode'][$cap][2];
} else {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap], $cap);
}
} else {
$capcode['cap'] = sprintf($config['capcode'], $cap);
}
return $capcode;
}
function truncate($body, $url, $max_lines = false, $max_chars = false) {
global $config;
if ($max_lines === false)
$max_lines = $config['body_truncate'];
if ($max_chars === false)
$max_chars = $config['body_truncate_char'];
// We don't want to risk truncating in the middle of an HTML comment.
// It's easiest just to remove them all first.
$body = preg_replace('/<!--.*?-->/s', '', $body);
$original_body = $body;
$lines = substr_count($body, '<br/>');
// Limit line count
if ($lines > $max_lines) {
if (preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m))
$body = $m[0];
}
$body = mb_substr($body, 0, $max_chars);
if ($body != $original_body) {
// Remove any corrupt tags at the end
$body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body);
// Open tags
if (preg_match_all('/<([\w]+)[^>]*>/', $body, $open_tags)) {
$tags = array();
for ($x=0;$x<count($open_tags[0]);$x++) {
if (!preg_match('/\/(\s+)?>$/', $open_tags[0][$x]))
$tags[] = $open_tags[1][$x];
}
// List successfully closed tags
if (preg_match_all('/(<\/([\w]+))>/', $body, $closed_tags)) {
for ($x=0;$x<count($closed_tags[0]);$x++) {
unset($tags[array_search($closed_tags[2][$x], $tags)]);
}
}
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
$tags_no_close_needed = array("colgroup", "dd", "dt", "li", "optgroup", "option", "p", "tbody", "td", "tfoot", "th", "thead", "tr", "br", "img");
// Close any open tags
foreach ($tags as &$tag) {
if (!in_array($tag, $tags_no_close_needed))
$body .= "</{$tag}>";
}
} else {
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]*$/', '', $body);
}
$body .= '<span class="toolong">'.sprintf(_('Post too long. Click <a href="%s">here</a> to view the full text.'), $url).'</span>';
}
return $body;
global $config;
if ($max_lines === false)
$max_lines = $config['body_truncate'];
if ($max_chars === false)
$max_chars = $config['body_truncate_char'];
// We don't want to risk truncating in the middle of an HTML comment.
// It's easiest just to remove them all first.
$body = preg_replace('/<!--.*?-->/s', '', $body);
$original_body = $body;
$lines = substr_count($body, '<br/>');
// Limit line count
if ($lines > $max_lines) {
if (preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m))
$body = $m[0];
}
$body = mb_substr($body, 0, $max_chars);
if ($body != $original_body) {
// Remove any corrupt tags at the end
$body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body);
// Open tags
if (preg_match_all('/<([\w]+)[^>]*>/', $body, $open_tags)) {
$tags = array();
for ($x=0;$x<count($open_tags[0]);$x++) {
if (!preg_match('/\/(\s+)?>$/', $open_tags[0][$x]))
$tags[] = $open_tags[1][$x];
}
// List successfully closed tags
if (preg_match_all('/(<\/([\w]+))>/', $body, $closed_tags)) {
for ($x=0;$x<count($closed_tags[0]);$x++) {
unset($tags[array_search($closed_tags[2][$x], $tags)]);
}
}
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
$tags_no_close_needed = array("colgroup", "dd", "dt", "li", "optgroup", "option", "p", "tbody", "td", "tfoot", "th", "thead", "tr", "br", "img");
// Close any open tags
foreach ($tags as &$tag) {
if (!in_array($tag, $tags_no_close_needed))
$body .= "</{$tag}>";
}
} else {
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]*$/', '', $body);
}
$body .= '<span class="toolong">'.sprintf(_('Post too long. Click <a href="%s">here</a> to view the full text.'), $url).'</span>';
}
return $body;
}
function bidi_cleanup($data) {
// Closes all embedded RTL and LTR unicode formatting blocks in a string so that
// it can be used inside another without controlling its direction.
// Closes all embedded RTL and LTR unicode formatting blocks in a string so that
// it can be used inside another without controlling its direction.
$explicits = '\xE2\x80\xAA|\xE2\x80\xAB|\xE2\x80\xAD|\xE2\x80\xAE';
$pdf = '\xE2\x80\xAC';
preg_match_all("!$explicits!", $data, $m1, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
preg_match_all("!$pdf!", $data, $m2, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
if (count($m1) || count($m2)){
$p = array();
foreach ($m1 as $m){ $p[$m[0][1]] = 'push'; }
foreach ($m2 as $m){ $p[$m[0][1]] = 'pop'; }
ksort($p);
$offset = 0;
$stack = 0;
foreach ($p as $pos => $type){
if ($type == 'push'){
$stack++;
}else{
if ($stack){
$stack--;
}else{
# we have a pop without a push - remove it
$data = substr($data, 0, $pos-$offset)
.substr($data, $pos+3-$offset);
$offset += 3;
}
}
}
# now add some pops if your stack is bigger than 0
for ($i=0; $i<$stack; $i++){
$data .= "\xE2\x80\xAC";
}
return $data;
}
return $data;
$explicits = '\xE2\x80\xAA|\xE2\x80\xAB|\xE2\x80\xAD|\xE2\x80\xAE';
$pdf = '\xE2\x80\xAC';
preg_match_all("!$explicits!", $data, $m1, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
preg_match_all("!$pdf!", $data, $m2, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
if (count($m1) || count($m2)){
$p = array();
foreach ($m1 as $m){ $p[$m[0][1]] = 'push'; }
foreach ($m2 as $m){ $p[$m[0][1]] = 'pop'; }
ksort($p);
$offset = 0;
$stack = 0;
foreach ($p as $pos => $type){
if ($type == 'push'){
$stack++;
}else{
if ($stack){
$stack--;
}else{
# we have a pop without a push - remove it
$data = substr($data, 0, $pos-$offset)
.substr($data, $pos+3-$offset);
$offset += 3;
}
}
}
# now add some pops if your stack is bigger than 0
for ($i=0; $i<$stack; $i++){
$data .= "\xE2\x80\xAC";
}
return $data;
}
return $data;
}
function secure_link_confirm($text, $title, $confirm_message, $href) {
global $config;
global $config;
return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlspecialchars(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlspecialchars(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
}
function secure_link($href) {
return $href . '/' . make_secure_link_token($href);
return $href . '/' . make_secure_link_token($href);
}
function embed_html($link) {
global $config;
foreach ($config['embedding'] as $embed) {
if ($html = preg_replace($embed[0], $embed[1], $link)) {
if ($html == $link)
continue; // Nope
$html = str_replace('%%tb_width%%', $config['embed_width'], $html);
$html = str_replace('%%tb_height%%', $config['embed_height'], $html);
return $html;
}
}
if ($link[0] == '<') {
// Prior to v0.9.6-dev-8, HTML code for embedding was stored in the database instead of the link.
return $link;
}
return 'Embedding error.';
global $config;
foreach ($config['embedding'] as $embed) {
if ($html = preg_replace($embed[0], $embed[1], $link)) {
if ($html == $link)
continue; // Nope
$html = str_replace('%%tb_width%%', $config['embed_width'], $html);
$html = str_replace('%%tb_height%%', $config['embed_height'], $html);
return $html;
}
}
if ($link[0] == '<') {
// Prior to v0.9.6-dev-8, HTML code for embedding was stored in the database instead of the link.
return $link;
}
return 'Embedding error.';
}
class Post {
public function __construct($post, $root=null, $mod=false) {
global $config;
if (!isset($root))
$root = &$config['root'];
foreach ($post as $key => $value) {
$this->{$key} = $value;
}
public function __construct($post, $root=null, $mod=false) {
global $config;
if (!isset($root))
$root = &$config['root'];
foreach ($post as $key => $value) {
$this->{$key} = $value;
}
if (isset($this->files) && $this->files)
$this->files = @json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
$this->mod = $mod;
$this->root = $root;
if ($this->embed)
$this->embed = embed_html($this->embed);
$this->modifiers = extract_modifiers($this->body_nomarkup);
if ($config['always_regenerate_markup']) {
$this->body = $this->body_nomarkup;
markup($this->body);
}
if ($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '', $page = false) {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
}
public function build($index=false) {
global $board, $config;
return Element('post_reply.html', array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'mod' => $this->mod));
}
if (isset($this->files) && $this->files)
$this->files = @json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
$this->mod = $mod;
$this->root = $root;
if ($this->embed)
$this->embed = embed_html($this->embed);
$this->modifiers = extract_modifiers($this->body_nomarkup);
if ($config['always_regenerate_markup']) {
$this->body = $this->body_nomarkup;
markup($this->body);
}
if ($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '', $page = false) {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
}
public function build($index=false) {
global $board, $config;
return Element('post_reply.html', array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'mod' => $this->mod));
}
};
class Thread {
public function __construct($post, $root = null, $mod = false, $hr = true) {
global $config;
if (!isset($root))
$root = &$config['root'];
foreach ($post as $key => $value) {
$this->{$key} = $value;
}
if (isset($this->files))
$this->files = @json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
$this->mod = $mod;
$this->root = $root;
$this->hr = $hr;
public function __construct($post, $root = null, $mod = false, $hr = true) {
global $config;
if (!isset($root))
$root = &$config['root'];
foreach ($post as $key => $value) {
$this->{$key} = $value;
}
if (isset($this->files))
$this->files = @json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
$this->mod = $mod;
$this->root = $root;
$this->hr = $hr;
$this->posts = array();
$this->omitted = 0;
$this->omitted_images = 0;
if ($this->embed)
$this->embed = embed_html($this->embed);
$this->modifiers = extract_modifiers($this->body_nomarkup);
if ($config['always_regenerate_markup']) {
$this->body = $this->body_nomarkup;
markup($this->body);
}
if ($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '', $page = false) {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
}
public function add(Post $post) {
$this->posts[] = $post;
}
public function postCount() {
return count($this->posts) + $this->omitted;
}
public function build($index=false, $isnoko50=false) {
global $board, $config, $debug;
$hasnoko50 = $this->postCount() >= $config['noko50_min'];
event('show-thread', $this);
$this->posts = array();
$this->omitted = 0;
$this->omitted_images = 0;
if ($this->embed)
$this->embed = embed_html($this->embed);
$this->modifiers = extract_modifiers($this->body_nomarkup);
if ($config['always_regenerate_markup']) {
$this->body = $this->body_nomarkup;
markup($this->body);
}
if ($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), $config['board_regex']) . ')/u',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '', $page = false) {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . link_for((array)$this, $page == '50') . '#' . $pre . $this->id;
}
public function add(Post $post) {
$this->posts[] = $post;
}
public function postCount() {
return count($this->posts) + $this->omitted;
}
public function build($index=false, $isnoko50=false) {
global $board, $config, $debug;
$hasnoko50 = $this->postCount() >= $config['noko50_min'];
event('show-thread', $this);
$file = ($index && $config['file_board']) ? 'post_thread_fileboard.html' : 'post_thread.html';
$built = Element($file, array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'hasnoko50' => $hasnoko50, 'isnoko50' => $isnoko50, 'mod' => $this->mod));
return $built;
}
$file = ($index && $config['file_board']) ? 'post_thread_fileboard.html' : 'post_thread.html';
$built = Element($file, array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'hasnoko50' => $hasnoko50, 'isnoko50' => $isnoko50, 'mod' => $this->mod));
return $built;
}
};

View File

@ -1,4 +1,4 @@
<?PHP
<?php
function error_handler($errno,$errstr,$errfile, $errline, $errcontext){
if(error_reporting() & $errno){
@ -8,7 +8,7 @@ function error_handler($errno,$errstr,$errfile, $errline, $errcontext){
return false;
}
function exception_handler(Exception $e){
function exception_handler($e){
error($e->getMessage());
}
@ -22,6 +22,8 @@ function fatal_error_handler(){
register_shutdown_function('fatal_error_handler');
// Due to composer autoload, this isn't implicitly global anymore
global $error_recursion;
$error_recursion=false;
function error($message, $priority = true, $debug_stuff = false) {

View File

@ -7,243 +7,240 @@
defined('TINYBOARD') or exit;
class Filter {
public $flood_check;
private $condition;
private $post;
public function __construct(array $arr) {
foreach ($arr as $key => $value)
$this->$key = $value;
}
public function match($condition, $match) {
$condition = strtolower($condition);
public $flood_check;
private $condition;
private $post;
public function __construct(array $arr) {
foreach ($arr as $key => $value)
$this->$key = $value;
}
public function match($condition, $match) {
$condition = strtolower($condition);
$post = &$this->post;
switch($condition) {
case 'custom':
if (!is_callable($match))
error('Custom condition for filter is not callable!');
return $match($post);
case 'flood-match':
if (!is_array($match))
error('Filter condition "flood-match" must be an array.');
// Filter out "flood" table entries which do not match this filter.
$flood_check_matched = array();
foreach ($this->flood_check as $flood_post) {
foreach ($match as $flood_match_arg) {
switch ($flood_match_arg) {
case 'ip':
if ($flood_post['ip'] != $_SERVER['REMOTE_ADDR'])
continue 3;
break;
case 'body':
if ($flood_post['posthash'] != make_comment_hex($post['body_nomarkup']))
continue 3;
break;
case 'file':
if (!isset($post['filehash']))
return false;
if ($flood_post['filehash'] != $post['filehash'])
continue 3;
break;
case 'board':
if ($flood_post['board'] != $post['board'])
continue 3;
break;
case 'isreply':
if ($flood_post['isreply'] == $post['op'])
continue 3;
break;
default:
error('Invalid filter flood condition: ' . $flood_match_arg);
}
}
$flood_check_matched[] = $flood_post;
}
$this->flood_check = $flood_check_matched;
return !empty($this->flood_check);
case 'flood-time':
foreach ($this->flood_check as $flood_post) {
if (time() - $flood_post['time'] <= $match) {
return true;
}
}
return false;
case 'flood-count':
$count = 0;
foreach ($this->flood_check as $flood_post) {
if (time() - $flood_post['time'] <= $this->condition['flood-time']) {
++$count;
}
}
return $count >= $match;
case 'name':
return preg_match($match, $post['name']);
case 'trip':
return $match === $post['trip'];
case 'email':
return preg_match($match, $post['email']);
case 'subject':
return preg_match($match, $post['subject']);
case 'body':
return preg_match($match, $post['body_nomarkup']);
case 'filehash':
return $match === $post['filehash'];
case 'filename':
if (!$post['files'])
return false;
$post = &$this->post;
switch($condition) {
case 'custom':
if (!is_callable($match))
error('Custom condition for filter is not callable!');
return $match($post);
case 'flood-match':
if (!is_array($match))
error('Filter condition "flood-match" must be an array.');
// Filter out "flood" table entries which do not match this filter.
$flood_check_matched = array();
foreach ($this->flood_check as $flood_post) {
foreach ($match as $flood_match_arg) {
switch ($flood_match_arg) {
case 'ip':
if ($flood_post['ip'] != $_SERVER['REMOTE_ADDR'])
continue 3;
break;
case 'body':
if ($flood_post['posthash'] != make_comment_hex($post['body_nomarkup']))
continue 3;
break;
case 'file':
if (!isset($post['filehash']))
return false;
if ($flood_post['filehash'] != $post['filehash'])
continue 3;
break;
case 'board':
if ($flood_post['board'] != $post['board'])
continue 3;
break;
case 'isop':
if ($flood_post['isreply'] != '0')
continue 3;
break;
case 'isreply':
if ($flood_post['isreply'] != '1')
continue 3;
break;
default:
error('Invalid filter flood condition: ' . $flood_match_arg);
}
}
$flood_check_matched[] = $flood_post;
}
// is there any reason for this assignment?
$this->flood_check = $flood_check_matched;
return !empty($this->flood_check);
case 'flood-time':
foreach ($this->flood_check as $flood_post) {
if (time() - $flood_post['time'] <= $match) {
return true;
}
}
return false;
case 'flood-count':
$count = 0;
foreach ($this->flood_check as $flood_post) {
if (time() - $flood_post['time'] <= $this->condition['flood-time']) {
++$count;
}
}
return $count >= $match;
case 'name':
return preg_match($match, $post['name']);
case 'trip':
return $match === $post['trip'];
case 'email':
return preg_match($match, $post['email']);
case 'subject':
return preg_match($match, $post['subject']);
case 'body':
return preg_match($match, $post['body_nomarkup']);
case 'filehash':
return $match === $post['filehash'];
case 'filename':
if (!$post['files'])
return false;
foreach ($post['files'] as $file) {
if (preg_match($match, $file['filename'])) {
return true;
}
}
return false;
case 'extension':
if (!$post['files'])
return false;
foreach ($post['files'] as $file) {
if (preg_match($match, $file['filename'])) {
return true;
}
}
return false;
case 'extension':
if (!$post['files'])
return false;
foreach ($post['files'] as $file) {
if (preg_match($match, $file['extension'])) {
return true;
}
}
return false;
case 'ip':
return preg_match($match, $_SERVER['REMOTE_ADDR']);
case 'op':
return $post['op'] == $match;
case 'has_file':
return $post['has_file'] == $match;
case 'board':
return $post['board'] == $match;
case 'password':
return $post['password'] == $match;
default:
error('Unknown filter condition: ' . $condition);
}
}
public function action() {
global $board;
foreach ($post['files'] as $file) {
if (preg_match($match, $file['extension'])) {
return true;
}
}
return false;
case 'ip':
return preg_match($match, $_SERVER['REMOTE_ADDR']);
case 'op':
return $post['op'] == $match;
case 'has_file':
return $post['has_file'] == $match;
case 'board':
return $post['board'] == $match;
case 'password':
return $post['password'] == $match;
default:
error('Unknown filter condition: ' . $condition);
}
}
public function action() {
global $board;
$this->add_note = isset($this->add_note) ? $this->add_note : false;
if ($this->add_note) {
$query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':mod', -1);
$query->bindValue(':time', time());
$query->bindValue(':body', "Autoban message: ".$this->post['body']);
$query->execute() or error(db_error($query));
}
if (isset ($this->action)) switch($this->action) {
case 'reject':
error(isset($this->message) ? $this->message : 'Posting throttled by filter.');
case 'ban':
if (!isset($this->reason))
error('The ban action requires a reason.');
$this->expires = isset($this->expires) ? $this->expires : false;
$this->reject = isset($this->reject) ? $this->reject : true;
$this->all_boards = isset($this->all_boards) ? $this->all_boards : false;
Bans::new_ban($_SERVER['REMOTE_ADDR'], $this->reason, $this->expires, $this->all_boards ? false : $board['uri'], -1);
$this->add_note = isset($this->add_note) ? $this->add_note : false;
if ($this->add_note) {
$query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':mod', -1);
$query->bindValue(':time', time());
$query->bindValue(':body', "Autoban message: ".$this->post['body']);
$query->execute() or error(db_error($query));
}
if (isset ($this->action)) switch($this->action) {
case 'reject':
error(isset($this->message) ? $this->message : 'Posting blocked by filter.');
case 'ban':
if (!isset($this->reason))
error('The ban action requires a reason.');
$this->expires = isset($this->expires) ? $this->expires : false;
$this->reject = isset($this->reject) ? $this->reject : true;
$this->all_boards = isset($this->all_boards) ? $this->all_boards : false;
Bans::new_ban($_SERVER['REMOTE_ADDR'], $this->reason, $this->expires, $this->all_boards ? false : $board['uri'], -1);
if ($this->reject) {
if (isset($this->message))
error($message);
checkBan($board['uri']);
exit;
}
break;
default:
error('Unknown filter action: ' . $this->action);
}
}
public function check(array $post) {
$this->post = $post;
foreach ($this->condition as $condition => $value) {
if ($condition[0] == '!') {
$NOT = true;
$condition = substr($condition, 1);
} else $NOT = false;
if ($this->match($condition, $value) == $NOT)
return false;
}
return true;
}
if ($this->reject) {
if (isset($this->message))
error($message);
checkBan($board['uri']);
exit;
}
break;
default:
error('Unknown filter action: ' . $this->action);
}
}
public function check(array $post) {
$this->post = $post;
foreach ($this->condition as $condition => $value) {
if ($condition[0] == '!') {
$NOT = true;
$condition = substr($condition, 1);
} else {
$NOT = false;
}
if ($this->match($condition, $value) == $NOT)
return false;
}
return true;
}
}
function purge_flood_table() {
global $config;
// Determine how long we need to keep a cache of posts for flood prevention. Unfortunately, it is not
// aware of flood filters in other board configurations. You can solve this problem by settings the
// config variable $config['flood_cache'] (seconds).
if (isset($config['flood_cache'])) {
$max_time = &$config['flood_cache'];
} else {
$max_time = 0;
foreach ($config['filters'] as $filter) {
if (isset($filter['condition']['flood-time']))
$max_time = max($max_time, $filter['condition']['flood-time']);
}
}
$time = time() - $max_time;
query("DELETE FROM ``flood`` WHERE `time` < $time") or error(db_error());
global $config;
// Determine how long we need to keep a cache of posts for flood prevention. Unfortunately, it is not
// aware of flood filters in other board configurations. You can solve this problem by settings the
// config variable $config['flood_cache'] (seconds).
if (isset($config['flood_cache'])) {
$max_time = &$config['flood_cache'];
} else {
$max_time = 0;
foreach ($config['filters'] as $filter) {
if (isset($filter['condition']['flood-time']))
$max_time = max($max_time, $filter['condition']['flood-time']);
}
}
$time = time() - $max_time;
query("DELETE FROM ``flood`` WHERE `time` < $time") or error(db_error());
}
function do_filters(array $post) {
global $config;
if (!isset($config['filters']) || empty($config['filters']))
return;
foreach ($config['filters'] as $filter) {
if (isset($filter['condition']['flood-match'])) {
$has_flood = true;
break;
}
}
if (isset($has_flood)) {
if ($post['has_file']) {
$query = prepare("SELECT * FROM ``flood`` WHERE `ip` = :ip OR `posthash` = :posthash OR `filehash` = :filehash");
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':posthash', make_comment_hex($post['body_nomarkup']));
$query->bindValue(':filehash', $post['filehash']);
} else {
$query = prepare("SELECT * FROM ``flood`` WHERE `ip` = :ip OR `posthash` = :posthash");
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':posthash', make_comment_hex($post['body_nomarkup']));
}
$query->execute() or error(db_error($query));
$flood_check = $query->fetchAll(PDO::FETCH_ASSOC);
} else {
$flood_check = false;
}
foreach ($config['filters'] as $filter_array) {
$filter = new Filter($filter_array);
$filter->flood_check = $flood_check;
if ($filter->check($post))
$filter->action();
}
purge_flood_table();
global $config;
if (!isset($config['filters']) || empty($config['filters']))
return;
foreach ($config['filters'] as $filter) {
if (isset($filter['condition']['flood-match'])) {
$has_flood = true;
}
}
if (isset($has_flood)) {
$query = prepare("SELECT * FROM ``flood``");
$query->execute() or error(db_error($query));
$flood_check = $query->fetchAll(PDO::FETCH_ASSOC);
} else {
$flood_check = false;
}
foreach ($config['filters'] as $filter_array) {
$filter = new Filter($filter_array);
$filter->flood_check = $flood_check;
if ($filter->check($post)) {
$filter->action();
}
}
purge_flood_table();
}

735
inc/functions.php Executable file → Normal file

File diff suppressed because it is too large Load Diff

17
inc/functions/net.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace Vichan\Functions\Net;
/**
* @return bool Returns if the client-server connection is an HTTPS one.
*/
function is_connection_https(): bool {
return !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
}
/**
* @return bool Returns if the client-server connection is an encrypted one (HTTPS or Tor loopback).
*/
function is_connection_secure(): bool {
return is_connection_https() || (!empty($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] === '127.0.0.1');
}

View File

@ -5,12 +5,13 @@
*/
defined('TINYBOARD') or exit;
require_once 'inc/polyfill.php';
class Image {
public $src, $format, $image, $size;
public function __construct($src, $format = false, $size = false) {
global $config;
$this->src = $src;
$this->format = $format;
@ -24,21 +25,21 @@ class Image {
error(_('Unsupported file format: ') . $this->format);
}
}
$this->image = new $classname($this, $size);
if (!$this->image->valid()) {
$this->delete();
error($config['error']['invalidimg']);
}
$this->size = (object)array('width' => $this->image->_width(), 'height' => $this->image->_height());
if ($this->size->width < 1 || $this->size->height < 1) {
$this->delete();
error($config['error']['invalidimg']);
}
}
public function resize($extension, $max_width, $max_height) {
global $config;
@ -62,16 +63,16 @@ class Image {
error(_('Unsupported file format: ') . $extension);
}
}
$thumb = new $classname(false);
$thumb->src = $this->src;
$thumb->format = $this->format;
$thumb->original_width = $this->size->width;
$thumb->original_height = $this->size->height;
$x_ratio = $max_width / $this->size->width;
$y_ratio = $max_height / $this->size->height;
if (($this->size->width <= $max_width) && ($this->size->height <= $max_height)) {
$width = $this->size->width;
$height = $this->size->height;
@ -82,16 +83,16 @@ class Image {
$width = ceil($y_ratio * $this->size->width);
$height = $max_height;
}
$thumb->_resize($this->image->image, $width, $height);
return $thumb;
}
public function to($dst) {
$this->image->to($dst);
}
public function delete() {
file_unlink($this->src);
}
@ -114,26 +115,26 @@ class ImageGD {
}
class ImageBase extends ImageGD {
public $image, $src, $original, $original_width, $original_height, $width, $height;
public $image, $src, $original, $original_width, $original_height, $width, $height;
public function valid() {
return (bool)$this->image;
}
public function __construct($img, $size = false) {
if (method_exists($this, 'init'))
$this->init();
if ($size && $size[0] > 0 && $size[1] > 0) {
$this->width = $size[0];
$this->height = $size[1];
}
if ($img !== false) {
$this->src = $img->src;
$this->from();
}
}
public function _width() {
if (method_exists($this, 'width'))
return $this->width();
@ -156,7 +157,7 @@ class ImageBase extends ImageGD {
$this->original = &$original;
$this->width = $width;
$this->height = $height;
if (method_exists($this, 'resize'))
$this->resize();
else
@ -199,31 +200,31 @@ class ImageImagick extends ImageBase {
}
public function resize() {
global $config;
if ($this->format == 'gif' && ($config['thumb_ext'] == 'gif' || $config['thumb_ext'] == '')) {
$this->image = new Imagick();
$this->image->setFormat('gif');
$keep_frames = array();
for ($i = 0; $i < $this->original->getNumberImages(); $i += floor($this->original->getNumberImages() / $config['thumb_keep_animation_frames']))
$keep_frames[] = $i;
$i = 0;
$delay = 0;
foreach ($this->original as $frame) {
$delay += $frame->getImageDelay();
if (in_array($i, $keep_frames)) {
// $frame->scaleImage($this->width, $this->height, false);
$frame->sampleImage($this->width, $this->height);
$frame->setImagePage($this->width, $this->height, 0, 0);
$frame->setImageDelay($delay);
$delay = 0;
$this->image->addImage($frame->getImage());
}
$i++;
}
}
} else {
$this->image = clone $this->original;
$this->image->scaleImage($this->width, $this->height, false);
@ -234,15 +235,15 @@ class ImageImagick extends ImageBase {
class ImageConvert extends ImageBase {
public $width, $height, $temp, $gm = false, $gifsicle = false;
public function init() {
global $config;
if ($config['thumb_method'] == 'gm' || $config['thumb_method'] == 'gm+gifsicle')
$this->gm = true;
if ($config['thumb_method'] == 'convert+gifsicle' || $config['thumb_method'] == 'gm+gifsicle')
$this->gifsicle = true;
$this->temp = false;
}
public function get_size($src, $try_gd_first = true) {
@ -264,7 +265,7 @@ class ImageConvert extends ImageBase {
if ($size) {
$this->width = $size[0];
$this->height = $size[1];
$this->image = true;
} else {
// mark as invalid
@ -273,7 +274,7 @@ class ImageConvert extends ImageBase {
}
public function to($src) {
global $config;
if (!$this->temp) {
if ($config['strip_exif']) {
if($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
@ -305,16 +306,16 @@ class ImageConvert extends ImageBase {
}
public function resize() {
global $config;
if ($this->temp) {
// remove old
$this->destroy();
}
$this->temp = tempnam($config['tmp'], 'convert');
$this->temp = tempnam($config['tmp'], 'convert') . ($config['thumb_ext'] == '' ? '' : '.' . $config['thumb_ext']);
$config['thumb_keep_animation_frames'] = (int)$config['thumb_keep_animation_frames'];
if ($this->format == 'gif' && ($config['thumb_ext'] == 'gif' || $config['thumb_ext'] == '') && $config['thumb_keep_animation_frames'] > 1) {
if ($this->gifsicle) {
if (($error = shell_exec("gifsicle -w --unoptimize -O2 --resize {$this->width}x{$this->height} < " .
@ -379,7 +380,7 @@ class ImageConvert extends ImageBase {
}
}
}
// For when -auto-orient doesn't exist (older versions)
static public function jpeg_exif_orientation($src, $exif = false) {
if (!$exif) {
@ -397,16 +398,16 @@ class ImageConvert extends ImageBase {
// 8888
// 88
// 88
return '-flop';
case 3:
// 88
// 88
// 8888
// 88
// 888888
return '-flip -flop';
case 4:
// 88
@ -414,31 +415,31 @@ class ImageConvert extends ImageBase {
// 8888
// 88
// 888888
return '-flip';
case 5:
// 8888888888
// 88 88
// 88
return '-rotate 90 -flop';
case 6:
// 88
// 88 88
// 8888888888
return '-rotate 90';
case 7:
// 88
// 88 88
// 8888888888
return '-rotate "-90" -flop';
case 8:
// 8888888888
// 88 88
// 88
return '-rotate "-90"';
}
}
@ -496,170 +497,11 @@ class ImageBMP extends ImageBase {
}
}
/*********************************************/
/* Fonction: imagecreatefrombmp */
/* Author: DHKold */
/* Contact: admin@dhkold.com */
/* Date: The 15th of June 2005 */
/* Version: 2.0B */
/*********************************************/
function imagecreatefrombmp($filename) {
if (! $f1 = fopen($filename,"rb")) return FALSE;
$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
if ($FILE['file_type'] != 19778) return FALSE;
$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
'/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
$BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
$BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] = 4-(4*$BMP['decal']);
if ($BMP['decal'] == 4) $BMP['decal'] = 0;
$PALETTE = array();
if ($BMP['colors'] < 16777216)
{
$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
}
$IMG = fread($f1,$BMP['size_bitmap']);
$VIDE = chr(0);
$res = imagecreatetruecolor($BMP['width'],$BMP['height']);
$P = 0;
$Y = $BMP['height']-1;
while ($Y >= 0)
{
$X=0;
while ($X < $BMP['width'])
{
if ($BMP['bits_per_pixel'] == 24)
$COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
elseif ($BMP['bits_per_pixel'] == 16)
{
$COLOR = unpack("n",substr($IMG,$P,2));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 8)
{
$COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 4)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 1)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*8)%8 == 0) $COLOR[1] = $COLOR[1] >>7;
elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
else
return FALSE;
imagesetpixel($res,$X,$Y,$COLOR[1]);
$X++;
$P += $BMP['bytes_per_pixel'];
class ImageWEBP extends ImageBase {
public function from() {
$this->image = @imagecreatefromwebp($this->src);
}
$Y--;
$P+=$BMP['decal'];
}
fclose($f1);
return $res;
}
function imagebmp(&$img, $filename='') {
$widthOrig = imagesx($img);
$widthFloor = ((floor($widthOrig/16))*16);
$widthCeil = ((ceil($widthOrig/16))*16);
$height = imagesy($img);
$size = ($widthCeil*$height*3)+54;
// Bitmap File Header
$result = 'BM'; // header (2b)
$result .= int_to_dword($size); // size of file (4b)
$result .= int_to_dword(0); // reserved (4b)
$result .= int_to_dword(54); // byte location in the file which is first byte of IMAGE (4b)
// Bitmap Info Header
$result .= int_to_dword(40); // Size of BITMAPINFOHEADER (4b)
$result .= int_to_dword($widthCeil); // width of bitmap (4b)
$result .= int_to_dword($height); // height of bitmap (4b)
$result .= int_to_word(1); // biPlanes = 1 (2b)
$result .= int_to_word(24); // biBitCount = {1 (mono) or 4 (16 clr ) or 8 (256 clr) or 24 (16 Mil)} (2b
$result .= int_to_dword(0); // RLE COMPRESSION (4b)
$result .= int_to_dword(0); // width x height (4b)
$result .= int_to_dword(0); // biXPelsPerMeter (4b)
$result .= int_to_dword(0); // biYPelsPerMeter (4b)
$result .= int_to_dword(0); // Number of palettes used (4b)
$result .= int_to_dword(0); // Number of important colour (4b)
// is faster than chr()
$arrChr = array();
for ($i=0; $i<256; $i++){
$arrChr[$i] = chr($i);
}
// creates image data
$bgfillcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
// bottom to top - left to right - attention blue green red !!!
$y=$height-1;
for ($y2=0; $y2<$height; $y2++) {
for ($x=0; $x<$widthFloor; ) {
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
for ($x=$widthFloor; $x<$widthCeil; $x++) {
$rgb = ($x<$widthOrig) ? imagecolorsforindex($img, imagecolorat($img, $x, $y)) : $bgfillcolor;
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
$y--;
}
// see imagegif
if ($filename == '') {
echo $result;
} else {
$file = fopen($filename, 'wb');
fwrite($file, $result);
fclose($file);
public function to($src) {
imagewebp($this->image, $src);
}
}
// imagebmp helpers
function int_to_dword($n) {
return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255);
}
function int_to_word($n) {
return chr($n & 255).chr(($n >> 8) & 255);
}

View File

@ -1,48 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Autoloads Twig classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Autoloader
{
/**
* Registers Twig_Autoloader as an SPL autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not.
*/
public static function register($prepend = false)
{
if (version_compare(phpversion(), '5.3.0', '>=')) {
spl_autoload_register(array(new self, 'autoload'), true, $prepend);
} else {
spl_autoload_register(array(new self, 'autoload'));
}
}
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*/
public static function autoload($class)
{
if (0 !== strpos($class, 'Twig')) {
return;
}
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
require $file;
}
}
}

View File

@ -1,268 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Compiler implements Twig_CompilerInterface
{
protected $lastLine;
protected $source;
protected $indentation;
protected $env;
protected $debugInfo;
protected $sourceOffset;
protected $sourceLine;
protected $filename;
/**
* Constructor.
*
* @param Twig_Environment $env The twig environment instance
*/
public function __construct(Twig_Environment $env)
{
$this->env = $env;
$this->debugInfo = array();
}
public function getFilename()
{
return $this->filename;
}
/**
* Returns the environment instance related to this compiler.
*
* @return Twig_Environment The environment instance
*/
public function getEnvironment()
{
return $this->env;
}
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource()
{
return $this->source;
}
/**
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
* @param integer $indentation The current indentation
*
* @return Twig_Compiler The current compiler instance
*/
public function compile(Twig_NodeInterface $node, $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
$this->indentation = $indentation;
if ($node instanceof Twig_Node_Module) {
$this->filename = $node->getAttribute('filename');
}
$node->compile($this);
return $this;
}
public function subcompile(Twig_NodeInterface $node, $raw = true)
{
if (false === $raw) {
$this->addIndentation();
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @param string $string The string
*
* @return Twig_Compiler The current compiler instance
*/
public function raw($string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return Twig_Compiler The current compiler instance
*/
public function write()
{
$strings = func_get_args();
foreach ($strings as $string) {
$this->addIndentation();
$this->source .= $string;
}
return $this;
}
/**
* Appends an indentation to the current PHP code after compilation.
*
* @return Twig_Compiler The current compiler instance
*/
public function addIndentation()
{
$this->source .= str_repeat(' ', $this->indentation * 4);
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @param string $value The string
*
* @return Twig_Compiler The current compiler instance
*/
public function string($value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @param mixed $value The value to convert
*
* @return Twig_Compiler The current compiler instance
*/
public function repr($value)
{
if (is_int($value) || is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
setlocale(LC_NUMERIC, 'C');
}
$this->raw($value);
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $value) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($value);
}
$this->raw(')');
} else {
$this->string($value);
}
return $this;
}
/**
* Adds debugging information.
*
* @param Twig_NodeInterface $node The related twig node
*
* @return Twig_Compiler The current compiler instance
*/
public function addDebugInfo(Twig_NodeInterface $node)
{
if ($node->getLine() != $this->lastLine) {
$this->write("// line {$node->getLine()}\n");
// when mbstring.func_overload is set to 2
// mb_substr_count() replaces substr_count()
// but they have different signatures!
if (((int) ini_get('mbstring.func_overload')) & 2) {
// this is much slower than the "right" version
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
} else {
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
}
$this->sourceOffset = strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getLine();
$this->lastLine = $node->getLine();
}
return $this;
}
public function getDebugInfo()
{
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param integer $step The number of indentation to add
*
* @return Twig_Compiler The current compiler instance
*/
public function indent($step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* Outdents the generated code.
*
* @param integer $step The number of indentation to remove
*
* @return Twig_Compiler The current compiler instance
*/
public function outdent($step = 1)
{
// can't outdent by more steps than the current indentation level
if ($this->indentation < $step) {
throw new LogicException('Unable to call outdent() as the indentation would become negative');
}
$this->indentation -= $step;
return $this;
}
}

View File

@ -1,35 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_CompilerInterface
{
/**
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
*
* @return Twig_CompilerInterface The current compiler instance
*/
public function compile(Twig_NodeInterface $node);
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,243 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template name
* and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1
* and/or the filename is set to null). As this is a costly operation, this
* can be disabled by passing false for both the filename and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error extends Exception
{
protected $lineno;
protected $filename;
protected $rawMessage;
protected $previous;
/**
* Constructor.
*
* Set both the line number and the filename to false to
* disable automatic guessing of the original template name
* and line number.
*
* Set the line number to -1 to enable its automatic guessing.
* Set the filename to null to enable its automatic guessing.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param integer $lineno The template line where the error occurred
* @param string $filename The template file name where the error occurred
* @param Exception $previous The previous exception
*/
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
$this->previous = $previous;
parent::__construct('');
} else {
parent::__construct('', 0, $previous);
}
$this->lineno = $lineno;
$this->filename = $filename;
if (-1 === $this->lineno || null === $this->filename) {
$this->guessTemplateInfo();
}
$this->rawMessage = $message;
$this->updateRepr();
}
/**
* Gets the raw message.
*
* @return string The raw message
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Gets the filename where the error occurred.
*
* @return string The filename
*/
public function getTemplateFile()
{
return $this->filename;
}
/**
* Sets the filename where the error occurred.
*
* @param string $filename The filename
*/
public function setTemplateFile($filename)
{
$this->filename = $filename;
$this->updateRepr();
}
/**
* Gets the template line where the error occurred.
*
* @return integer The template line
*/
public function getTemplateLine()
{
return $this->lineno;
}
/**
* Sets the template line where the error occurred.
*
* @param integer $lineno The template line
*/
public function setTemplateLine($lineno)
{
$this->lineno = $lineno;
$this->updateRepr();
}
public function guess()
{
$this->guessTemplateInfo();
$this->updateRepr();
}
/**
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method The method name
* @param array $arguments The parameters to be passed to the method
*
* @return Exception The previous exception or null
*
* @throws BadMethodCallException
*/
public function __call($method, $arguments)
{
if ('getprevious' == strtolower($method)) {
return $this->previous;
}
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
}
protected function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if ($this->filename) {
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
$filename = sprintf('"%s"', $this->filename);
} else {
$filename = json_encode($this->filename);
}
$this->message .= sprintf(' in %s', $filename);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
if ($dot) {
$this->message .= '.';
}
}
protected function guessTemplateInfo()
{
$template = null;
$templateClass = null;
if (version_compare(phpversion(), '5.3.6', '>=')) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
} else {
$backtrace = debug_backtrace();
}
foreach ($backtrace as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
$currentClass = get_class($trace['object']);
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
$template = $trace['object'];
$templateClass = get_class($trace['object']);
}
}
}
// update template filename
if (null !== $template && null === $this->filename) {
$this->filename = $template->getTemplateName();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new ReflectionObject($template);
$file = $r->getFileName();
$exceptions = array($e = $this);
while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;
}
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}

View File

@ -1,31 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs during template loading.
*
* Automatic template information guessing is always turned off as
* if a template cannot be loaded, there is nothing to guess.
* However, when a template is loaded from another one, then, we need
* to find the current context and this is automatically done by
* Twig_Template::displayWithErrorHandling().
*
* This strategy makes Twig_Environment::resolveTemplate() much faster.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Loader extends Twig_Error
{
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
{
parent::__construct($message, false, false, $previous);
}
}

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Runtime extends Twig_Error
{
}

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Syntax extends Twig_Error
{
}

View File

@ -1,28 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_ExistsLoaderInterface
{
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return boolean If the template source code is handled by this loader or not
*/
public function exists($name);
}

View File

@ -1,611 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_ExpressionParser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
protected $parser;
protected $unaryOperators;
protected $binaryOperators;
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
{
$this->parser = $parser;
$this->unaryOperators = $unaryOperators;
$this->binaryOperators = $binaryOperators;
}
public function parseExpression($precedence = 0)
{
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if (isset($op['callable'])) {
$expr = call_user_func($op['callable'], $this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
protected function getPrimary()
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr = $this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
protected function parseConditionalExpression($expr)
{
while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
$this->parser->getStream()->next();
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$this->parser->getStream()->next();
$expr3 = $this->parseExpression();
} else {
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
}
} else {
$this->parser->getStream()->next();
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
protected function isUnary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
}
protected function isBinary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case Twig_Token::NAME_TYPE:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
}
}
break;
case Twig_Token::NUMBER_TYPE:
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
break;
case Twig_Token::STRING_TYPE:
case Twig_Token::INTERPOLATION_START_TYPE:
$node = $this->parseStringExpression();
break;
default:
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
$node = $this->parseHashExpression();
} else {
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = array();
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
$token = $stream->next();
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
$stream->next();
$nodes[] = $this->parseExpression();
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
break;
}
}
$first = false;
$node->addElement($this->parseExpression());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
break;
}
}
$first = false;
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2)
if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
$token = $stream->next();
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$args = $this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
case 'attribute':
$args = $this->parseArguments();
if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
default:
$args = $this->parseArguments(true);
if (null !== $alias = $this->parser->getImportedSymbol('macro', $name)) {
return new Twig_Node_Expression_MacroCall($alias['node'], $alias['name'], $this->createArrayFromArguments($args), $line);
}
try {
$class = $this->getFunctionNodeClass($name, $line);
} catch (Twig_Error_Syntax $e) {
if (!$this->parser->hasMacro($name)) {
throw $e;
}
return new Twig_Node_Expression_MacroCall(new Twig_Node_Expression_Name('_self', $line), $name, $this->createArrayFromArguments($args), $line);
}
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_Template::ANY_CALL;
if ($token->getValue() == '.') {
$token = $stream->next();
if (
$token->getType() == Twig_Token::NAME_TYPE
||
$token->getType() == Twig_Token::NUMBER_TYPE
||
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
} else {
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
}
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
}
$arguments = $this->createArrayFromArguments($this->parseArguments(true));
return new Twig_Node_Expression_MacroCall($node, $arg->getAttribute('value'), $arguments, $lineno);
}
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_Template::METHOD_CALL;
$arguments = $this->createArrayFromArguments($this->parseArguments());
}
} else {
$type = Twig_Template::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$stream->next();
}
if ($slice) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Twig_Node(array($arg, $length));
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
}
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = new Twig_Node();
} else {
$arguments = $this->parseArguments(true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
*
* @return Twig_Node
*/
public function parseArguments($namedArguments = false, $definition = false)
{
$args = array();
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
if ($definition) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression();
}
$name = null;
if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
$token = $stream->next();
if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $this->parser->getFilename());
}
} else {
$value = $this->parseExpression();
}
}
if ($definition && null === $name) {
$name = $value->getAttribute('name');
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
}
if (null === $name) {
$args[] = $value;
} else {
if ($definition && isset($args[$name])) {
throw new Twig_Error_Syntax(sprintf('Arguments cannot contain the same argument name more than once ("%s" is defined twice).', $name), $token->getLine(), $this->parser->getFilename());
}
$args[$name] = $value;
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return new Twig_Node($args);
}
public function parseAssignmentExpression()
{
$targets = array();
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
$this->parser->getStream()->next();
}
return new Twig_Node($targets);
}
public function parseMultitargetExpression()
{
$targets = array();
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
$this->parser->getStream()->next();
}
return new Twig_Node($targets);
}
protected function getFunctionNodeClass($name, $line)
{
$env = $this->parser->getEnvironment();
if (false === $function = $env->getFunction($name)) {
$message = sprintf('The function "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($function instanceof Twig_SimpleFunction) {
return $function->getNodeClass();
}
return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
}
protected function getFilterNodeClass($name, $line)
{
$env = $this->parser->getEnvironment();
if (false === $filter = $env->getFilter($name)) {
$message = sprintf('The filter "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($filter instanceof Twig_SimpleFilter) {
return $filter->getNodeClass();
}
return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
}
// checks that the node only contains "constant" elements
protected function checkConstantExpression(Twig_NodeInterface $node)
{
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
private function createArrayFromArguments(Twig_Node $arguments, $line = null)
{
$line = null === $line ? $arguments->getLine() : $line;
$array = new Twig_Node_Expression_Array(array(), $line);
foreach ($arguments as $key => $value) {
$array->addElement($value, new Twig_Node_Expression_Constant($key, $value->getLine()));
}
return $array;
}
}

View File

@ -1,93 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Extension implements Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/
public function initRuntime(Twig_Environment $environment)
{
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array();
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array();
}
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array();
}
/**
* Returns a list of tests to add to the existing list.
*
* @return array An array of tests
*/
public function getTests()
{
return array();
}
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of functions
*/
public function getFunctions()
{
return array();
}
/**
* Returns a list of operators to add to the existing list.
*
* @return array An array of operators
*/
public function getOperators()
{
return array();
}
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*/
public function getGlobals()
{
return array();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Debug extends Twig_Extension
{
/**
* Returns a list of global functions to add to the existing list.
*
* @return array An array of global functions
*/
public function getFunctions()
{
// dump is safe if var_dump is overridden by xdebug
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
// false means that it was not set (and the default is on) or it explicitly enabled
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
// false means that it was not set (and the default is on) or it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
&& (false === ini_get('html_errors') || ini_get('html_errors'))
|| 'cli' === php_sapi_name()
;
return array(
new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'debug';
}
}
function twig_var_dump(Twig_Environment $env, $context)
{
if (!$env->isDebug()) {
return;
}
ob_start();
$count = func_num_args();
if (2 === $count) {
$vars = array();
foreach ($context as $key => $value) {
if (!$value instanceof Twig_Template) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
for ($i = 2; $i < $count; $i++) {
var_dump(func_get_arg($i));
}
}
return ob_get_clean();
}

View File

@ -1,107 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Escaper extends Twig_Extension
{
protected $defaultStrategy;
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array(new Twig_TokenParser_AutoEscape());
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Escaper());
}
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array(
new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
);
}
/**
* Sets the default strategy to use when not defined by the user.
*
* The strategy can be a valid PHP callback that takes the template
* "filename" as an argument and returns the strategy to use.
*
* @param mixed $defaultStrategy An escaping strategy
*/
public function setDefaultStrategy($defaultStrategy)
{
// for BC
if (true === $defaultStrategy) {
$defaultStrategy = 'html';
}
$this->defaultStrategy = $defaultStrategy;
}
/**
* Gets the default strategy to use when not defined by the user.
*
* @param string $filename The template "filename"
*
* @return string The default strategy to use for the template
*/
public function getDefaultStrategy($filename)
{
// disable string callables to avoid calling a function named html or js,
// or any other upcoming escaping strategy
if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
return call_user_func($this->defaultStrategy, $filename);
}
return $this->defaultStrategy;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'escaper';
}
}
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*/
function twig_raw_filter($string)
{
return $string;
}

View File

@ -1,35 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Optimizer extends Twig_Extension
{
protected $optimizers;
public function __construct($optimizers = -1)
{
$this->optimizers = $optimizers;
}
/**
* {@inheritdoc}
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'optimizer';
}
}

View File

@ -1,112 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Sandbox extends Twig_Extension
{
protected $sandboxedGlobally;
protected $sandboxed;
protected $policy;
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array(new Twig_TokenParser_Sandbox());
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Sandbox());
}
public function enableSandbox()
{
$this->sandboxed = true;
}
public function disableSandbox()
{
$this->sandboxed = false;
}
public function isSandboxed()
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally()
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy()
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters, $functions);
}
}
public function checkMethodAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkMethodAllowed($obj, $method);
}
}
public function checkPropertyAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkPropertyAllowed($obj, $method);
}
}
public function ensureToStringAllowed($obj)
{
if (is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString');
}
return $obj;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'sandbox';
}
}

View File

@ -1,113 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Internal class.
*
* This class is used by Twig_Environment as a staging area and must not be used directly.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Extension_Staging extends Twig_Extension
{
protected $functions = array();
protected $filters = array();
protected $visitors = array();
protected $tokenParsers = array();
protected $globals = array();
protected $tests = array();
public function addFunction($name, $function)
{
$this->functions[$name] = $function;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return $this->functions;
}
public function addFilter($name, $filter)
{
$this->filters[$name] = $filter;
}
/**
* {@inheritdoc}
*/
public function getFilters()
{
return $this->filters;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
/**
* {@inheritdoc}
*/
public function getNodeVisitors()
{
return $this->visitors;
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
$this->tokenParsers[] = $parser;
}
/**
* {@inheritdoc}
*/
public function getTokenParsers()
{
return $this->tokenParsers;
}
public function addGlobal($name, $value)
{
$this->globals[$name] = $value;
}
/**
* {@inheritdoc}
*/
public function getGlobals()
{
return $this->globals;
}
public function addTest($name, $test)
{
$this->tests[$name] = $test;
}
/**
* {@inheritdoc}
*/
public function getTests()
{
return $this->tests;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'staging';
}
}

View File

@ -1,64 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_StringLoader extends Twig_Extension
{
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'string_loader';
}
}
/**
* Loads a template from a string.
*
* <pre>
* {{ include(template_from_string("Hello {{ name }}")) }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param string $template A template as a string
*
* @return Twig_Template A Twig_Template instance
*/
function twig_template_from_string(Twig_Environment $env, $template)
{
$name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
$loader = new Twig_Loader_Chain(array(
new Twig_Loader_Array(array($name => $template)),
$current = $env->getLoader(),
));
$env->setLoader($loader);
try {
$template = $env->loadTemplate($name);
} catch (Exception $e) {
$env->setLoader($current);
throw $e;
}
$env->setLoader($current);
return $template;
}

View File

@ -1,83 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/
public function initRuntime(Twig_Environment $environment);
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return array An array of tests
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of functions
*/
public function getFunctions();
/**
* Returns a list of operators to add to the existing list.
*
* @return array An array of operators
*/
public function getOperators();
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*/
public function getGlobals();
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName();
}

View File

@ -1,45 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extensions_Extension_I18n extends Twig_Extension
{
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array(new Twig_Extensions_TokenParser_Trans());
}
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array(
new Twig_SimpleFilter('trans', 'gettext'),
);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'i18n';
}
}

View File

@ -1,134 +0,0 @@
<?php
class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
{
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array(
new Twig_SimpleFilter('filesize', 'format_bytes'),
new Twig_SimpleFilter('truncate', 'twig_truncate_filter'),
new Twig_SimpleFilter('truncate_body', 'truncate'),
new Twig_SimpleFilter('truncate_filename', 'twig_filename_truncate_filter'),
new Twig_SimpleFilter('extension', 'twig_extension_filter'),
new Twig_SimpleFilter('sprintf', 'sprintf'),
new Twig_SimpleFilter('capcode', 'capcode'),
new Twig_SimpleFilter('hasPermission', 'twig_hasPermission_filter'),
new Twig_SimpleFilter('date', 'twig_date_filter'),
new Twig_SimpleFilter('poster_id', 'poster_id'),
new Twig_SimpleFilter('remove_whitespace', 'twig_remove_whitespace_filter'),
new Twig_SimpleFilter('count', 'count'),
new Twig_SimpleFilter('ago', 'ago'),
new Twig_SimpleFilter('until', 'until'),
new Twig_SimpleFilter('push', 'twig_push_filter'),
new Twig_SimpleFilter('bidi_cleanup', 'bidi_cleanup'),
new Twig_SimpleFilter('addslashes', 'addslashes'),
);
}
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of filters
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction('time', 'time'),
new Twig_SimpleFunction('floor', 'floor'),
new Twig_SimpleFunction('timezone', 'twig_timezone_function'),
new Twig_SimpleFunction('hiddenInputs', 'hiddenInputs'),
new Twig_SimpleFunction('hiddenInputsHash', 'hiddenInputsHash'),
new Twig_SimpleFunction('ratio', 'twig_ratio_function'),
new Twig_SimpleFunction('secure_link_confirm', 'twig_secure_link_confirm'),
new Twig_SimpleFunction('secure_link', 'twig_secure_link'),
new Twig_SimpleFunction('link_for', 'link_for')
);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'tinyboard';
}
}
function twig_timezone_function() {
return 'Z';
}
function twig_push_filter($array, $value) {
array_push($array, $value);
return $array;
}
function twig_remove_whitespace_filter($data) {
return preg_replace('/[\t\r\n]/', '', $data);
}
function twig_date_filter($date, $format) {
return gmstrftime($format, $date);
}
function twig_hasPermission_filter($mod, $permission, $board = null) {
return hasPermission($permission, $board, $mod);
}
function twig_extension_filter($value, $case_insensitive = true) {
$ext = mb_substr($value, mb_strrpos($value, '.') + 1);
if($case_insensitive)
$ext = mb_strtolower($ext);
return $ext;
}
function twig_sprintf_filter( $value, $var) {
return sprintf($value, $var);
}
function twig_truncate_filter($value, $length = 30, $preserve = false, $separator = '…') {
if (mb_strlen($value) > $length) {
if ($preserve) {
if (false !== ($breakpoint = mb_strpos($value, ' ', $length))) {
$length = $breakpoint;
}
}
return mb_substr($value, 0, $length) . $separator;
}
return $value;
}
function twig_filename_truncate_filter($value, $length = 30, $separator = '…') {
if (mb_strlen($value) > $length) {
$value = strrev($value);
$array = array_reverse(explode(".", $value, 2));
$array = array_map("strrev", $array);
$filename = &$array[0];
$extension = isset($array[1]) ? $array[1] : false;
$filename = mb_substr($filename, 0, $length - ($extension ? mb_strlen($extension) + 1 : 0)) . $separator;
return implode(".", $array);
}
return $value;
}
function twig_ratio_function($w, $h) {
return fraction($w, $h, ':');
}
function twig_secure_link_confirm($text, $title, $confirm_message, $href) {
global $config;
return '<a onclick="if (event.which==2) return true;if (confirm(\'' . htmlentities(addslashes($confirm_message)) . '\')) document.location=\'?/' . htmlspecialchars(addslashes($href . '/' . make_secure_link_token($href))) . '\';return false;" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
}
function twig_secure_link($href) {
return $href . '/' . make_secure_link_token($href);
}

View File

@ -1,133 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a trans node.
*
* @package twig
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class Twig_Extensions_Node_Trans extends Twig_Node
{
public function __construct(Twig_NodeInterface $body, Twig_NodeInterface $plural = null, Twig_Node_Expression $count = null, $lineno, $tag = null)
{
parent::__construct(array('count' => $count, 'body' => $body, 'plural' => $plural), array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
list($msg, $vars) = $this->compileString($this->getNode('body'));
if (null !== $this->getNode('plural')) {
list($msg1, $vars1) = $this->compileString($this->getNode('plural'));
$vars = array_merge($vars, $vars1);
}
$function = null === $this->getNode('plural') ? 'gettext' : 'ngettext';
if ($vars) {
$compiler
->write('echo strtr('.$function.'(')
->subcompile($msg)
;
if (null !== $this->getNode('plural')) {
$compiler
->raw(', ')
->subcompile($msg1)
->raw(', abs(')
->subcompile($this->getNode('count'))
->raw(')')
;
}
$compiler->raw('), array(');
foreach ($vars as $var) {
if ('count' === $var->getAttribute('name')) {
$compiler
->string('%count%')
->raw(' => abs(')
->subcompile($this->getNode('count'))
->raw('), ')
;
} else {
$compiler
->string('%'.$var->getAttribute('name').'%')
->raw(' => ')
->subcompile($var)
->raw(', ')
;
}
}
$compiler->raw("));\n");
} else {
$compiler
->write('echo '.$function.'(')
->subcompile($msg)
;
if (null !== $this->getNode('plural')) {
$compiler
->raw(', ')
->subcompile($msg1)
->raw(', abs(')
->subcompile($this->getNode('count'))
->raw(')')
;
}
$compiler->raw(");\n");
}
}
protected function compileString(Twig_NodeInterface $body)
{
if ($body instanceof Twig_Node_Expression_Name || $body instanceof Twig_Node_Expression_Constant || $body instanceof Twig_Node_Expression_TempName) {
return array($body, array());
}
$vars = array();
if (count($body)) {
$msg = '';
foreach ($body as $node) {
if (get_class($node) === 'Twig_Node' && $node->getNode(0) instanceof Twig_Node_SetTemp) {
$node = $node->getNode(1);
}
if ($node instanceof Twig_Node_Print) {
$n = $node->getNode('expr');
while ($n instanceof Twig_Node_Expression_Filter) {
$n = $n->getNode('node');
}
$msg .= sprintf('%%%s%%', $n->getAttribute('name'));
$vars[] = new Twig_Node_Expression_Name($n->getAttribute('name'), $n->getLine());
} else {
$msg .= $node->getAttribute('data');
}
}
} else {
$msg = $body->getAttribute('data');
}
return array(new Twig_Node(array(new Twig_Node_Expression_Constant(trim($msg), $body->getLine()))), $vars);
}
}

View File

@ -1,80 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extensions_TokenParser_Trans extends Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param Twig_Token $token A Twig_Token instance
*
* @return Twig_NodeInterface A Twig_NodeInterface instance
*/
public function parse(Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$count = null;
$plural = null;
if (!$stream->test(Twig_Token::BLOCK_END_TYPE)) {
$body = $this->parser->getExpressionParser()->parseExpression();
} else {
$stream->expect(Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this, 'decideForFork'));
if ('plural' === $stream->next()->getValue()) {
$count = $this->parser->getExpressionParser()->parseExpression();
$stream->expect(Twig_Token::BLOCK_END_TYPE);
$plural = $this->parser->subparse(array($this, 'decideForEnd'), true);
}
}
$stream->expect(Twig_Token::BLOCK_END_TYPE);
$this->checkTransString($body, $lineno);
return new Twig_Extensions_Node_Trans($body, $plural, $count, $lineno, $this->getTag());
}
public function decideForFork(Twig_Token $token)
{
return $token->test(array('plural', 'endtrans'));
}
public function decideForEnd(Twig_Token $token)
{
return $token->test('endtrans');
}
/**
* Gets the tag name associated with this token parser.
*
* @param string The tag name
*/
public function getTag()
{
return 'trans';
}
protected function checkTransString(Twig_NodeInterface $body, $lineno)
{
foreach ($body as $i => $node) {
if (
$node instanceof Twig_Node_Text
||
($node instanceof Twig_Node_Print && $node->getNode('expr') instanceof Twig_Node_Expression_Name)
) {
continue;
}
throw new Twig_Error_Syntax(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno);
}
}
}

View File

@ -1,81 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'pre_escape' => null,
'preserves_safety' => null,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $filterArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $filterArgs);
}
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function getCallable()
{
return $this->options['callable'];
}
}

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a function template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Function extends Twig_Filter
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a method template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Method extends Twig_Filter
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter as a node.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Node extends Twig_Filter
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View File

@ -1,23 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterCallableInterface
{
public function getCallable();
}

View File

@ -1,42 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterInterface
{
/**
* Compiles a filter.
*
* @return string The PHP code for the filter
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function getPreservesSafety();
public function getPreEscape();
public function setArguments($arguments);
public function getArguments();
}

View File

@ -1,71 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $functionArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $functionArgs);
}
return array();
}
public function getCallable()
{
return $this->options['callable'];
}
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a function template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Function extends Twig_Function
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View File

@ -1,40 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a method template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Method extends Twig_Function
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function as a node.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Node extends Twig_Function
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View File

@ -1,23 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionCallableInterface
{
public function getCallable();
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionInterface
{
/**
* Compiles a function.
*
* @return string The PHP code for the function
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function setArguments($arguments);
public function getArguments();
}

View File

@ -1,408 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lexes a template string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Lexer implements Twig_LexerInterface
{
protected $tokens;
protected $code;
protected $cursor;
protected $lineno;
protected $end;
protected $state;
protected $states;
protected $brackets;
protected $env;
protected $filename;
protected $options;
protected $regexes;
protected $position;
protected $positions;
protected $currentVarBlockLine;
const STATE_DATA = 0;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Twig_Environment $env, array $options = array())
{
$this->env = $env;
$this->options = array_merge(array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{{', '}}'),
'whitespace_trim' => '-',
'interpolation' => array('#{', '}'),
), $options);
$this->regexes = array(
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
'operator' => $this->getOperatorRegex(),
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
);
}
/**
* Tokenizes a source code.
*
* @param string $code The source code
* @param string $filename A unique identifier for the source code
*
* @return Twig_TokenStream A token stream instance
*/
public function tokenize($code, $filename = null)
{
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
$this->code = str_replace(array("\r\n", "\r"), "\n", $code);
$this->filename = $filename;
$this->cursor = 0;
$this->lineno = 1;
$this->end = strlen($this->code);
$this->tokens = array();
$this->state = self::STATE_DATA;
$this->states = array();
$this->brackets = array();
$this->position = -1;
// find all token starts in one go
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
$this->positions = $matches;
while ($this->cursor < $this->end) {
// dispatch to the lexing functions depending
// on the current state
switch ($this->state) {
case self::STATE_DATA:
$this->lexData();
break;
case self::STATE_BLOCK:
$this->lexBlock();
break;
case self::STATE_VAR:
$this->lexVar();
break;
case self::STATE_STRING:
$this->lexString();
break;
case self::STATE_INTERPOLATION:
$this->lexInterpolation();
break;
}
}
$this->pushToken(Twig_Token::EOF_TYPE);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return new Twig_TokenStream($this->tokens, $this->filename);
}
protected function lexData()
{
// if no matches are left we return the rest of the template as simple text token
if ($this->position == count($this->positions[0]) - 1) {
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
$this->cursor = $this->end;
return;
}
// Find the first token after the current cursor
$position = $this->positions[0][++$this->position];
while ($position[1] < $this->cursor) {
if ($this->position == count($this->positions[0]) - 1) {
return;
}
$position = $this->positions[0][++$this->position];
}
// push the template text first
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
if (isset($this->positions[2][$this->position][0])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
$this->moveCursor($textContent.$position[0]);
switch ($this->positions[1][$this->position][0]) {
case $this->options['tag_comment'][0]:
$this->lexComment();
break;
case $this->options['tag_block'][0]:
// raw data?
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData($match[1]);
// {% line \d+ %}
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(Twig_Token::VAR_START_TYPE);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
protected function lexBlock()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexVar()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::VAR_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexExpression()
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
}
}
// operators
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
$number = (float) $match[0]; // floats
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
$number = (int) $match[0]; // integers lower than the maximum
}
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
$this->moveCursor($match[0]);
}
// punctuation
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
// opening bracket
if (false !== strpos('([{', $this->code[$this->cursor])) {
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
}
// closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
}
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
}
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
$this->moveCursor($match[0]);
}
// opening double quoted string
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array('"', $this->lineno);
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
}
}
protected function lexRawData($tag)
{
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
}
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
$this->moveCursor($text.$match[0][0]);
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
}
protected function lexComment()
{
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
}
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
}
protected function lexString()
{
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != '"') {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
$this->popState();
++$this->cursor;
}
}
protected function lexInterpolation()
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function pushToken($type, $value = '')
{
// do not push empty text tokens
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
return;
}
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
}
protected function moveCursor($text)
{
$this->cursor += strlen($text);
$this->lineno += substr_count($text, "\n");
}
protected function getOperatorRegex()
{
$operators = array_merge(
array('='),
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
$regex = array();
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) {
$regex[] = preg_quote($operator, '/').'(?=[\s()])';
} else {
$regex[] = preg_quote($operator, '/');
}
}
return '/'.implode('|', $regex).'/A';
}
protected function pushState($state)
{
$this->states[] = $this->state;
$this->state = $state;
}
protected function popState()
{
if (0 === count($this->states)) {
throw new Exception('Cannot pop state without a previous state');
}
$this->state = array_pop($this->states);
}
}

View File

@ -1,29 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by lexer classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_LexerInterface
{
/**
* Tokenizes a source code.
*
* @param string $code The source code
* @param string $filename A unique identifier for the source code
*
* @return Twig_TokenStream A token stream instance
*/
public function tokenize($code, $filename = null);
}

View File

@ -1,95 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads a template from an array.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
protected $templates = array();
/**
* Constructor.
*
* @param array $templates An array of templates (keys are the names, and values are the source code)
*
* @see Twig_Loader
*/
public function __construct(array $templates)
{
$this->templates = $templates;
}
/**
* Adds or overrides a template.
*
* @param string $name The template name
* @param string $template The template source
*/
public function setTemplate($name, $template)
{
$this->templates[(string) $name] = $template;
}
/**
* {@inheritdoc}
*/
public function getSource($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $this->templates[$name];
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
return isset($this->templates[(string) $name]);
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $this->templates[$name];
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return true;
}
}

View File

@ -1,138 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads templates from other loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
private $hasSourceCache = array();
protected $loaders = array();
/**
* Constructor.
*
* @param Twig_LoaderInterface[] $loaders An array of loader instances
*/
public function __construct(array $loaders = array())
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
/**
* Adds a loader instance.
*
* @param Twig_LoaderInterface $loader A Loader instance
*/
public function addLoader(Twig_LoaderInterface $loader)
{
$this->loaders[] = $loader;
$this->hasSourceCache = array();
}
/**
* {@inheritdoc}
*/
public function getSource($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getSource($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
$name = (string) $name;
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
continue;
}
try {
$loader->getSource($name);
return $this->hasSourceCache[$name] = true;
} catch (Twig_Error_Loader $e) {
}
}
return $this->hasSourceCache[$name] = false;
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
}
}

View File

@ -1,226 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads template from the filesystem.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
/** Identifier of the main namespace. */
const MAIN_NAMESPACE = '__main__';
protected $paths = array();
protected $cache = array();
/**
* Constructor.
*
* @param string|array $paths A path or an array of paths where to look for templates
*/
public function __construct($paths = array())
{
if ($paths) {
$this->setPaths($paths);
}
}
/**
* Returns the paths to the templates.
*
* @param string $namespace A path namespace
*
* @return array The array of paths where to look for templates
*/
public function getPaths($namespace = self::MAIN_NAMESPACE)
{
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
}
/**
* Returns the path namespaces.
*
* The main namespace is always defined.
*
* @return array The array of defined namespaces
*/
public function getNamespaces()
{
return array_keys($this->paths);
}
/**
* Sets the paths where templates are stored.
*
* @param string|array $paths A path or an array of paths where to look for templates
* @param string $namespace A path namespace
*/
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
{
if (!is_array($paths)) {
$paths = array($paths);
}
$this->paths[$namespace] = array();
foreach ($paths as $path) {
$this->addPath($path, $namespace);
}
}
/**
* Adds a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path name
*
* @throws Twig_Error_Loader
*/
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = array();
if (!is_dir($path)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
}
/**
* Prepends a path where templates are stored.
*
* @param string $path A path where to look for templates
* @param string $namespace A path name
*
* @throws Twig_Error_Loader
*/
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
{
// invalidate the cache
$this->cache = array();
if (!is_dir($path)) {
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
}
$path = rtrim($path, '/\\');
if (!isset($this->paths[$namespace])) {
$this->paths[$namespace][] = $path;
} else {
array_unshift($this->paths[$namespace], $path);
}
}
/**
* {@inheritdoc}
*/
public function getSource($name)
{
return file_get_contents($this->findTemplate($name));
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
return $this->findTemplate($name);
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
$name = (string) $name;
if (isset($this->cache[$name])) {
return true;
}
try {
$this->findTemplate($name);
return true;
} catch (Twig_Error_Loader $exception) {
return false;
}
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
return filemtime($this->findTemplate($name)) <= $time;
}
protected function findTemplate($name)
{
$name = (string) $name;
// normalize name
$name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'));
if (isset($this->cache[$name])) {
return $this->cache[$name];
}
$this->validateName($name);
$namespace = self::MAIN_NAMESPACE;
$shortname = $name;
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
$shortname = substr($name, $pos + 1);
}
if (!isset($this->paths[$namespace])) {
throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
}
foreach ($this->paths[$namespace] as $path) {
if (is_file($path.'/'.$shortname)) {
return $this->cache[$name] = $path.'/'.$shortname;
}
}
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
}
protected function validateName($name)
{
if (false !== strpos($name, "\0")) {
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
}
$name = ltrim($name, '/');
$parts = explode('/', $name);
$level = 0;
foreach ($parts as $part) {
if ('..' === $part) {
--$level;
} elseif ('.' !== $part) {
++$level;
}
if ($level < 0) {
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}
}

View File

@ -1,59 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads a template from a string.
*
* This loader should only be used for unit testing as it has many limitations
* (for instance, the include or extends tag does not make any sense for a string
* loader).
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
/**
* {@inheritdoc}
*/
public function getSource($name)
{
return $name;
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
return true;
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
return $name;
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
return true;
}
}

View File

@ -1,52 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface all loaders must implement.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_LoaderInterface
{
/**
* Gets the source code of a template, given its name.
*
* @param string $name The name of the template to load
*
* @return string The template source code
*
* @throws Twig_Error_Loader When $name is not found
*/
public function getSource($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws Twig_Error_Loader When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
*
* @return Boolean true if the template is fresh, false otherwise
*
* @throws Twig_Error_Loader When $name is not found
*/
public function isFresh($name, $time);
}

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Marks a content as safe.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Markup implements Countable
{
protected $content;
protected $charset;
public function __construct($content, $charset)
{
$this->content = (string) $content;
$this->charset = $charset;
}
public function __toString()
{
return $this->content;
}
public function count()
{
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
}
}

View File

@ -1,226 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node implements Twig_NodeInterface
{
protected $nodes;
protected $attributes;
protected $lineno;
protected $tag;
/**
* Constructor.
*
* The nodes are automatically made available as properties ($this->node).
* The attributes are automatically made available as array items ($this['name']).
*
* @param array $nodes An array of named nodes
* @param array $attributes An array of attributes (should not be nodes)
* @param integer $lineno The line number
* @param string $tag The tag name associated with the Node
*/
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
{
$this->nodes = $nodes;
$this->attributes = $attributes;
$this->lineno = $lineno;
$this->tag = $tag;
}
public function __toString()
{
$attributes = array();
foreach ($this->attributes as $name => $value) {
$attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
}
$repr = array(get_class($this).'('.implode(', ', $attributes));
if (count($this->nodes)) {
foreach ($this->nodes as $name => $node) {
$len = strlen($name) + 4;
$noderepr = array();
foreach (explode("\n", (string) $node) as $line) {
$noderepr[] = str_repeat(' ', $len).$line;
}
$repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
}
$repr[] = ')';
} else {
$repr[0] .= ')';
}
return implode("\n", $repr);
}
public function toXml($asDom = false)
{
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dom->appendChild($xml = $dom->createElement('twig'));
$xml->appendChild($node = $dom->createElement('node'));
$node->setAttribute('class', get_class($this));
foreach ($this->attributes as $name => $value) {
$node->appendChild($attribute = $dom->createElement('attribute'));
$attribute->setAttribute('name', $name);
$attribute->appendChild($dom->createTextNode($value));
}
foreach ($this->nodes as $name => $n) {
if (null === $n) {
continue;
}
$child = $n->toXml(true)->getElementsByTagName('node')->item(0);
$child = $dom->importNode($child, true);
$child->setAttribute('name', $name);
$node->appendChild($child);
}
return $asDom ? $dom : $dom->saveXml();
}
public function compile(Twig_Compiler $compiler)
{
foreach ($this->nodes as $node) {
$node->compile($compiler);
}
}
public function getLine()
{
return $this->lineno;
}
public function getNodeTag()
{
return $this->tag;
}
/**
* Returns true if the attribute is defined.
*
* @param string The attribute name
*
* @return Boolean true if the attribute is defined, false otherwise
*/
public function hasAttribute($name)
{
return array_key_exists($name, $this->attributes);
}
/**
* Gets an attribute.
*
* @param string The attribute name
*
* @return mixed The attribute value
*/
public function getAttribute($name)
{
if (!array_key_exists($name, $this->attributes)) {
throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->attributes[$name];
}
/**
* Sets an attribute.
*
* @param string The attribute name
* @param mixed The attribute value
*/
public function setAttribute($name, $value)
{
$this->attributes[$name] = $value;
}
/**
* Removes an attribute.
*
* @param string The attribute name
*/
public function removeAttribute($name)
{
unset($this->attributes[$name]);
}
/**
* Returns true if the node with the given identifier exists.
*
* @param string The node name
*
* @return Boolean true if the node with the given name exists, false otherwise
*/
public function hasNode($name)
{
return array_key_exists($name, $this->nodes);
}
/**
* Gets a node by name.
*
* @param string The node name
*
* @return Twig_Node A Twig_Node instance
*/
public function getNode($name)
{
if (!array_key_exists($name, $this->nodes)) {
throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
}
return $this->nodes[$name];
}
/**
* Sets a node.
*
* @param string The node name
* @param Twig_Node A Twig_Node instance
*/
public function setNode($name, $node = null)
{
$this->nodes[$name] = $node;
}
/**
* Removes a node by name.
*
* @param string The node name
*/
public function removeNode($name)
{
unset($this->nodes[$name]);
}
public function count()
{
return count($this->nodes);
}
public function getIterator()
{
return new ArrayIterator($this->nodes);
}
}

View File

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents an autoescape node.
*
* The value is the escaping strategy (can be html, js, ...)
*
* The true value is equivalent to html.
*
* If autoescaping is disabled, then the value is false.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_AutoEscape extends Twig_Node
{
public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
{
parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler->subcompile($this->getNode('body'));
}
}

View File

@ -1,44 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a block node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Block extends Twig_Node
{
public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
{
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
->indent()
;
$compiler
->subcompile($this->getNode('body'))
->outdent()
->write("}\n\n")
;
}
}

View File

@ -1,37 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a block call node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
{
public function __construct($name, $lineno, $tag = null)
{
parent::__construct(array(), array('name' => $name), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
;
}
}

View File

@ -1,19 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a body node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Body extends Twig_Node
{
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a do node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Do extends Twig_Node
{
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
{
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('')
->subcompile($this->getNode('expr'))
->raw(";\n")
;
}
}

View File

@ -1,38 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents an embed node.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Node_Embed extends Twig_Node_Include
{
// we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
{
parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
$this->setAttribute('filename', $filename);
$this->setAttribute('index', $index);
}
protected function addGetTemplate(Twig_Compiler $compiler)
{
$compiler
->write("\$this->env->loadTemplate(")
->string($this->getAttribute('filename'))
->raw(', ')
->string($this->getAttribute('index'))
->raw(")")
;
}
}

View File

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Abstract class for all nodes that represents an expression.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Twig_Node_Expression extends Twig_Node
{
}

View File

@ -1,86 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Array extends Twig_Node_Expression
{
protected $index;
public function __construct(array $elements, $lineno)
{
parent::__construct($elements, array(), $lineno);
$this->index = -1;
foreach ($this->getKeyValuePairs() as $pair) {
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
$this->index = $pair['key']->getAttribute('value');
}
}
}
public function getKeyValuePairs()
{
$pairs = array();
foreach (array_chunk($this->nodes, 2) as $pair) {
$pairs[] = array(
'key' => $pair[0],
'value' => $pair[1],
);
}
return $pairs;
}
public function hasElement(Twig_Node_Expression $key)
{
foreach ($this->getKeyValuePairs() as $pair) {
// we compare the string representation of the keys
// to avoid comparing the line numbers which are not relevant here.
if ((string) $key == (string) $pair['key']) {
return true;
}
}
return false;
}
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
{
if (null === $key) {
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
}
array_push($this->nodes, $key, $value);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler->raw('array(');
$first = true;
foreach ($this->getKeyValuePairs() as $pair) {
if (!$first) {
$compiler->raw(', ');
}
$first = false;
$compiler
->subcompile($pair['key'])
->raw(' => ')
->subcompile($pair['value'])
;
}
$compiler->raw(')');
}
}

View File

@ -1,28 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
{
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('$context[')
->string($this->getAttribute('name'))
->raw(']')
;
}
}

View File

@ -1,40 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
{
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
{
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
$compiler
->raw('(')
->subcompile($this->getNode('left'))
->raw(' ')
;
$this->operator($compiler);
$compiler
->raw(' ')
->subcompile($this->getNode('right'))
->raw(')')
;
}
abstract public function operator(Twig_Compiler $compiler);
}

View File

@ -1,18 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('+');
}
}

View File

@ -1,18 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('&&');
}
}

View File

@ -1,18 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('&');
}
}

View File

@ -1,18 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('|');
}
}

View File

@ -1,18 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
{
public function operator(Twig_Compiler $compiler)
{
return $compiler->raw('^');
}
}

Some files were not shown because too many files have changed in this diff Show More