Compare commits

...

145 Commits
3.8.2 ... 3.8.5

Author SHA1 Message Date
Mario Vavti
1044e8e91a version 3.8.5 2018-11-19 11:12:32 +01:00
Mario Vavti
ba4b1cb5af Merge branch 'master' of https://framagit.org/hubzilla/core 2018-11-19 11:10:36 +01:00
Mario Vavti
5cb4cdaa5e changelog 2018-11-19 11:10:22 +01:00
Mario
7be1d9e45a Merge branch 'patch-20181118a' into 'dev'
Patch 20181118a - fix delayed publication of posts

See merge request hubzilla/core!1398

(cherry picked from commit f34af496ec)

3787c490 Fix: delayed items propagate before publication on cloned channels
2018-11-19 10:45:01 +01:00
Mario Vavti
ae97649948 update sql schemas to include update column in pconfig table 2018-11-19 10:42:18 +01:00
Mario Vavti
f15e32d063 recalculate photo filesize when rotating an image 2018-11-17 09:41:26 +01:00
Mario Vavti
afc75af62f strlen($this->imageString()) does not return the correct size when dealing with os_storage images. use filesize() instead. 2018-11-16 22:14:11 +01:00
Mario
2778a7220f Merge branch 'master' into 'master'
delivery issue

See merge request hubzilla/core!1397
2018-11-16 10:29:45 +01:00
zotlabs
26f593afaa delivery issue 2018-11-15 13:52:25 -08:00
Mario Vavti
beac45b075 more changelog 2018-11-14 11:20:39 +01:00
Mario Vavti
dfc5159aa3 Merge branch 'dev' 2018-11-14 11:12:20 +01:00
Mario Vavti
886cdb440b changelog and version 2018-11-14 11:08:25 +01:00
Mario
6ed9443972 Merge branch 'patch-20181113b' into 'dev'
Patch 20181113b

See merge request hubzilla/core!1395
2018-11-14 09:30:54 +01:00
Mario
08e0f172de Merge branch 'dev' into 'dev'
Remove unneccessary fetch_image_from_url() function

See merge request hubzilla/core!1393
2018-11-14 09:30:28 +01:00
DM42.Net (Matt Dent)
f1d168f781 Fix double escaping after xss fix 2018-11-13 23:06:00 -05:00
DM42.Net (Matt Dent)
302d9796c4 Revert "Filter search box before display"
This reverts commit 35e66770be.
2018-11-13 22:59:36 -05:00
M. Dent
1260887fa7 Merge branch 'patch-20181113a' into 'dev'
Patch 20181113a

See merge request hubzilla/core!1394
2018-11-14 03:21:32 +01:00
DM42.Net (Matt Dent)
ce8073d25e Merge remote-tracking branch red/master into patch-20181113a. Add Mike's fix to search xss and Superblock fix. 2018-11-13 20:19:12 -05:00
zotlabs
31f4d9066b xss in search 2018-11-13 14:23:56 -08:00
DM42.Net (Matt Dent)
35e66770be Filter search box before display 2018-11-13 17:20:21 -05:00
Max Kostikov
cf2f7f2132 Update Photo.php 2018-11-13 12:52:35 +01:00
Max Kostikov
a145559662 Remove uneccessary include/photos.php 2018-11-13 11:45:18 +01:00
Max Kostikov
d029e3dc16 Text formatting in Photo.php 2018-11-13 11:39:42 +01:00
Max Kostikov
286326a98e Replace fetch_image_from_url() with z_fetch_url() 2018-11-13 11:38:49 +01:00
Max Kostikov
2f59d78737 Remove fetch_image_from_url() because of functions duplicate 2018-11-13 11:37:32 +01:00
Max Kostikov
adf4782076 Merge branch 'revert-6375f2d7' into 'dev'
Revert "Replace fetch_image_from_url() with z_fetch_url()"

See merge request hubzilla/core!1392
2018-11-13 11:36:02 +01:00
Max Kostikov
b38ffef2be Revert "Replace fetch_image_from_url() with z_fetch_url()"
This reverts commit 6375f2d73a
2018-11-13 11:25:46 +01:00
Max Kostikov
6375f2d73a Replace fetch_image_from_url() with z_fetch_url() 2018-11-13 11:25:14 +01:00
M. Dent
a7d3a49171 Merge branch 'fix-activity-filter-widget' into 'dev'
use the correct javascript function for this case

See merge request hubzilla/core!1390
2018-11-12 21:50:08 +01:00
M. Dent
920e7db709 Merge branch 'css-fixes' into 'dev'
css fixes

See merge request hubzilla/core!1391
2018-11-12 21:49:07 +01:00
zotlabs
4a6b45cf04 enotify::format hook for superblock 2018-11-12 11:13:36 -08:00
Mario Vavti
7bd60adfbe fix css issues in bbcode conversion and focus-light schema 2018-11-12 09:35:12 +01:00
Mario Vavti
c335719e8f use the correct javascript function for this case 2018-11-11 14:46:35 +01:00
Mario Vavti
d57cdf645e Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2018-11-11 14:01:25 +01:00
Mario
e47a96bf24 Merge branch 'dev' into 'dev'
Preserve photo modification date on edit

See merge request hubzilla/core!1389
2018-11-11 13:49:29 +01:00
Mario
daad607c7c Merge branch 'dev' into 'dev'
fix shared_header img expanding to 100% width when sharing a share

See merge request hubzilla/core!1387
2018-11-11 13:47:03 +01:00
Max Kostikov
29f1f9c872 Merge branch 'dev' into 'dev'
# Conflicts:
#   include/photo/photo_driver.php
2018-11-10 20:47:35 +01:00
Max Kostikov
a49cfa8142 Update photo_driver.php 2018-11-10 20:45:20 +01:00
Max Kostikov
b57d296adc Preserve photo modification date 2018-11-10 20:35:14 +01:00
Mario
01d8bd445e Merge branch 'dev' into 'dev'
Remove DNS check for database connection during installation...

See merge request hubzilla/core!1384
2018-11-10 15:02:27 +01:00
Mario Vavti
750d6f4be9 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2018-11-10 12:22:09 +01:00
Max Kostikov
c6e14a696e Fixed wrong value assign on compare with 0 2018-11-10 11:56:34 +01:00
Max Kostikov
d34423fce9 Fixed wrong value assign on compare with 0 2018-11-10 11:53:49 +01:00
Mario
4999547f87 Merge branch 'dev' into 'dev'
Preserve received image modification date on caching

See merge request hubzilla/core!1386
2018-11-10 11:47:20 +01:00
Mario Vavti
fc5dc9717a fix shared_header img expanding to 100% width when sharing a share 2018-11-10 11:31:06 +01:00
Max Kostikov
d20759c141 Do not return default images from vCard 2018-11-10 11:11:23 +01:00
Max Kostikov
f7b00c62a4 Remove unnecessary Zulu timezone mention 2018-11-10 10:05:28 +01:00
Max Kostikov
32873ce70d Preserve received image modification date on caching 2018-11-09 22:20:41 +01:00
Max Kostikov
dc59561a95 Fixed timezone conversion 2018-11-09 22:17:11 +01:00
Mario
4bf3fdd898 Merge branch 'patch-1' into 'dev'
Return image modification date on remote fetch for caching

See merge request hubzilla/core!1383
2018-11-09 16:51:36 +01:00
Andrew Manning
108a892a11 Remove DNS check for database connection during installation. Causes friction with Docker deployment. 2018-11-09 05:31:55 -05:00
Max Kostikov
2c4bd9a3fe Workaround for local resource path to photo from Diaspora 2018-11-09 10:03:58 +01:00
Max Kostikov
098ec1abb4 remove image type double guess by checking HTTP headers 2018-11-08 22:43:17 +01:00
Max Kostikov
17cf824545 Return image modification date using HTTP 'Last-Modified' and '304 Not Modified' on remote fetch for caching 2018-11-08 18:00:18 +01:00
M. Dent
e35f5d3c93 Merge branch 'fix-photo' into 'dev'
Fix photo

See merge request hubzilla/core!1382
2018-11-08 13:09:05 +01:00
Mario
f4f98e5856 Merge branch 'patch-1' into 'fix-photo'
Correct "Content-Length:" calculation added

See merge request mario/core!1
2018-11-08 12:13:00 +01:00
Max Kostikov
dc0335d1d5 Correct "Content-Length:" calculation added 2018-11-08 11:53:27 +01:00
M. Dent
6013814cf4 Merge branch 'fix-photo' into 'dev'
$data only contains the link to the image if the image is in os storage. The…

See merge request hubzilla/core!1379
2018-11-08 11:25:36 +01:00
Mario Vavti
e0a0570cc4 $data only contains the link to the image if the image is in os storage. The size is calculatet wrong in this case and the download fails. rely on filesize from the db for content-length 2018-11-08 11:06:44 +01:00
Mario
61deb4fcfd Merge branch 'patch-1' into 'dev'
Disable image caching if personal or group permissions enabled

See merge request hubzilla/core!1377
2018-11-08 10:25:11 +01:00
Mario Vavti
7c4c60425b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2018-11-08 10:16:17 +01:00
Mario Vavti
302f49baf2 provide a function to log to syslog 2018-11-08 10:12:33 +01:00
Max Kostikov
3f6cd5a663 Disable image caching if personal or group permissions enabled 2018-11-07 19:52:38 +01:00
M. Dent
1b232041c9 Merge branch 'patch-1' into 'dev'
Added `If-Modified-Since` header support for better image caching and fixed absent 404 for photos

See merge request hubzilla/core!1375
2018-11-07 18:22:55 +01:00
Max Kostikov
eaf117cce1 Added If-Modified-Since header support for better image caching and fixed absent 404 for photos 2018-11-07 18:22:55 +01:00
zotlabs
7148311953 Merge branch 'dev' of https://framagit.org/hubzilla/core into xdev_merge 2018-11-07 01:43:26 -08:00
Mario Vavti
c23dfa0d23 Merge remote-tracking branch 'mike/master' into dev 2018-11-07 10:15:40 +01:00
Mario Vavti
b08de33b0b fix es-es hstrings.php 2018-11-07 10:02:24 +01:00
Mario
fc1d8c0138 Merge branch 'revert-40d9277e' into 'dev'
Revert "remove 'Expiries' HTTP header"

See merge request hubzilla/core!1372
2018-11-07 09:36:30 +01:00
Max Kostikov
a5a77d1e7c Revert "remove 'Expiries' HTTP header"
This reverts commit 40d9277ef3
2018-11-07 08:41:32 +01:00
zotlabs
f57fcefe6b signature issue 2018-11-06 21:45:43 -08:00
M. Dent
6c6dca05e7 Merge branch 'patch-25' into 'dev'
'Last-Modified' and 'Content-Length' HTTP headers added for better image caching

See merge request hubzilla/core!1369
2018-11-06 19:25:38 +01:00
M. Dent
97b4a31b16 Merge branch 'patch-26' into 'dev'
New plural functions for JavaScript compatibility

See merge request hubzilla/core!1370
2018-11-06 18:26:58 +01:00
Max Kostikov
40d9277ef3 remove 'Expiries' HTTP header 2018-11-06 16:22:34 +01:00
Max Kostikov
009044b71e Update hmessages.po 2018-11-06 14:58:06 +01:00
Max Kostikov
4760a3f3e8 Update hmessages.po 2018-11-06 14:57:12 +01:00
Max Kostikov
3302012c02 New pt-br plural function for JavaScript compatibility 2018-11-06 14:55:58 +01:00
Max Kostikov
812c5a314f New nl plural function for JavaScript compatibility 2018-11-06 14:55:21 +01:00
Max Kostikov
c2da8c3fd4 New nb-no plural function for JavaScript compatibility 2018-11-06 14:54:49 +01:00
Max Kostikov
aa78640491 New it plural function for JavaScript compatibility 2018-11-06 14:54:06 +01:00
Max Kostikov
7c49688e1b New he plural function for JavaScript compatibility 2018-11-06 14:53:29 +01:00
Max Kostikov
dbe10c7965 New fi plural function for JavaScript compatibility 2018-11-06 14:52:58 +01:00
Max Kostikov
f1f5107282 New es plural function for JavaScript compatibility 2018-11-06 14:52:23 +01:00
Max Kostikov
cc06250bf8 New fr plural function for JavaScript compatibility 2018-11-06 14:50:37 +01:00
Max Kostikov
af1ea7f495 New plural function for JavaScript compatibility 2018-11-06 14:48:58 +01:00
Max Kostikov
3491c488d3 Update Photo.php 2018-11-06 13:51:01 +01:00
Max Kostikov
1828b6daab Update Photo.php 2018-11-06 13:41:41 +01:00
Max Kostikov
c26f45b7c2 Update Photo.php 2018-11-06 13:39:36 +01:00
Max Kostikov
e116b90116 'Last-Modified' and 'Content-Length' HTTP headers added for better image caching 2018-11-06 13:37:50 +01:00
zotlabs
43a5f928ba these changes needed to ensure cloning/syncing works in the future to non-zot6 enabled servers after the (coming) zot6 schema updates. This should probably be on a fast track to master branch 2018-11-05 16:57:32 -08:00
M. Dent
873fa16517 Merge branch 'patch-23' into 'dev'
Use modern get_config() syntax

See merge request hubzilla/core!1368
2018-11-06 01:27:06 +01:00
Max Kostikov
f7ce374a28 Update Photo.php 2018-11-05 21:26:10 +01:00
Max Kostikov
2dd124d09e Use modern get_config() syntax 2018-11-05 21:25:08 +01:00
Mario
d6523c67a6 Merge branch 'patch-20181028a' into 'dev'
Add timestamp to pconfig

See merge request hubzilla/core!1355
2018-11-05 10:40:29 +01:00
Mario Vavti
a9fd3608ea version 3.8.3 2018-11-05 10:26:59 +01:00
Mario Vavti
b25cace3ea update changelog 2018-11-05 10:25:57 +01:00
Mario Vavti
4320f047db update changelog and bump version 2018-11-05 10:22:56 +01:00
Mario Vavti
b4b3e7b9a4 update linkinfo from dev 2018-11-05 09:59:25 +01:00
Mario Vavti
b6938da552 Merge remote-tracking branch 'mike/master' into dev 2018-11-05 09:56:52 +01:00
Mario Vavti
4830a1559d Merge branch 'dev' 2018-11-05 09:55:23 +01:00
Mario
92ea3ef720 Merge branch 'dev' into 'dev'
more fixes for forum notifications handling: do not count likes/dislikes if…

See merge request hubzilla/core!1367
2018-11-05 09:42:07 +01:00
zotlabs
73d2719330 debug zot6 discovery 2018-11-04 19:35:55 -08:00
zotlabs
af82aab3a6 Merge branch 'dev' of https://framagit.org/hubzilla/core into xdev_merge 2018-11-04 13:58:02 -08:00
zotlabs
51b4b6216f z6 updates to owa, linkinfo improved image detection 2018-11-04 13:56:32 -08:00
Mario Vavti
de32b0bba5 more fixes for forum notifications handling: do not count likes/dislikes if likes notifications are disabled and also do not show like activities when clicking a forum notification and like notifications are disabled 2018-11-03 20:53:23 +01:00
Mario
de0fab78ed Merge branch 'dev' into 'dev'
Fixed typo at view/es-es/hstrings.php

See merge request hubzilla/core!1366
2018-11-03 20:11:14 +01:00
Manuel Jiménez Friaza
71425c3b23 Fixed typo at view/es-es/hstrings.php 2018-11-03 19:19:01 +01:00
Mario
75f7b1e261 Merge branch 'patch-3' into 'dev'
Update hmessages.po

See merge request hubzilla/core!1365
2018-11-03 13:22:34 +01:00
Mario
9af35d998f Merge branch 'patch-2' into 'dev'
Update hstrings.php

See merge request hubzilla/core!1364
2018-11-03 13:21:53 +01:00
Mario
34e3f3907a Merge branch 'patch-22' into 'dev'
More precise content encoding detection on conversion

See merge request hubzilla/core!1363
2018-11-03 13:21:22 +01:00
Max Kostikov
46b0510b99 Update Linkinfo.php 2018-11-03 10:41:31 +01:00
Max Kostikov
a7624ea48b Update Linkinfo.php 2018-11-03 00:10:05 +01:00
Max Kostikov
2f3b4a7aaf Update Linkinfo.php 2018-11-03 00:01:15 +01:00
Max Kostikov
a9bbe0b128 Update Linkinfo.php 2018-11-02 22:40:48 +01:00
Max Kostikov
0d9d0a4b70 more precise codepage detection 2018-11-02 22:37:53 +01:00
gia vec
8235d0bd50 Update hmessages.po 2018-11-02 19:41:07 +01:00
gia vec
c2e01bedc5 Update hstrings.php 2018-11-02 19:27:11 +01:00
Max Kostikov
32c4614a32 Workaround for incorrect ISO-8859-5 encoded content conversion 2018-11-02 10:52:52 +01:00
Mario
24ae6c91ea Merge branch 'patch-21' into 'dev'
Fix wrong image resize for some external images

See merge request hubzilla/core!1362
2018-11-02 10:20:18 +01:00
M.Dent
346a4f5933 strpos needs to test with ===0 not ==0 2018-11-01 20:23:22 -04:00
Max Kostikov
c6551336c8 Fix wrong image resize for some external images 2018-11-01 21:50:36 +01:00
Mario Vavti
3dab0d365d css fix for reshared-content images and whitespace 2018-10-31 13:20:09 +01:00
Mario Vavti
0252bac4ba Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2018-10-31 09:39:10 +01:00
Mario
b468069875 Merge branch 'patch-20' into 'dev'
Beautiful embedding for Hubzilla links

See merge request hubzilla/core!1360
2018-10-31 09:36:09 +01:00
Mike Macgirvin
7e1f431eca yet another blueimp vulnerability. Move to composer. 2018-10-31 15:56:08 +11:00
zotlabs
70c55da1df Merge branch 'dev' of https://framagit.org/hubzilla/core into xdev_merge 2018-10-30 18:11:49 -07:00
M. Dent
f9ab7647dd Merge branch 'composer-updates' into 'dev'
update html_to_markdown, smarty and sabredav libs via composer

See merge request hubzilla/core!1361
2018-10-31 01:32:44 +01:00
zotlabs
623aa7ea48 remove primary/clone counts from admin summary. The last checkins should fix this count "eventually" but the information has little direct value and may require location information for a local channel to change before it is actually corrected. 2018-10-30 17:30:59 -07:00
M. Dent
046d264688 Merge branch 'forum-ping' into 'dev'
fix forum ping results - the term query requires xchan_name instead of…

See merge request hubzilla/core!1358
2018-10-31 01:25:41 +01:00
M. Dent
944e168120 Merge branch 'wikilist-widget' into 'dev'
allow wiki_list widget to be used in any page

See merge request hubzilla/core!1359
2018-10-31 01:24:32 +01:00
zotlabs
9594105e57 typo 2018-10-30 17:21:39 -07:00
zotlabs
675343f575 issue syncing the channel_primary setting which shows up as a wrong count on the admin summary page 2018-10-30 17:18:15 -07:00
Mario Vavti
fc6ff45c49 fix another markdown test 2018-10-30 22:51:52 +01:00
Mario Vavti
b4bac88c39 fix markdown tests 2018-10-30 22:37:41 +01:00
Mario Vavti
c622ba84b9 really fix html2markdown() - when using environment, we must set the defaults 2018-10-30 22:16:37 +01:00
Max Kostikov
339f95c647 Update oembed.php 2018-10-30 16:49:48 +01:00
Max Kostikov
ec67e0ab22 Beautiful embedding for Hubzilla links 2018-10-30 15:38:19 +01:00
Mario Vavti
0b371c8103 fix html2markdown() and re-enable previously failing tests 2018-10-30 13:55:08 +01:00
Mario Vavti
2192ea6fdf update html_to_markdown, smarty and sabredav libs via composer 2018-10-30 12:12:07 +01:00
M.Dent
0060f88c45 Add tracking of deleted pconfig variables 2018-10-29 23:04:13 -04:00
Mario Vavti
1eac4db491 fix forum ping results - the term query requires xchan_name instead of xchan_hash. also improve the query itself - item_permission_sql() is redundant here since we always deal with local_channel() and use count(id) instead of sum(item_unseen) to get the unseen count 2018-10-29 23:01:13 +01:00
Mario Vavti
0d2c3be367 allow wiki_list widget to be used in any page 2018-10-29 22:55:24 +01:00
M.Dent
1241e778f9 Fix to set update time in pconfig on update 2018-10-28 17:30:22 -04:00
M.Dent
3ab0ef1902 Add timestamp and associated logic to pconfig 2018-10-28 17:23:31 -04:00
M.Dent
c7c35b8b5a DB Updates to prep for pconfig timestamps. 2018-10-28 17:20:29 -04:00
346 changed files with 7443 additions and 5782 deletions

View File

@@ -1,3 +1,46 @@
Hubzilla 3.8.5 (2018-11-19)
- Fix pconfig for new installs
- Fix delayed publication of posts in combination with channel clones
- Fix issue where photo filesize was not updated in the DB when a photo was edited
- Fix issue where the original photo size was not set correct in the DB
- Fix delivery issue in zot_fetch()
- Fix typo in channel reputation addon
Hubzilla 3.8.4 (2018-11-14)
- Fix xss issue (thanks to Eduardo)
- Implement hook in enotify to be used by superblock
- Various css fixes
- Improve photo cache handling
- Provide a function hz_syslog() to log to syslog
- Fix request_target in z_post_url()
- Fix plural handling for various languages
- Some preparatory work for zot6
- Fix warning in gallery addon
- Fix date issue on xchan photo update in diaspora and pubcrawl addons
- Fix typos in startpage addon
- Improve activitypub addressing
- Fix taxonomy in activitypub direct messages
- Fix syntax error in diaspora addon
- New e-learning addon flashcards
- Remove DNS check for database connection during installation
- Implement timestamps for pconfig
Hubzilla 3.8.3 (2018-11-05)
- Do not count likes in forum notifications if likes notifications are disabled
- Fix typo in spanish translation which broke javascript
- Improve linkinfo charset handling and image detection
- Fix wrong image resize for some external images
- Move blueimp upload lib to composer and update to version 9.25
- Remove primary/clone counts from admin summary until we have a mechanism to update the fixed counts
- Fix html2markdown() and re-enable previously failing tests
- Improve look of oembed content for Hubzilla links
- Fix forum notifications count not correct
- Fix gallery addon which broke mod apps in some situations
- Fix wiki_list widget not working on every page respectively level
Hubzilla 3.8.2 (2018-10-29)
- Merge unmerged changes from dev into master
- Fix issues with forum handling in mod network and ping

View File

@@ -825,7 +825,7 @@ class Enotify {
// convert this logic into a json array just like the system notifications
return array(
$x = array(
'notify_link' => $item['llink'],
'name' => $item['author']['xchan_name'],
'url' => $item['author']['xchan_url'],
@@ -835,9 +835,19 @@ class Enotify {
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
'notify_id' => 'undefined',
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text))
'message' => strip_tags(bbcode($itemem_text)),
// these are for the superblock addon
'hash' => $item['author']['xchan_hash'],
'uid' => local_channel(),
'display' => true
);
call_hooks('enotify_format',$x);
if(! $x['display']) {
return [];
}
return $x;
}
}

View File

@@ -7,16 +7,10 @@ namespace Zotlabs\Lib;
*
*/
use Zotlabs\Lib\DReport;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\Group;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\System;
use Zotlabs\Lib\MessageFilter;
use Zotlabs\Lib\Queue;
use Zotlabs\Lib\Zotfinger;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
require_once('include/crypto.php');
@@ -211,9 +205,10 @@ class Libzot {
if($channel) {
$headers = [
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Content-type' => 'application/x-zot+json'
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
'Content-type' => 'application/x-zot+json',
'(request-target)' => 'post ' . get_request_string($url)
];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false,'sha512',
@@ -378,13 +373,13 @@ class Libzot {
else {
// if we were just granted read stream permission and didn't have it before, try to pull in some posts
if((! $old_read_stream_perm) && (intval($permissions['view_stream'])))
\Zotlabs\Daemon\Master::Summon(array('Onepoll',$r[0]['abook_id']));
Master::Summon([ 'Onepoll', $r[0]['abook_id'] ]);
}
}
else {
$p = \Zotlabs\Access\Permissions::connect_perms($channel['channel_id']);
$my_perms = \Zotlabs\Access\Permissions::serialise($p['perms']);
$p = Permissions::connect_perms($channel['channel_id']);
$my_perms = Permissions::serialise($p['perms']);
$automatic = $p['automatic'];
@@ -424,8 +419,8 @@ class Libzot {
);
if($new_connection) {
if(! \Zotlabs\Access\Permissions::PermsCompare($new_perms,$previous_perms))
\Zotlabs\Daemon\Master::Summon(array('Notifier','permissions_create',$new_connection[0]['abook_id']));
if(! Permissions::PermsCompare($new_perms,$previous_perms))
Master::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]);
Enotify::submit(
[
'type' => NOTIFY_INTRO,
@@ -438,7 +433,7 @@ class Libzot {
if(intval($permissions['view_stream'])) {
if(intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING)
|| (! intval($new_connection[0]['abook_pending'])))
\Zotlabs\Daemon\Master::Summon(array('Onepoll',$new_connection[0]['abook_id']));
Master::Summon([ 'Onepoll', $new_connection[0]['abook_id'] ]);
}
@@ -975,39 +970,45 @@ class Libzot {
$x = json_decode($x,true);
}
if(! $x['success']) {
// handle remote validation issues
$b = q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc(($x['message']) ? $x['message'] : 'unknown delivery error'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
if(! is_array($x)) {
btlogger('failed communication - no response');
}
if(array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) {
foreach($x['delivery_report'] as $xx) {
if(is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s','%s','%s','%s','%s' ) ",
dbesc($xx['message_id']),
dbesc($xx['location']),
dbesc($xx['recipient']),
dbesc($xx['name']),
dbesc($xx['status']),
dbesc(datetime_convert($xx['date'])),
dbesc($xx['sender'])
);
}
if($x) {
if(! $x['success']) {
// handle remote validation issues
$b = q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'",
dbesc(($x['message']) ? $x['message'] : 'unknown delivery error'),
dbesc(datetime_convert()),
dbesc($outq['outq_hash'])
);
}
// we have a more descriptive delivery report, so discard the per hub 'queue' report.
if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) {
foreach($x['delivery_report'] as $xx) {
call_hooks('dreport_process',$xx);
if(is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s','%s','%s','%s','%s' ) ",
dbesc($xx['message_id']),
dbesc($xx['location']),
dbesc($xx['recipient']),
dbesc($xx['name']),
dbesc($xx['status']),
dbesc(datetime_convert($xx['date'])),
dbesc($xx['sender'])
);
}
}
q("delete from dreport where dreport_queue = '%s' ",
dbesc($outq['outq_hash'])
);
// we have a more descriptive delivery report, so discard the per hub 'queue' report.
q("delete from dreport where dreport_queue = '%s' ",
dbesc($outq['outq_hash'])
);
}
}
// update the timestamp for this site
q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'",
@@ -1092,13 +1093,27 @@ class Libzot {
return;
}
$message_request = ((array_key_exists('message_id',$env)) ? true : false);
if($message_request)
logger('processing message request');
$message_request = false;
$has_data = array_key_exists('data',$env) && $env['data'];
$data = (($has_data) ? $env['data'] : false);
$AS = null;
if($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
if(! $AS->is_valid()) {
logger('Activity rejected: ' . print_r($data,true));
return;
}
$arr = Activity::decode_note($AS);
logger($AS->debug());
}
$deliveries = null;
if(array_key_exists('recipients',$env) && count($env['recipients'])) {
@@ -1140,7 +1155,7 @@ class Libzot {
// and who are allowed to see them based on the sender's permissions
// @fixme;
$deliveries = self::public_recips($env);
$deliveries = self::public_recips($env,$AS);
}
@@ -1157,49 +1172,43 @@ class Libzot {
if(in_array($env['type'],['activity','response'])) {
if($env['encoding'] === 'zot') {
$arr = get_item_elements($data);
$v = validate_item_elements($data,$arr);
if(! $v['success']) {
logger('Activity rejected: ' . $v['message'] . ' ' . print_r($data,true));
return;
}
$arr = Activity::decode_note($AS);
//logger($AS->debug());
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($AS->actor['id'])
);
if($r) {
$arr['author_xchan'] = $r[0]['hubloc_hash'];
}
elseif($env['encoding'] === 'activitystreams') {
$AS = new \Zotlabs\Lib\ActivityStreams($data);
if(! $AS->is_valid()) {
logger('Activity rejected: ' . print_r($data,true));
return;
}
$arr = \Zotlabs\Lib\Activity::decode_note($AS);
logger($AS->debug());
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($env['sender'])
);
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($AS->actor['id'])
);
if($r) {
$arr['author_xchan'] = $r[0]['hubloc_hash'];
}
// @fixme (in individual delivery, change owner if needed)
// in individual delivery, change owner if needed
if($s) {
$arr['owner_xchan'] = $s[0]['hubloc_hash'];
}
else {
$arr['owner_xchan'] = $env['sender'];
if($private) {
$arr['item_private'] = true;
}
// @fixme - spoofable
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}
}
if($private) {
$arr['item_private'] = true;
}
// @fixme - spoofable
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}
logger('Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
@@ -1225,15 +1234,31 @@ class Libzot {
}
static function is_top_level($env) {
static function is_top_level($env,$act) {
if($env['encoding'] === 'zot' && array_key_exists('flags',$env) && in_array('thread_parent', $env['flags'])) {
return true;
}
if($env['encoding'] === 'activitystreams') {
if(array_key_exists('inReplyTo',$env['data']) && $env['data']['inReplyTo']) {
if($act) {
if(in_array($act->type, ['Like','Dislike'])) {
return false;
}
return true;
$x = self::find_parent($env,$act);
if($x === $act->id || $x === $act->obj['id']) {
return true;
}
}
return false;
}
static function find_parent($env,$act) {
if($act) {
if(in_array($act->type, ['Like','Dislike'])) {
return $act->obj['id'];
}
if($act->parent_id) {
return $act->parent_id;
}
}
return false;
}
@@ -1255,7 +1280,7 @@ class Libzot {
* @return NULL|array
*/
static function public_recips($msg) {
static function public_recips($msg, $act) {
require_once('include/channel.php');
@@ -1269,7 +1294,7 @@ class Libzot {
$perm = 'send_stream';
if(self::is_top_level($msg)) {
if(self::is_top_level($msg,$act)) {
$check_mentions = true;
}
}
@@ -1301,9 +1326,9 @@ class Libzot {
if($check_mentions) {
// It's a top level post. Look at the tags. See if any of them are mentions and are on this hub.
if(array_path_exists('data/object/tag',$msg)) {
if(is_array($msg['data']['object']['tag']) && $msg['data']['object']['tag']) {
foreach($msg['data']['object']['tag'] as $tag) {
if($act && $act->obj) {
if(is_array($act->obj['tag']) && $act->obj['tag']) {
foreach($act->obj['tag'] as $tag) {
if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) {
$address = basename($tag['href']);
if($address) {
@@ -1325,9 +1350,12 @@ class Libzot {
// everybody that stored a copy of the parent. This way we know we're covered. We'll check the
// comment permissions when we deliver them.
if(array_path_exists('data/inReplyTo',$msg)) {
$z = q("select owner_xchan as hash from item where parent_mid = '%s' ",
dbesc($msg['data']['inReplyTo'])
$thread_parent = self::find_parent($msg,$act);
if($thread_parent) {
$z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
dbesc($thread_parent),
dbesc($thread_parent)
);
if($z) {
foreach($z as $zv) {
@@ -1341,7 +1369,7 @@ class Libzot {
// It's a bit of work since it's a multi-dimensional array
if($r) {
$r = array_unique($r);
$r = array_values(array_unique($r));
}
logger('public_recips: ' . print_r($r,true), LOGGER_DATA, LOG_DEBUG);
@@ -1378,7 +1406,7 @@ class Libzot {
$local_public = $public;
$DR = new \Zotlabs\Lib\DReport(z_root(),$sender,$d,$arr['mid']);
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
$channel = channelx_by_hash($d);
@@ -1413,7 +1441,7 @@ class Libzot {
$local_public = true;
$r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1",
dbesc($sender['hash'])
dbesc($sender)
);
// don't import sys channel posts from selfcensored authors
if($r && (intval($r[0]['xchan_selfcensored']))) {
@@ -1441,11 +1469,30 @@ class Libzot {
$arr['item_wall'] = 0;
}
if((! perm_is_allowed($channel['channel_id'],$sender,$perm)) && (! $tag_delivery) && (! $local_public)) {
logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
$friendofriend = false;
if ((! $tag_delivery) && (! $local_public)) {
$allowed = (perm_is_allowed($channel['channel_id'],$sender,$perm));
if((! $allowed) && $perm === 'post_comments') {
$parent = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
if ($parent) {
$allowed = can_comment_on_post($d,$parent[0]);
}
}
if($request) {
$allowed = true;
$friendofriend = true;
}
if (! $allowed) {
logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
}
}
if($arr['mid'] != $arr['parent_mid']) {
@@ -1456,7 +1503,7 @@ class Libzot {
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
$r = q("select route, id from item where mid = '%s' and uid = %d limit 1",
$r = q("select route, id, owner_xchan, item_private from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
@@ -1480,15 +1527,21 @@ class Libzot {
if((! $relay) && (! $request) && (! $local_public)
&& perm_is_allowed($channel['channel_id'],$sender,'send_stream')) {
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'request', $channel['channel_id'], $sender, $arr['parent_mid']));
self::fetch_conversation($channel,$arr['parent_mid']);
}
continue;
}
if($relay) {
if($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
// reset the route in case it travelled a great distance upstream
// use our parent's route so when we go back downstream we'll match
// with whatever route our parent has.
// Also friend-of-friend conversations may have been imported without a route,
// but we are now getting comments via listener delivery
// and if there is no privacy on this or the parent, we don't care about the route,
// so just set the owner and route accordingly.
$arr['route'] = $r[0]['route'];
$arr['owner_xchan'] = $r[0]['owner_xchan'];
}
else {
@@ -1546,13 +1599,13 @@ class Libzot {
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
$item_id = delete_imported_item($sender,$arr,$channel['channel_id'],$relay);
$item_id = self::delete_imported_item($sender,$arr,$channel['channel_id'],$relay);
$DR->update(($item_id) ? 'deleted' : 'delete_failed');
$result[] = $DR->get();
if($relay && $item_id) {
logger('process_delivery: invoking relay');
\Zotlabs\Daemon\Master::Summon(array('Notifier','relay',intval($item_id)));
Master::Summon([ 'Notifier', 'relay', intval($item_id) ]);
$DR->update('relayed');
$result[] = $DR->get();
}
@@ -1662,7 +1715,7 @@ class Libzot {
if($relay && $item_id) {
logger('Invoking relay');
\Zotlabs\Daemon\Master::Summon(array('Notifier','relay',intval($item_id)));
Master::Summon([ 'Notifier', 'relay', intval($item_id) ]);
$DR->addto_update('relayed');
$result[] = $DR->get();
}
@@ -1676,6 +1729,98 @@ class Libzot {
return $result;
}
static public function fetch_conversation($channel,$mid) {
// Use Zotfinger to create a signed request
$a = Zotfinger::exec($mid,$channel);
logger('received conversation: ' . print_r($a,true), LOGGER_DATA);
if($a['data']['type'] !== 'OrderedCollection') {
return;
}
if(! intval($a['data']['totalItems'])) {
return;
}
$ret = [];
foreach($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity);
if(! $AS->is_valid()) {
logger('FOF Activity rejected: ' . print_r($activity,true));
continue;
}
$arr = Activity::decode_note($AS);
logger($AS->debug());
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($AS->actor['id'])
);
if(! $r) {
$y = import_author_xchan([ 'url' => $AS->actor['id'] ]);
if($y) {
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($AS->actor['id'])
);
}
if(! $r) {
logger('FOF Activity: no actor');
continue;
}
}
if($AS->obj['actor'] && $AS->obj['actor']['id'] && $AS->obj['actor']['id'] !== $AS->actor['id']) {
$y = import_author_xchan([ 'url' => $AS->obj['actor']['id'] ]);
if(! $y) {
logger('FOF Activity: no object actor');
continue;
}
}
if($r) {
$arr['author_xchan'] = $r[0]['hubloc_hash'];
}
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
dbesc($a['signature']['signer'])
);
if($s) {
$arr['owner_xchan'] = $s[0]['hubloc_hash'];
}
else {
$arr['owner_xchan'] = $a['signature']['signer'];
}
// @fixme - spoofable
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}
logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
$result = self::process_delivery($arr['owner_xchan'],$arr, [ $channel['channel_hash'] ],false,false,true);
if ($result) {
$ret = array_merge($ret, $result);
}
}
return $ret;
}
/**
* @brief Remove community tag.
*
@@ -1900,7 +2045,7 @@ class Libzot {
foreach($deliveries as $d) {
$DR = new \Zotlabs\Lib\DReport(z_root(),$sender,$d,$arr['mid']);
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
@@ -2112,7 +2257,8 @@ class Libzot {
if(intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root())
$hub['hubloc_deleted'] = 1;
$ret[] = [
$z = [
'host' => $hub['hubloc_host'],
'address' => $hub['hubloc_addr'],
'id_url' => $hub['hubloc_id_url'],
@@ -2120,10 +2266,25 @@ class Libzot {
'url' => $hub['hubloc_url'],
'url_sig' => $hub['hubloc_url_sig'],
'site_id' => $hub['hubloc_site_id'],
'callback' => $hub['hubloc_callback'],
'callback' => $hub['hubloc_url'] . '/zot',
'sitekey' => $hub['hubloc_sitekey'],
'deleted' => (intval($hub['hubloc_deleted']) ? true : false)
];
// version compatibility tweaks
if(! strpos($z['url_sig'],'.')) {
$z['url_sig'] = 'sha256.' . $z['url_sig'];
}
if(! $z['id_url']) {
$z['id_url'] = $z['url'] . '/channel/' . substr($z['address'],0,strpos($z['address'],'@'));
}
if(! $z['site_id']) {
$z['site_id'] = Libzot::make_xchan_hash($z['url'],$z['sitekey']);
}
$ret[] = $z;
}
}
@@ -2331,6 +2492,10 @@ class Libzot {
// we may only end up with one; which results in posts with no author name or photo and are a bit
// of a hassle to repair. If either or both are missing, do a full discovery probe.
if(! array_key_exists('id',$x)) {
return import_author_activitypub($x);
}
$hash = self::make_xchan_hash($x['id'],$x['key']);
$desturl = $x['url'];
@@ -2502,7 +2667,7 @@ class Libzot {
}
else {
// check if it has characteristics of a public forum based on custom permissions.
$m = \Zotlabs\Access\Permissions::FilledAutoperms($e['channel_id']);
$m = Permissions::FilledAutoperms($e['channel_id']);
if($m) {
foreach($m as $k => $v) {
if($k == 'tag_deliver' && intval($v) == 1)
@@ -2584,13 +2749,13 @@ class Libzot {
];
$ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom');
$ret['protocols'] = [ 'zot6' ];
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
$ret['comments'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($e['channel_id'],'post_comments'));
$ret['mail'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($e['channel_id'],'post_mail'));
$ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_comments'));
$ret['mail'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_mail'));
if($deleted)
$ret['deleted'] = $deleted;

View File

@@ -57,6 +57,7 @@ class PConfig {
\App::$config[$uid][$c]['config_loaded'] = true;
}
\App::$config[$uid][$c][$k] = $rr['v'];
\App::$config[$uid][$c]['pcfgud:'.$k] = $rr['updated'];
}
}
}
@@ -113,7 +114,7 @@ class PConfig {
* The value to store
* @return mixed Stored $value or false
*/
static public function Set($uid, $family, $key, $value) {
static public function Set($uid, $family, $key, $value, $updated=NULL) {
// this catches subtle errors where this function has been called
// with local_channel() when not logged in (which returns false)
@@ -130,29 +131,74 @@ class PConfig {
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if (! $updated) {
$updated = datetime_convert();
}
$hash = hash('sha256',$family.':'.$key);
if (self::Get($uid, 'hz_delpconfig', $hash) !== false) {
if (Get($uid, 'hz_delpconfig', $hash) > $updated) {
logger('Refusing to update pconfig with outdated info (Item deleted more recently).', LOGGER_NORMAL, LOG_ERR);
return self::Get($uid,$family,$key);
} else {
self::Delete($uid,'hz_delpconfig',$hash);
}
}
if(self::Get($uid, $family, $key) === false) {
if(! array_key_exists($uid, \App::$config))
\App::$config[$uid] = array();
if(! array_key_exists($family, \App::$config[$uid]))
\App::$config[$uid][$family] = array();
$ret = q("INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ",
$ret = q("INSERT INTO pconfig ( uid, cat, k, v, updated ) VALUES ( %d, '%s', '%s', '%s', '%s' ) ",
intval($uid),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
dbesc($dbvalue),
dbesc($updated)
);
// There is a possible race condition if another process happens
// to insert something after this thread has Loaded and now. We should
// at least make a note of it if it happens.
if (!$ret) {
logger("Error: Insert to pconfig failed.",LOGGER_NORMAL, LOG_ERR);
}
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
}
else {
$new = (\App::$config[$uid][$family]['pcfgud:'.$key] < $updated);
$ret = q("UPDATE pconfig SET v = '%s' WHERE uid = %d and cat = '%s' AND k = '%s'",
dbesc($dbvalue),
intval($uid),
dbesc($family),
dbesc($key)
);
if ($new) {
// @NOTE There is still a possible race condition under limited circumstances
// where a value will be updated by another thread with more current data than
// we have. At this point there is no easy way to test for it, so we update
// and hope for the best.
$ret = q("UPDATE pconfig SET v = '%s', updated = '%s' WHERE uid = %d and cat = '%s' AND k = '%s' ",
dbesc($dbvalue),
dbesc($updated),
intval($uid),
dbesc($family),
dbesc($key)
);
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
} else {
logger('Refusing to update pconfig with outdated info.', LOGGER_NORMAL, LOG_ERR);
return self::Get($uid, $family, $key);
}
}
// keep a separate copy for all variables which were
// set in the life of this page. We need this to
// synchronise channel clones.
@@ -163,7 +209,11 @@ class PConfig {
\App::$config[$uid]['transient'][$family] = array();
\App::$config[$uid][$family][$key] = $value;
\App::$config[$uid]['transient'][$family][$key] = $value;
if ($new) {
\App::$config[$uid]['transient'][$family][$key] = $value;
\App::$config[$uid]['transient'][$family]['pcfgud:'.$key] = $updated;
}
if($ret)
return $value;
@@ -186,18 +236,29 @@ class PConfig {
* The configuration key to delete
* @return mixed
*/
static public function Delete($uid, $family, $key) {
static public function Delete($uid, $family, $key, $updated = NULL) {
if(is_null($uid) || $uid === false)
return false;
$updated = ($updated) ? $updated : datetime_convert();
$newer = (\App::$config[$uid][$family]['pcfgud:'.$key] < $updated);
if (! $newer) {
logger('Refusing to delete pconfig with outdated delete request.', LOGGER_NORMAL, LOG_ERR);
return false;
}
$ret = false;
if(array_key_exists($uid,\App::$config)
&& is_array(\App::$config['uid'])
&& array_key_exists($family,\App::$config['uid'])
&& array_key_exists($key, \App::$config[$uid][$family]))
if (isset(\App::$config[$uid][$family][$key])) {
unset(\App::$config[$uid][$family][$key]);
}
if (isset(\App::$config[$uid][$family]['pcfgud:'.$key])) {
unset(\App::$config[$uid][$family]['pcfgud:'.$key]);
}
$ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
intval($uid),
@@ -205,6 +266,22 @@ class PConfig {
dbesc($key)
);
if ($family != 'hz_delpconfig') {
$hash = hash('sha256',$family.':'.$key);
set_pconfig($uid,'hz_delpconfig',$hash,$updated);
}
// Synchronize delete with clones.
if(! array_key_exists('transient', \App::$config[$uid]))
\App::$config[$uid]['transient'] = array();
if(! array_key_exists($family, \App::$config[$uid]['transient']))
\App::$config[$uid]['transient'][$family] = array();
if ($new) {
\App::$config[$uid]['transient'][$family]['pcfgdel:'.$key] = $updated;
}
return $ret;
}

View File

@@ -109,11 +109,9 @@ class Admin extends \Zotlabs\Web\Controller {
// available channels, primary and clones
$channels = array();
$r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0 and channel_system = 0");
$r = q("SELECT COUNT(*) AS total FROM channel WHERE channel_removed = 0 and channel_system = 0");
if ($r) {
$channels['total'] = array('label' => t('Channels'), 'val' => $r[0]['total']);
$channels['main'] = array('label' => t('Primary'), 'val' => $r[0]['main']);
$channels['clones'] = array('label' => t('Clones'), 'val' => $r[0]['clones']);
}
// We can do better, but this is a quick queue status

View File

@@ -228,8 +228,13 @@ class Linkinfo extends \Zotlabs\Web\Controller {
$header = $result['header'];
$body = $result['body'];
// Check codepage in HTTP headers or HTML if not exist
$cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : '');
if(empty($cp))
$cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO');
$body = mb_convert_encoding($body, 'UTF-8', (preg_match('/meta.+content=["|\']text\/html;\s+charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'UTF-8'));
$body = mb_convert_encoding($body, 'UTF-8', $cp);
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$doc = new \DOMDocument();
@@ -265,20 +270,43 @@ class Linkinfo extends \Zotlabs\Web\Controller {
$attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8");
switch (strtolower($attr["name"])) {
case 'generator':
$siteinfo['generator'] = $attr['content'];
break;
case "fulltitle":
$siteinfo["title"] = $attr["content"];
$siteinfo["title"] = trim($attr["content"]);
break;
case "description":
$siteinfo["text"] = $attr["content"];
$siteinfo["text"] = trim($attr["content"]);
break;
case "thumbnail":
$siteinfo["image"] = $attr["content"];
break;
case "twitter:image":
$siteinfo["image"] = $attr["content"];
break;
case "twitter:image:src":
$siteinfo["image"] = $attr["content"];
break;
case "twitter:card":
if (($siteinfo["type"] == "") || ($attr["content"] == "photo")) {
$siteinfo["type"] = $attr["content"];
}
break;
case "twitter:description":
$siteinfo["text"] = trim($attr["content"]);
break;
case "twitter:title":
$siteinfo["title"] = trim($attr["content"]);
break;
case "dc.title":
$siteinfo["title"] = $attr["content"];
$siteinfo["title"] = trim($attr["content"]);
break;
case "dc.description":
$siteinfo["text"] = $attr["content"];
$siteinfo["text"] = trim($attr["content"]);
break;
case "keywords":
$keywords = explode(",", $attr["content"]);
break;
case "news_keywords":
$keywords = explode(",", $attr["content"]);
break;
}
}

View File

@@ -258,6 +258,10 @@ class Network extends \Zotlabs\Web\Controller {
}
elseif($pf && $unseen && $nouveau) {
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
if(! ($vnotify & VNOTIFY_LIKE))
$likes_sql = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
// This is for nouveau view public forum cid queries (if a forum notification is clicked)
$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
intval(local_channel()),
@@ -269,7 +273,7 @@ class Network extends \Zotlabs\Web\Controller {
if($p_str)
$p_sql = " OR item.parent IN ( $p_str ) ";
$sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 ";
$sql_extra = " AND ( owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' OR owner_xchan = '" . protect_sprintf(dbesc($cid_r[0]['abook_xchan'])) . "' $p_sql ) AND item_unseen = 1 $likes_sql ";
}
else {
// This is for threaded view cid queries (e.g. if a forum is selected from the forum filter)

View File

@@ -31,15 +31,17 @@ class Owa extends \Zotlabs\Web\Controller {
if($keyId) {
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
where hubloc_addr = '%s' ",
dbesc(str_replace('acct:','',$keyId))
where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
dbesc(str_replace('acct:','',$keyId)),
dbesc($keyId)
);
if(! $r) {
$found = discover_by_webbie(str_replace('acct:','',$keyId));
if($found) {
$r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
where hubloc_addr = '%s' ",
dbesc(str_replace('acct:','',$keyId))
where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) ",
dbesc(str_replace('acct:','',$keyId)),
dbesc($keyId)
);
}
}

View File

@@ -4,13 +4,12 @@ namespace Zotlabs\Module;
require_once('include/security.php');
require_once('include/attach.php');
require_once('include/photo/photo_driver.php');
require_once('include/photos.php');
class Photo extends \Zotlabs\Web\Controller {
function init() {
$prvcachecontrol = false;
$streaming = null;
$channel = null;
@@ -32,26 +31,26 @@ class Photo extends \Zotlabs\Web\Controller {
}
$observer_xchan = get_observer_hash();
$ismodified = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
$default = z_root() . '/' . get_default_profile_photo();
if(isset($type)) {
/**
* Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites.
*
*/
$default = get_default_profile_photo();
if($type === 'profile') {
switch($res) {
case 'm':
$resolution = 5;
$default = z_root() . '/' . get_default_profile_photo(80);
$default = get_default_profile_photo(80);
break;
case 's':
$resolution = 6;
$default = z_root() . '/' . get_default_profile_photo(48);
$default = get_default_profile_photo(48);
break;
case 'l':
default:
@@ -60,6 +59,8 @@ class Photo extends \Zotlabs\Web\Controller {
}
}
$modified = filemtime($default);
$default = z_root() . '/' . $default;
$uid = $person;
$d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ];
@@ -78,17 +79,18 @@ class Photo extends \Zotlabs\Web\Controller {
intval(PHOTO_PROFILE)
);
if($r) {
$modified = strtotime($r[0]['edited'] . "Z");
$data = dbunescbin($r[0]['content']);
$mimetype = $r[0]['mimetype'];
}
if(intval($r[0]['os_storage']))
$data = file_get_contents($data);
}
if(! $data) {
$data = fetch_image_from_url($default,$mimetype);
}
if(! $mimetype) {
$mimetype = 'image/png';
$x = z_fetch_url($default,true,0,[ 'novalidate' => true ]);
$data = ($x['success'] ? $x['body'] : EMPTY_STR);
$mimetype = 'image/png';
}
}
else {
@@ -124,9 +126,7 @@ class Photo extends \Zotlabs\Web\Controller {
$photo = substr($photo,0,-2);
// If viewing on a high-res screen, attempt to serve a higher resolution image:
if ($resolution == 2 && ($cookie_value > 1))
{
$resolution = 1;
}
}
$r = q("SELECT uid, photo_usage FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
@@ -163,10 +163,13 @@ class Photo extends \Zotlabs\Web\Controller {
if($exists && $allowed) {
$data = dbunescbin($e[0]['content']);
$filesize = $e[0]['filesize'];
$mimetype = $e[0]['mimetype'];
if(intval($e[0]['os_storage'])) {
$modified = strtotime($e[0]['edited'] . 'Z');
if(intval($e[0]['os_storage']))
$streaming = $data;
}
if($e[0]['allow_cid'] != '' || $e[0]['allow_gid'] != '' || $e[0]['deny_gid'] != '' || $e[0]['deny_gid'] != '')
$prvcachecontrol = true;
}
else {
if(! $allowed) {
@@ -177,27 +180,40 @@ class Photo extends \Zotlabs\Web\Controller {
}
}
} else {
http_status_exit(404,'not found');
}
}
header_remove('Pragma');
if($ismodified === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
header_remove('Expires');
header_remove('Cache-Control');
header_remove('Set-Cookie');
http_status_exit(304,'not modified');
}
if(! isset($data)) {
if(isset($resolution)) {
switch($resolution) {
case 4:
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(),$mimetype);
$default = get_default_profile_photo();
break;
case 5:
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(80),$mimetype);
$default = get_default_profile_photo(80);
break;
case 6:
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(48),$mimetype);
$default = get_default_profile_photo(48);
break;
default:
killme();
// NOTREACHED
break;
}
$x = z_fetch_url(z_root() . '/' . $default,true,0,[ 'novalidate' => true ]);
$data = ($x['success'] ? $x['body'] : EMPTY_STR);
$mimetype = 'image/png';
}
}
@@ -210,15 +226,14 @@ class Photo extends \Zotlabs\Web\Controller {
}
}
// @FIXME Seems never invoked
// Writing in cachefile
if (isset($cachefile) && $cachefile != '')
if (isset($cachefile) && $cachefile != '') {
file_put_contents($cachefile, $data);
if(function_exists('header_remove')) {
header_remove('Pragma');
header_remove('pragma');
$modified = filemtime($cachefile);
}
header("Content-type: " . $mimetype);
if($prvcachecontrol) {
@@ -240,15 +255,16 @@ class Photo extends \Zotlabs\Web\Controller {
// This has performance considerations but we highly recommend you
// leave it alone.
$cache = get_config('system','photo_cache_time');
if(! $cache)
$cache = (3600 * 24); // 1 day
$cache = get_config('system','photo_cache_time', 86400); // 1 day by default
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT");
header("Cache-Control: max-age=" . $cache);
}
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $modified) . " GMT");
header("Content-Length: " . (isset($filesize) ? $filesize : strlen($data)));
// If it's a file resource, stream it.
if($streaming && $channel) {

View File

@@ -263,7 +263,8 @@ class Photos extends \Zotlabs\Web\Controller {
$fsize = strlen($data);
}
$x = q("update photo set content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 0",
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc(datetime_convert()),
dbescbin($data),
intval($fsize),
intval($height),
@@ -277,9 +278,13 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
$data = $ph->imageString();
$fsize = strlen($data);
$x = q("update photo set content = '%s', height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 1",
dbescbin($ph->imageString()),
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 1",
dbesc(datetime_convert()),
dbescbin($data),
intval($fsize),
intval($height),
intval($width),
dbesc($resource_id),
@@ -292,9 +297,13 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
$data = $ph->imageString();
$fsize = strlen($data);
$x = q("update photo set content = '%s', height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 2",
dbescbin($ph->imageString()),
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 2",
dbesc(datetime_convert()),
dbescbin($data),
intval($fsize),
intval($height),
intval($width),
dbesc($resource_id),
@@ -307,9 +316,13 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
$data = $ph->imageString();
$fsize = strlen($data);
$x = q("update photo set content = '%s', height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 3",
dbescbin($ph->imageString()),
$x = q("update photo set edited = '%s', content = '%s', filesize = %d, height = %d, width = %d where resource_id = '%s' and uid = %d and imgscale = 3",
dbesc(datetime_convert()),
dbescbin($data),
intval($fsize),
intval($height),
intval($width),
dbesc($resource_id),
@@ -612,9 +625,9 @@ class Photos extends \Zotlabs\Web\Controller {
nav_set_selected('Photos');
$o = '<script src="library/blueimp_upload/js/vendor/jquery.ui.widget.js"></script>
<script src="library/blueimp_upload/js/jquery.iframe-transport.js"></script>
<script src="library/blueimp_upload/js/jquery.fileupload.js"></script>';
$o = '<script src="vendor/blueimp/jquery-file-upload/js/vendor/jquery.ui.widget.js"></script>
<script src="vendor/blueimp/jquery-file-upload/js/jquery.iframe-transport.js"></script>
<script src="vendor/blueimp/jquery-file-upload/js/jquery.fileupload.js"></script>';
$o .= "<script> var profile_uid = " . \App::$profile['profile_uid']

View File

@@ -635,7 +635,6 @@ class Ping extends \Zotlabs\Web\Controller {
$forums = get_forum_channels(local_channel());
if($forums) {
$perms_sql = item_permissions_sql(local_channel());
$item_normal = item_normal();
$fcount = count($forums);
$forums['total'] = 0;
@@ -644,14 +643,14 @@ class Ping extends \Zotlabs\Web\Controller {
$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
intval(local_channel()),
intval(TERM_FORUM),
dbesc($forums[$x]['xchan_hash'])
dbesc($forums[$x]['xchan_name'])
);
$p_str = ids_to_querystr($p, 'parent');
$p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
$r = q("select sum(item_unseen) as unseen from item
where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $perms_sql $item_normal",
$r = q("select count(id) as unseen from item
where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $item_normal $sql_extra",
intval(local_channel()),
dbesc($forums[$x]['xchan_hash']),
dbesc($forums[$x]['xchan_hash'])

View File

@@ -6,7 +6,7 @@ class Search extends \Zotlabs\Web\Controller {
function init() {
if(x($_REQUEST,'search'))
\App::$data['search'] = $_REQUEST['search'];
\App::$data['search'] = escape_tags($_REQUEST['search']);
}
@@ -46,12 +46,12 @@ class Search extends \Zotlabs\Web\Controller {
if(x(\App::$data,'search'))
$search = trim(\App::$data['search']);
else
$search = ((x($_GET,'search')) ? trim(rawurldecode($_GET['search'])) : '');
$search = ((x($_GET,'search')) ? trim(escape_tags(rawurldecode($_GET['search']))) : '');
$tag = false;
if(x($_GET,'tag')) {
$tag = true;
$search = ((x($_GET,'tag')) ? trim(rawurldecode($_GET['tag'])) : '');
$search = ((x($_GET,'tag')) ? trim(escape_tags(rawurldecode($_GET['tag']))) : '');
}
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
@@ -227,9 +227,9 @@ class Search extends \Zotlabs\Web\Controller {
}
if($tag)
$o .= '<h2>' . sprintf( t('Items tagged with: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '</h2>';
$o .= '<h2>' . sprintf( t('Items tagged with: %s'),$search) . '</h2>';
else
$o .= '<h2>' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '</h2>';
$o .= '<h2>' . sprintf( t('Search results for: %s'),$search) . '</h2>';
$o .= conversation($items,'search',$update,'client');

26
Zotlabs/Update/_1225.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace Zotlabs\Update;
class _1225 {
function run() {
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = q("ALTER TABLE pconfig ADD updated timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' ");
$r2 = q("create index \"pconfig_updated_idx\" on pconfig (\"updated\")");
$r = ($r1 && $r2);
}
else {
$r = q("ALTER TABLE `pconfig` ADD `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' ,
ADD INDEX `pconfig_updated` (`updated`)");
}
if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}
}

View File

@@ -6,10 +6,6 @@ class Wiki_list {
function widget($arr) {
if(argc() < 3) {
return;
}
$channel = channelx_by_n(\App::$profile_uid);
$wikis = \Zotlabs\Lib\NativeWiki::listwikis($channel,get_observer_hash());

View File

@@ -50,11 +50,10 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '3.8.2' );
define ( 'STD_VERSION', '3.8.5' );
define ( 'ZOT_REVISION', '6.0a' );
define ( 'DB_UPDATE_VERSION', 1224 );
define ( 'DB_UPDATE_VERSION', 1225 );
define ( 'PROJECT_BASE', __DIR__ );

View File

@@ -39,7 +39,8 @@
"lukasreschke/id3parser": "^0.0.1",
"smarty/smarty": "~3.1",
"ramsey/uuid": "^3.8",
"twbs/bootstrap": "4.1.3"
"twbs/bootstrap": "4.1.3",
"blueimp/jquery-file-upload": "^9.25"
},
"require-dev" : {
"phpunit/phpunit" : "@stable",

272
composer.lock generated
View File

@@ -4,8 +4,63 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b7862124a9afe837c7eef8ee66f02ff4",
"content-hash": "63d0e52cc07f8113059ec30d3637b850",
"packages": [
{
"name": "blueimp/jquery-file-upload",
"version": "v9.25.1",
"source": {
"type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
"reference": "28891f9b2bc339bcc1ca8d548e5401e8563bf04b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/28891f9b2bc339bcc1ca8d548e5401e8563bf04b",
"reference": "28891f9b2bc339bcc1ca8d548e5401e8563bf04b",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"server/php/UploadHandler.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sebastian Tschan",
"homepage": "https://blueimp.net"
}
],
"description": "File Upload widget for jQuery.",
"homepage": "https://github.com/blueimp/jQuery-File-Upload",
"keywords": [
"bootstrap",
"chunk",
"cross-domain",
"cross-site",
"drag",
"drop",
"file",
"gae",
"go",
"jquery",
"multiple",
"php",
"preview",
"progress",
"python",
"resume",
"selection",
"upload",
"widget"
],
"time": "2018-10-26T07:21:48+00:00"
},
{
"name": "bshaffer/oauth2-server-php",
"version": "v1.10.0",
@@ -157,16 +212,16 @@
},
{
"name": "league/html-to-markdown",
"version": "4.7.0",
"version": "4.8.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "76c076483cef89860d32a3fd25312f5a42848a8c"
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/76c076483cef89860d32a3fd25312f5a42848a8c",
"reference": "76c076483cef89860d32a3fd25312f5a42848a8c",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/f9a879a068c68ff47b722de63f58bec79e448f9d",
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d",
"shasum": ""
},
"require": {
@@ -185,7 +240,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.8-dev"
"dev-master": "4.9-dev"
}
},
"autoload": {
@@ -198,17 +253,17 @@
"MIT"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "http://www.colinodell.com",
"role": "Lead Developer"
},
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "An HTML-to-markdown conversion helper for PHP",
@@ -217,7 +272,7 @@
"html",
"markdown"
],
"time": "2018-05-19T23:47:12+00:00"
"time": "2018-09-18T12:18:08+00:00"
},
{
"name": "lukasreschke/id3parser",
@@ -520,16 +575,16 @@
},
{
"name": "sabre/dav",
"version": "3.2.2",
"version": "3.2.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516"
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"shasum": ""
},
"require": {
@@ -599,7 +654,7 @@
"framework",
"iCalendar"
],
"time": "2017-02-15T03:06:08+00:00"
"time": "2018-10-19T09:58:27+00:00"
},
{
"name": "sabre/event",
@@ -1002,16 +1057,16 @@
},
{
"name": "smarty/smarty",
"version": "v3.1.32",
"version": "v3.1.33",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459"
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/ac9d4b587e5bf53381e21881820a9830765cb459",
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"shasum": ""
},
"require": {
@@ -1051,7 +1106,7 @@
"keywords": [
"templating"
],
"time": "2018-04-24T14:53:33+00:00"
"time": "2018-09-12T20:54:16+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -2160,16 +2215,16 @@
},
{
"name": "php-mock/php-mock-phpunit",
"version": "2.1.1",
"version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-mock/php-mock-phpunit.git",
"reference": "ff1cc1d4e7478ce74221e05742588619bee84f69"
"reference": "57b92e621f14c2c07a4567cd29ed4e87de0d2912"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/ff1cc1d4e7478ce74221e05742588619bee84f69",
"reference": "ff1cc1d4e7478ce74221e05742588619bee84f69",
"url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/57b92e621f14c2c07a4567cd29ed4e87de0d2912",
"reference": "57b92e621f14c2c07a4567cd29ed4e87de0d2912",
"shasum": ""
},
"require": {
@@ -2210,7 +2265,7 @@
"test",
"test double"
],
"time": "2018-04-06T13:54:43+00:00"
"time": "2018-10-07T14:38:37+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -2481,16 +2536,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "6.0.7",
"version": "6.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "865662550c384bc1db7e51d29aeda1c2c161d69a"
"reference": "4d3ae9b21a7d7e440bd0cf65565533117976859f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a",
"reference": "865662550c384bc1db7e51d29aeda1c2c161d69a",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4d3ae9b21a7d7e440bd0cf65565533117976859f",
"reference": "4d3ae9b21a7d7e440bd0cf65565533117976859f",
"shasum": ""
},
"require": {
@@ -2501,7 +2556,7 @@
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^3.0",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.1",
"sebastian/environment": "^3.1 || ^4.0",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
@@ -2514,7 +2569,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.0-dev"
"dev-master": "6.1-dev"
}
},
"autoload": {
@@ -2540,25 +2595,28 @@
"testing",
"xunit"
],
"time": "2018-06-01T07:51:50+00:00"
"time": "2018-10-23T05:59:32+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "2.0.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c"
"reference": "050bedf145a257b1ff02746c31894800e5122946"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
"reference": "050bedf145a257b1ff02746c31894800e5122946",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
@@ -2587,7 +2645,7 @@
"filesystem",
"iterator"
],
"time": "2018-06-11T11:44:00+00:00"
"time": "2018-09-13T20:33:42+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -2681,16 +2739,16 @@
},
{
"name": "phpunit/php-token-stream",
"version": "3.0.0",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
"reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18",
"reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18",
"shasum": ""
},
"require": {
@@ -2726,20 +2784,20 @@
"keywords": [
"tokenizer"
],
"time": "2018-02-01T13:16:43+00:00"
"time": "2018-10-30T05:52:18+00:00"
},
{
"name": "phpunit/phpunit",
"version": "7.3.2",
"version": "7.4.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8"
"reference": "c151651fb6ed264038d486ea262e243af72e5e64"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/34705f81bddc3f505b9599a2ef96e2b4315ba9b8",
"reference": "34705f81bddc3f505b9599a2ef96e2b4315ba9b8",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c151651fb6ed264038d486ea262e243af72e5e64",
"reference": "c151651fb6ed264038d486ea262e243af72e5e64",
"shasum": ""
},
"require": {
@@ -2760,11 +2818,11 @@
"phpunit/php-timer": "^2.0",
"sebastian/comparator": "^3.0",
"sebastian/diff": "^3.0",
"sebastian/environment": "^3.1",
"sebastian/environment": "^3.1 || ^4.0",
"sebastian/exporter": "^3.1",
"sebastian/global-state": "^2.0",
"sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^1.0",
"sebastian/resource-operations": "^2.0",
"sebastian/version": "^2.0.1"
},
"conflict": {
@@ -2784,7 +2842,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.3-dev"
"dev-master": "7.4-dev"
}
},
"autoload": {
@@ -2810,7 +2868,7 @@
"testing",
"xunit"
],
"time": "2018-08-22T06:39:21+00:00"
"time": "2018-10-23T05:57:41+00:00"
},
{
"name": "psr/container",
@@ -3391,25 +3449,25 @@
},
{
"name": "sebastian/resource-operations",
"version": "1.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/resource-operations.git",
"reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
"reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
"url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
"reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
"shasum": ""
},
"require": {
"php": ">=5.6.0"
"php": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "2.0-dev"
}
},
"autoload": {
@@ -3429,7 +3487,7 @@
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"time": "2015-07-28T20:34:47+00:00"
"time": "2018-10-04T04:07:39+00:00"
},
{
"name": "sebastian/version",
@@ -3476,7 +3534,7 @@
},
{
"name": "symfony/browser-kit",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
@@ -3533,16 +3591,16 @@
},
{
"name": "symfony/class-loader",
"version": "v3.4.15",
"version": "v3.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
"reference": "31db283fc86d3143e7ff87e922177b457d909c30"
"reference": "f31333bdff54c7595f834d510a6d2325573ddb36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/31db283fc86d3143e7ff87e922177b457d909c30",
"reference": "31db283fc86d3143e7ff87e922177b457d909c30",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/f31333bdff54c7595f834d510a6d2325573ddb36",
"reference": "f31333bdff54c7595f834d510a6d2325573ddb36",
"shasum": ""
},
"require": {
@@ -3585,20 +3643,20 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T11:19:56+00:00"
"time": "2018-10-02T12:28:39+00:00"
},
{
"name": "symfony/config",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "76015a3cc372b14d00040ff58e18e29f69eba717"
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/76015a3cc372b14d00040ff58e18e29f69eba717",
"reference": "76015a3cc372b14d00040ff58e18e29f69eba717",
"url": "https://api.github.com/repos/symfony/config/zipball/b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"reference": "b3d4d7b567d7a49e6dfafb6d4760abc921177c96",
"shasum": ""
},
"require": {
@@ -3648,20 +3706,20 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2018-08-08T06:37:38+00:00"
"time": "2018-09-08T13:24:10+00:00"
},
{
"name": "symfony/console",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "ca80b8ced97cf07390078b29773dc384c39eee1f"
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/ca80b8ced97cf07390078b29773dc384c39eee1f",
"reference": "ca80b8ced97cf07390078b29773dc384c39eee1f",
"url": "https://api.github.com/repos/symfony/console/zipball/dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"reference": "dc7122fe5f6113cfaba3b3de575d31112c9aa60b",
"shasum": ""
},
"require": {
@@ -3716,20 +3774,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T11:24:31+00:00"
"time": "2018-10-03T08:15:46+00:00"
},
{
"name": "symfony/css-selector",
"version": "v3.4.15",
"version": "v3.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "edda5a6155000ff8c3a3f85ee5c421af93cca416"
"reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/edda5a6155000ff8c3a3f85ee5c421af93cca416",
"reference": "edda5a6155000ff8c3a3f85ee5c421af93cca416",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/3503415d4aafabc31cd08c3a4ebac7f43fde8feb",
"reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb",
"shasum": ""
},
"require": {
@@ -3769,20 +3827,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T09:06:28+00:00"
"time": "2018-10-02T16:33:53+00:00"
},
{
"name": "symfony/dependency-injection",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "bae4983003c9d451e278504d7d9b9d7fc1846873"
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/bae4983003c9d451e278504d7d9b9d7fc1846873",
"reference": "bae4983003c9d451e278504d7d9b9d7fc1846873",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"reference": "f6b9d893ad28aefd8942dc0469c8397e2216fe30",
"shasum": ""
},
"require": {
@@ -3840,20 +3898,20 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2018-08-08T11:48:58+00:00"
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "1c4519d257e652404c3aa550207ccd8ada66b38e"
"reference": "80e60271bb288de2a2259662cff125cff4f93f95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1c4519d257e652404c3aa550207ccd8ada66b38e",
"reference": "1c4519d257e652404c3aa550207ccd8ada66b38e",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/80e60271bb288de2a2259662cff125cff4f93f95",
"reference": "80e60271bb288de2a2259662cff125cff4f93f95",
"shasum": ""
},
"require": {
@@ -3897,11 +3955,11 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2018-07-26T11:00:49+00:00"
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@@ -3964,16 +4022,16 @@
},
{
"name": "symfony/filesystem",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e"
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e",
"reference": "c0f5f62db218fa72195b8b8700e4b9b9cf52eb5e",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/596d12b40624055c300c8b619755b748ca5cf0b5",
"reference": "596d12b40624055c300c8b619755b748ca5cf0b5",
"shasum": ""
},
"require": {
@@ -4010,7 +4068,7 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2018-08-18T16:52:46+00:00"
"time": "2018-10-02T12:40:59+00:00"
},
{
"name": "symfony/polyfill-mbstring",
@@ -4073,16 +4131,16 @@
},
{
"name": "symfony/translation",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f"
"reference": "9f0b61e339160a466ebcde167a6c5521c810e304"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/fa2182669f7983b7aa5f1a770d053f79f0ef144f",
"reference": "fa2182669f7983b7aa5f1a770d053f79f0ef144f",
"url": "https://api.github.com/repos/symfony/translation/zipball/9f0b61e339160a466ebcde167a6c5521c810e304",
"reference": "9f0b61e339160a466ebcde167a6c5521c810e304",
"shasum": ""
},
"require": {
@@ -4138,20 +4196,20 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2018-08-07T12:45:11+00:00"
"time": "2018-10-02T16:36:10+00:00"
},
{
"name": "symfony/yaml",
"version": "v4.1.4",
"version": "v4.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "b832cc289608b6d305f62149df91529a2ab3c314"
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/b832cc289608b6d305f62149df91529a2ab3c314",
"reference": "b832cc289608b6d305f62149df91529a2ab3c314",
"url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9",
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9",
"shasum": ""
},
"require": {
@@ -4197,7 +4255,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2018-08-18T16:52:46+00:00"
"time": "2018-10-02T16:36:10+00:00"
},
{
"name": "theseer/tokenizer",

View File

@@ -1198,24 +1198,24 @@ function bbcode($Text, $options = []) {
// Images
// [img]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width=100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width=100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img class="zrl" style="max-width: 100%;" src="$1" alt="' . t('Image/photo') . '" />', $Text);
}
// [img float={left, right}]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img style="max-width=100%;" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img float=left\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img style="max-width=100%;" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[img float=right\](.*?)\[\/img\]/ism", '<img src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img style="max-width=100%;" class="zrl" src="$1" style="float: left;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg float=left\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: left;" alt="' . t('Image/photo') . '" />', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img style="max-width=100%;" class="zrl" src="$1" style="float: right;" alt="' . t('Image/photo') . '" />', $Text);
$Text = preg_replace("/\[zmg float=right\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$1" style="max-width: 100%; float: right;" alt="' . t('Image/photo') . '" />', $Text);
}
// [img=widthxheight]pathtoimage[/img]

View File

@@ -59,8 +59,8 @@ function set_pconfig($uid, $family, $key, $value) {
return Zlib\PConfig::Set($uid,$family,$key,$value);
}
function del_pconfig($uid, $family, $key) {
return Zlib\PConfig::Delete($uid,$family,$key);
function del_pconfig($uid, $family, $key, $updated = NULL) {
return Zlib\PConfig::Delete($uid,$family,$key,$updated);
}
function load_xconfig($xchan) {

View File

@@ -173,14 +173,14 @@ abstract class dba_driver {
return false;
}
if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1') && (! strpbrk($server,':;'))) {
if(! z_dns_check($server)) {
$this->error = sprintf( t('Cannot locate DNS info for database server \'%s\''), $server);
$this->connected = false;
$this->db = null;
return false;
}
}
// if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1') && (! strpbrk($server,':;'))) {
// if(! z_dns_check($server)) {
// $this->error = sprintf( t('Cannot locate DNS info for database server \'%s\''), $server);
// $this->connected = false;
// $this->db = null;
// return false;
// }
// }
return true;
}
@@ -468,7 +468,7 @@ function db_columns($table) {
if(ACTIVE_DBTYPE === DBTYPE_POSTGRES) {
$r = q("SELECT column_name as field FROM information_schema.columns WHERE table_schema = 'public' AND table_name = '%s'",
dbesc($table)
);
);
if($r) {
return ids_to_array($r,'field');
}

View File

@@ -186,31 +186,30 @@ function hubloc_change_primary($hubloc) {
logger('no hubloc');
return false;
}
logger('setting primary: ' . $hubloc['hubloc_url'] . ((intval($hubloc['hubloc_primary'])) ? ' true' : ' false'));
// See if this is a local hubloc and if so update the primary for the corresponding channel record.
if($hubloc['hubloc_url'] === z_root()) {
$r = q("select channel_id from channel where channel_hash = '%s' limit 1",
dbesc($hubloc['hubloc_hash'])
);
if($r) {
q("update channel set channel_primary = %d where channel_id = %d",
intval($hubloc['hubloc_primary']),
intval($r[0]['channel_id'])
);
}
}
// we only need to proceed further if this particular hubloc is now primary
if(! (intval($hubloc['hubloc_primary']))) {
logger('not primary: ' . $hubloc['hubloc_url']);
return false;
}
logger('setting primary: ' . $hubloc['hubloc_url']);
// See if there's a local channel
$r = q("select channel_id, channel_primary from channel where channel_hash = '%s' limit 1",
dbesc($hubloc['hubloc_hash'])
);
if($r) {
if(! $r[0]['channel_primary']) {
q("update channel set channel_primary = 1 where channel_id = %d",
intval($r[0]['channel_id'])
);
}
else {
q("update channel set channel_primary = 0 where channel_id = %d",
intval($r[0]['channel_id'])
);
}
}
// do we even have an xchan for this hubloc and if so is it already set as primary?
$r = q("select * from xchan where xchan_hash = '%s' limit 1",

View File

@@ -93,8 +93,7 @@ function import_channel($channel, $account_id, $seize, $newname = '') {
'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall',
'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish',
'channel_a_delegate', 'perm_limits', 'channel_password', 'channel_salt',
'channel_moved', 'channel_primary', 'channel_removed', 'channel_deleted',
'channel_system'
'channel_moved', 'channel_removed', 'channel_deleted', 'channel_system'
];
$clean = array();

View File

@@ -608,8 +608,6 @@ function get_item_elements($x,$allow_code = false) {
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
$arr['edited'] = datetime_convert('UTC','UTC',$x['edited']);
if($arr['created'] > datetime_convert())
$arr['created'] = datetime_convert();
if($arr['edited'] > datetime_convert())
$arr['edited'] = datetime_convert();

View File

@@ -248,20 +248,12 @@ function bb_to_markdown($Text, $options = []) {
// Convert it to HTML - don't try oembed
$Text = bbcode($Text, [ 'tryoembed' => false ]);
// Markdownify does not preserve previously escaped html entities such as <> and &.
//$Text = str_replace(array('&lt;','&gt;','&amp;'),array('&_lt_;','&_gt_;','&_amp_;'),$Text);
// Now convert HTML to Markdown
$Text = html2markdown($Text);
//html2markdown adds backslashes infront of hashes after a new line. remove them
$Text = str_replace("\n\#", "\n#", $Text);
// It also adds backslashes to our attempt at getting around the html entity preservation for some weird reason.
//$Text = str_replace(array('&\\_lt\\_;','&\\_gt\\_;','&\\_amp\\_;'),array('&lt;','&gt;','&amp;'),$Text);
// If the text going into bbcode() has a plain URL in it, i.e.
// with no [url] tags around it, it will come out of parseString()
// looking like: <http://url.com>, which gets removed by strip_tags().
@@ -291,12 +283,24 @@ function bb_to_markdown($Text, $options = []) {
* If the HTML text can not get parsed it will return an empty string.
*
* @param string $html The HTML code to convert
* @param array $options an array of options to pass to the environment
* @return string Markdown representation of the given HTML text, empty on error
*/
function html2markdown($html,$options = []) {
function html2markdown($html, $options = []) {
$markdown = '';
$internal_errors = libxml_use_internal_errors(true);
if(! $options) {
$options = [
'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2
'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style
'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style
'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script'
'hard_break' => false, // Set to true to turn <br> into `\n` instead of ` \n`
'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+'
];
}
$environment = Environment::createDefaultEnvironment($options);
$environment->addConverter(new TableConverter());
@@ -308,8 +312,6 @@ function html2markdown($html,$options = []) {
logger("Invalid HTML. HTMLToMarkdown library threw an exception.");
}
libxml_use_internal_errors($internal_errors);
return $markdown;
}

View File

@@ -233,7 +233,7 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
return $ret;
if(! array_key_exists('request_target',$opts)) {
$opts['request_target'] = 'get ' . get_request_string($url);
$opts['request_target'] = 'post ' . get_request_string($url);
}
@curl_setopt($ch, CURLOPT_HEADER, true);
@@ -711,9 +711,9 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
foreach($matches as $mtch) {
logger('data: ' . $mtch[2] . ' ' . $mtch[3]);
if(substr($mtch[1],0,1) == '=') {
if(substr($mtch[2],0,1) == '=') {
$owidth = intval(substr($mtch[2],1));
if(intval($owidth) > 0 && intval($owidth) < 1024)
if($owidth > 0 && $owidth < 1024)
continue;
}

View File

@@ -272,6 +272,7 @@ function oembed_fetch_url($embedurl){
}
$j['embedurl'] = $embedurl;
$j['zrl'] = $is_matrix;
// logger('fetch return: ' . print_r($j,true));
@@ -335,7 +336,11 @@ function oembed_format_object($j){
case "rich": {
// not so safe..
$ret.= $jhtml;
if($j['zrl']) {
$ret = ((preg_match('/^<div[^>]+>(.*?)<\/div>$/is',$j['html'],$o)) ? $o[1] : $j['html']);
} else {
$ret.= $jhtml;
};
}; break;
}

View File

@@ -350,8 +350,7 @@ abstract class photo_driver {
$p['allow_gid'] = (($arr['allow_gid']) ? $arr['allow_gid'] : '');
$p['deny_cid'] = (($arr['deny_cid']) ? $arr['deny_cid'] : '');
$p['deny_gid'] = (($arr['deny_gid']) ? $arr['deny_gid'] : '');
$p['created'] = (($arr['created']) ? $arr['created'] : datetime_convert());
$p['edited'] = (($arr['edited']) ? $arr['edited'] : $p['created']);
$p['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert());
$p['title'] = (($arr['title']) ? $arr['title'] : '');
$p['description'] = (($arr['description']) ? $arr['description'] : '');
$p['photo_usage'] = intval($arr['photo_usage']);
@@ -365,13 +364,15 @@ abstract class photo_driver {
if(! intval($p['imgscale']))
logger('save: ' . print_r($arr,true), LOGGER_DATA);
$x = q("select id from photo where resource_id = '%s' and uid = %d and xchan = '%s' and imgscale = %d limit 1",
$x = q("select id, created from photo where resource_id = '%s' and uid = %d and xchan = '%s' and imgscale = %d limit 1",
dbesc($p['resource_id']),
intval($p['uid']),
dbesc($p['xchan']),
intval($p['imgscale'])
);
if($x) {
$p['created'] = (($x['created']) ? $x['created'] : $p['edited']);
$r = q("UPDATE photo set
aid = %d,
uid = %d,
@@ -412,7 +413,7 @@ abstract class photo_driver {
intval($p['width']),
(intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
(intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())),
intval($p['imgscale']),
intval($p['photo_usage']),
dbesc($p['title']),
@@ -427,6 +428,7 @@ abstract class photo_driver {
);
}
else {
$p['created'] = (($arr['created']) ? $arr['created'] : $p['edited']);
$r = q("INSERT INTO photo
( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
@@ -443,7 +445,7 @@ abstract class photo_driver {
intval($p['width']),
(intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
(intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())),
intval($p['imgscale']),
intval($p['photo_usage']),
dbesc($p['title']),
@@ -464,11 +466,6 @@ abstract class photo_driver {
/**
* Guess image mimetype from filename or from Content-Type header
*
@@ -485,11 +482,11 @@ function guess_image_type($filename, $headers = '') {
$h = explode("\n",$headers);
foreach ($h as $l) {
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[$k] = $v;
$hdrs[strtolower($k)] = $v;
}
logger('Curl headers: '.var_export($hdrs, true), LOGGER_DEBUG);
if (array_key_exists('Content-Type', $hdrs))
$type = $hdrs['Content-Type'];
if (array_key_exists('content-type', $hdrs))
$type = $hdrs['content-type'];
}
if (is_null($type)){
@@ -570,122 +567,166 @@ function delete_thing_photo($url,$ob_hash) {
function import_xchan_photo($photo,$xchan,$thing = false) {
/**
* @brief fetches an photo from external site and prepares its miniatures.
*
* @param string $photo
* external URL to fetch base image
* @param string $xchan
* channel unique hash
* @param boolean $thing
* TRUE if this is a thing URL
* @param boolean $force
* TRUE if ignore image modification date check (force fetch)
*
* @return array of results
* * \e string \b 0 => local URL to full image
* * \e string \b 1 => local URL to standard thumbnail
* * \e string \b 2 => local URL to micro thumbnail
* * \e string \b 3 => image type
* * \e boolean \b 4 => TRUE if fetch failure
* * \e string \b 5 => modification date
*/
$flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN);
$album = (($thing) ? 'Things' : 'Contact Photos');
function import_xchan_photo($photo,$xchan,$thing = false,$force = false) {
logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG);
$modified = '';
if($thing)
$hash = photo_new_resource();
else {
$r = q("select resource_id from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1",
dbesc($xchan),
intval(PHOTO_XCHAN)
);
if($r) {
$hash = $r[0]['resource_id'];
}
else {
$hash = photo_new_resource();
}
}
$flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN);
$album = (($thing) ? 'Things' : 'Contact Photos');
$photo_failure = false;
$img_str = '';
logger('import_xchan_photo: updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG);
if($photo) {
$filename = basename($photo);
if($thing) {
$hash = photo_new_resource();
}
else {
$r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1",
dbesc($xchan),
intval(PHOTO_XCHAN)
);
if($r) {
$hash = $r[0]['resource_id'];
$modified = $r[0]['edited'];
$type = $r[0]['mimetype'];
}
else {
$hash = photo_new_resource();
}
}
$result = z_fetch_url($photo,true);
$photo_failure = false;
$img_str = '';
if($result['success']) {
$img_str = $result['body'];
$type = guess_image_type($photo, $result['header']);
if($photo) {
$filename = basename($photo);
$h = explode("\n",$result['header']);
if($h) {
foreach($h as $hl) {
if(stristr($hl,'content-type:')) {
if(! stristr($hl,'image/')) {
$photo_failure = true;
}
}
}
}
}
}
else {
$photo_failure = true;
}
if($force || $modified == '') {
$result = z_fetch_url($photo,true);
}
else {
$h = array('headers' => array("If-Modified-Since: " . gmdate("D, d M Y H:i:s", strtotime($modified . "Z")) . " GMT"));
$result = z_fetch_url($photo,true,0,$h);
}
if(! $photo_failure) {
$img = photo_factory($img_str, $type);
if($img->is_valid()) {
$width = $img->getWidth();
$height = $img->getHeight();
if($width && $height) {
if(($width / $height) > 1.2) {
// crop out the sides
$margin = $width - $height;
$img->cropImage(300,($margin / 2),0,$height,$height);
}
elseif(($height / $width) > 1.2) {
// crop out the bottom
$margin = $height - $width;
$img->cropImage(300,0,0,$width,$width);
if($result['success']) {
$img_str = $result['body'];
$type = guess_image_type($photo, $result['header']);
$modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time()));
}
else {
$img->scaleImageSquare(300);
}
if(is_null($type))
$photo_failure = true;
}
elseif($result['return_code'] == 304) {
$photo = z_root() . '/photo/' . $hash . '-4';
$thumb = z_root() . '/photo/' . $hash . '-5';
$micro = z_root() . '/photo/' . $hash . '-6';
}
else {
$photo_failure = true;
}
}
else
$photo_failure = true;
}
else
$photo_failure = true;
$p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'imgscale' => 4);
if(! $photo_failure && $result['return_code'] != 304) {
$img = photo_factory($img_str, $type);
if($img->is_valid()) {
$width = $img->getWidth();
$height = $img->getHeight();
$r = $img->save($p);
if($width && $height) {
if(($width / $height) > 1.2) {
// crop out the sides
$margin = $width - $height;
$img->cropImage(300,($margin / 2),0,$height,$height);
}
elseif(($height / $width) > 1.2) {
// crop out the bottom
$margin = $height - $width;
$img->cropImage(300,0,0,$width,$width);
if($r === false)
$photo_failure = true;
}
else {
$img->scaleImageSquare(300);
}
$img->scaleImage(80);
$p['imgscale'] = 5;
$r = $img->save($p);
}
else
$photo_failure = true;
if($r === false)
$photo_failure = true;
$img->scaleImage(48);
$p['imgscale'] = 6;
$r = $img->save($p);
$p = array(
'xchan' => $xchan,
'resource_id' => $hash,
'filename' => basename($photo),
'album' => $album,
'photo_usage' => $flags,
'imgscale' => 4,
'edited' => $modified
);
if($r === false)
$photo_failure = true;
$r = $img->save($p);
$photo = z_root() . '/photo/' . $hash . '-4';
$thumb = z_root() . '/photo/' . $hash . '-5';
$micro = z_root() . '/photo/' . $hash . '-6';
}
else {
logger('import_xchan_photo: invalid image from ' . $photo);
$photo_failure = true;
}
}
if($photo_failure) {
$photo = z_root() . '/' . get_default_profile_photo();
$thumb = z_root() . '/' . get_default_profile_photo(80);
$micro = z_root() . '/' . get_default_profile_photo(48);
$type = 'image/png';
}
if($r === false)
$photo_failure = true;
return(array($photo,$thumb,$micro,$type,$photo_failure));
$img->scaleImage(80);
$p['imgscale'] = 5;
$r = $img->save($p);
if($r === false)
$photo_failure = true;
$img->scaleImage(48);
$p['imgscale'] = 6;
$r = $img->save($p);
if($r === false)
$photo_failure = true;
$photo = z_root() . '/photo/' . $hash . '-4';
$thumb = z_root() . '/photo/' . $hash . '-5';
$micro = z_root() . '/photo/' . $hash . '-6';
}
else {
logger('import_xchan_photo: invalid image from ' . $photo);
$photo_failure = true;
}
}
if($photo_failure) {
$default = get_default_profile_photo();
$photo = z_root() . '/' . $default;
$thumb = z_root() . '/' . get_default_profile_photo(80);
$micro = z_root() . '/' . get_default_profile_photo(48);
$type = 'image/png';
$modified = gmdate('Y-m-d H:i:s', filemtime($default));
}
logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG);
return(array($photo,$thumb,$micro,$type,$photo_failure,$modified));
}
@@ -700,16 +741,8 @@ function import_channel_photo_from_url($photo,$aid,$uid) {
$img_str = $result['body'];
$type = guess_image_type($photo, $result['header']);
$h = explode("\n",$result['header']);
if($h) {
foreach($h as $hl) {
if(stristr($hl,'content-type:')) {
if(! stristr($hl,'image/')) {
$photo_failure = true;
}
}
}
}
if(is_null($type))
$photo_failure = true;
}
}
else {

View File

@@ -1011,23 +1011,3 @@ function profile_photo_set_profile_perms($uid, $profileid = 0) {
}
}
}
function fetch_image_from_url($url,&$mimetype) {
$redirects = 0;
$x = z_fetch_url($url,true,$redirects,[ 'novalidate' => true ]);
if($x['success']) {
$hdrs = [];
$h = explode("\n",$x['header']);
foreach ($h as $l) {
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[strtolower($k)] = $v;
}
if (array_key_exists('content-type', $hdrs))
$mimetype = $hdrs['content-type'];
return $x['body'];
}
return EMPTY_STR;
}

View File

@@ -633,6 +633,19 @@ function attribute_contains($attr, $s) {
return false;
}
/**
* @brief Log to syslog
*
* @param string $msg Message to log
* @param int $priority - compatible with syslog
*/
function hz_syslog($msg, $priority = LOG_INFO) {
openlog("hz-log", LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog($priority, $msg);
closelog();
}
/**
* @brief Logging function for Hubzilla.
*
@@ -3219,8 +3232,16 @@ function create_table_from_array($table, $arr, $binary_fields = []) {
if(! ($arr && $table))
return false;
$columns = db_columns($table);
$clean = [];
foreach($arr as $k => $v) {
if(! in_array($k,$columns)) {
continue;
}
$matches = false;
if(preg_match('/([^a-zA-Z0-9\-\_\.])/',$k,$matches)) {
return false;

View File

@@ -1,5 +1,7 @@
<?php
use Zotlabs\Zot6\HTTPSig;
function xchan_store_lowlevel($arr) {
@@ -39,6 +41,13 @@ function xchan_store_lowlevel($arr) {
function xchan_store($arr) {
$update_photo = false;
$update_name = false;
if(! ($arr['guid'] || $arr['hash'])) {
$arr = json_decode(file_get_contents('php://input'),true);
}
logger('xchan_store: ' . print_r($arr,true));
if(! $arr['hash'])
@@ -49,57 +58,90 @@ function xchan_store($arr) {
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['hash'])
);
if($r)
return true;
if(! $r) {
if(! $arr['network'])
$arr['network'] = 'unknown';
if(! $arr['name'])
$arr['name'] = 'unknown';
if(! $arr['url'])
$arr['url'] = z_root();
if(! $arr['photo'])
$arr['photo'] = z_root() . '/' . get_default_profile_photo();
$update_photo = true;
if(! $arr['network'])
$arr['network'] = 'unknown';
if(! $arr['name'])
$arr['name'] = 'unknown';
if(! $arr['url'])
$arr['url'] = z_root();
if(! $arr['photo'])
$arr['photo'] = z_root() . '/' . get_default_profile_photo();
if($arr['network'] === 'zot') {
if((! $arr['key']) || (! rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$arr['key']))) {
logger('Unable to verify signature for ' . $arr['hash']);
return false;
if($arr['network'] === 'zot6') {
if((! $arr['key']) || (! Libzot::verify($arr['id'],$arr['id_sig'],$arr['key']))) {
logger('Unable to verify signature for ' . $arr['hash']);
return false;
}
}
}
$x = [];
foreach($arr as $k => $v) {
if($k === 'key') {
$x['xchan_pubkey'] = $v;
continue;
}
if($k === 'photo') {
continue;
if($arr['network'] === 'zot') {
if((! $arr['key']) || (! rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$arr['key']))) {
logger('Unable to verify signature for ' . $arr['hash']);
return false;
}
}
$columns = db_columns('xchan');
$x = [];
foreach($arr as $k => $v) {
if($k === 'key') {
$x['xchan_pubkey'] = HTTPSig::convertKey(escape_tags($v));;
continue;
}
if($k === 'photo') {
continue;
}
$x['xchan_' . $k] = $v;
if(in_array($columns,'xchan_' . $k))
$x['xchan_' . $k] = escape_tags($v);
}
$x['xchan_name_date'] = datetime_convert();
$x['xchan_photo_date'] = datetime_convert();
$x['xchan_system'] = false;
$result = xchan_store_lowlevel($x);
if(! $result)
return $result;
}
else {
if($r[0]['network'] === 'zot6') {
return true;
}
if($r[0]['xchan_photo_date'] < datetime_convert('UTC','UTC',$arr['photo_date'])) {
$update_photo = true;
}
if($r[0]['xchan_name_date'] < datetime_convert('UTC','UTC',$arr['name_date'])) {
$update_name = true;
}
}
if($update_photo && $arr['photo']) {
$photos = import_xchan_photo($arr['photo'],$arr['hash']);
$r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($arr['hash'])
);
}
if($update_name && $arr['name']) {
$x = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'",
dbesc(escape_tags($arr['name'])),
dbesc(datetime_convert()),
dbesc($arr['hash'])
);
}
$x['xchan_name_date'] = datetime_convert();
$r = xchan_store_lowlevel($x);
if(! $r)
return $r;
$photos = import_xchan_photo($arr['photo'],$arr['hash']);
$r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($arr['hash'])
);
return $r;
return true;
}

View File

@@ -1187,13 +1187,13 @@ function zot_fetch($arr) {
$zret = zot6_check_sig();
if($zret['success'] && $zret['hubloc'] && $zret['hubloc']['hubloc_guid'] === $data['sender']['guid'] && $data['msg']) {
if($zret['success'] && $zret['hubloc'] && $zret['hubloc']['hubloc_guid'] === $arr['sender']['guid'] && $arr['msg']) {
logger('zot6_delivery',LOGGER_DEBUG);
logger('zot6_data: ' . print_r($data,true),LOGGER_DATA);
logger('zot6_data: ' . print_r($arr,true),LOGGER_DATA);
$ret['collected'] = true;
$import = [ 'success' => true, 'body' => json_encode( [ 'success' => true, 'pickup' => [ [ 'notify' => $data, 'message' => json_decode($data['msg'],true) ] ] ] ) ];
$import = [ 'success' => true, 'body' => json_encode( [ 'success' => true, 'pickup' => [ [ 'notify' => $arr, 'message' => json_decode($arr['msg'],true) ] ] ] ) ];
$hubs = [ $zret['hubloc'] ] ;
}
@@ -3507,8 +3507,41 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('config',$arr) && is_array($arr['config']) && count($arr['config'])) {
foreach($arr['config'] as $cat => $k) {
foreach($arr['config'][$cat] as $k => $v)
set_pconfig($channel['channel_id'],$cat,$k,$v);
$pconfig_updated = [];
$pconfig_del = [];
foreach($arr['config'][$cat] as $k => $v) {
if (strpos($k,'pcfgud:')===0) {
$realk = substr($k,7);
$pconfig_updated[$realk] = $v;
unset($arr['config'][$cat][$k]);
}
if (strpos($k,'pcfgdel:')===0) {
$realk = substr($k,8);
$pconfig_del[$realk] = datetime_convert();
unset($arr['config'][$cat][$k]);
}
}
foreach($arr['config'][$cat] as $k => $v) {
if (!isset($pconfig_updated[$k])) {
$pconfig_updated[$k] = NULL;
}
set_pconfig($channel['channel_id'],$cat,$k,$v,$pconfig_updated[$k]);
}
foreach($pconfig_del as $k => $updated) {
del_pconfig($channel['channel_id'],$cat,$k,$updated);
}
}
}

View File

@@ -910,7 +910,6 @@ CREATE TABLE IF NOT EXISTS `outq` (
KEY `outq_priority` (`outq_priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS pchan (
`pchan_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`pchan_guid` char(191) NOT NULL DEFAULT '',
@@ -922,15 +921,16 @@ CREATE TABLE IF NOT EXISTS pchan (
KEY `pchan_hash` (`pchan_hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `pconfig` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NOT NULL DEFAULT 0 ,
`cat` char(191) NOT NULL DEFAULT '',
`k` char(191) NOT NULL DEFAULT '',
`v` mediumtext NOT NULL,
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `access` (`uid`,`cat`,`k`)
UNIQUE KEY `access` (`uid`,`cat`,`k`),
KEY `pconfig_updated` (`updated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `photo` (

View File

@@ -891,7 +891,6 @@ create index "outq_async" on outq ("outq_async");
create index "outq_delivered" on outq ("outq_delivered");
create index "outq_priority" on outq ("outq_priority");
CREATE TABLE "pchan" (
"pchan_id" serial NOT NULL,
"pchan_guid" text NOT NULL,
@@ -900,7 +899,6 @@ CREATE TABLE "pchan" (
"pchan_prvkey" text NOT NULL,
PRIMARY KEY ("pchan_id")
);
create index "pchan_guid" on pchan ("pchan_guid");
create index "pchan_hash" on pchan ("pchan_hash");
@@ -910,9 +908,11 @@ CREATE TABLE "pconfig" (
"cat" text NOT NULL,
"k" text NOT NULL,
"v" text NOT NULL,
"updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY ("id"),
UNIQUE ("uid","cat","k")
);
create index "pconfig_updated_idx" on pconfig ("updated");
CREATE TABLE "photo" (
"id" serial NOT NULL,

View File

@@ -52,12 +52,12 @@ class MarkdownTest extends UnitTestCase {
' &nbsp;',
''
],
/* it is not clear why this test fails
'strong, b, em, i, bib' => [
'<strong>strong</strong> <b>bold</b> <em>em</em> <i>italic</i> <b>bo<i>italic</i>ld</b>',
'**strong** **bold** _em_ _italic_ **bo_italic_ld**'
'**strong** **bold** *em* *italic* **bo*italic*ld**'
],
*/
'empty tags' => [
'text1 <b></b> text2 <i></i>',
'text1 text2'
@@ -70,10 +70,6 @@ class MarkdownTest extends UnitTestCase {
'&amp; lt &lt; gt &gt;',
'& lt < gt >'
],
'our escaped HTML entities' => [
'&_lt_; &_gt_; &_amp_;',
'&\_lt\_; &\_gt\_; &\_amp\_;'
],
'linebreak' => [
"line1<br>line2\nline3",
"line1 \nline2 line3"
@@ -84,15 +80,15 @@ class MarkdownTest extends UnitTestCase {
],
'unordered list' => [
'<ul><li>Item 1</li><li>Item 2</li><li>Item <b>3</b></li></ul>',
"- Item 1\n- Item 2\n- Item 3"
"- Item 1\n- Item 2\n- Item **3**"
],
'ordered list' => [
'<ol><li>Item 1</li><li>Item 2</li><li>Item <b>3</b></li></ol>',
"1. Item 1\n2. Item 2\n3. Item 3"
"1. Item 1\n2. Item 2\n3. Item **3**"
],
'nested lists' => [
'<ul><li>Item 1<ol><li>Item 1a</li><li>Item <b>1b</b></ol></li><li>Item 2</li></ul>',
"- Item 1\n 1. Item 1a\n 2. Item 1b\n- Item 2"
"- Item 1\n 1. Item 1a\n 2. Item **1b**\n- Item 2"
],
'img' => [
'<img src="/path/to/img.png" alt="alt text" title="title text">',
@@ -118,12 +114,10 @@ class MarkdownTest extends UnitTestCase {
'<code>&lt;p&gt;HTML text&lt;/p&gt;</code>',
'`<p>HTML text</p>`'
],
/* it is not clear why this test fails
'pre' => [
'<pre> line with spaces </pre>',
'` line with spaces `'
'<pre> one line with spaces </pre>',
"```\n one line with spaces \n```"
],
*/
'div p' => [
'<div>div</div><div><p>p</p></div>',
"<div>div</div><div>p\n\n</div>"

View File

@@ -1,12 +1,22 @@
# jQuery File Upload Plugin
## Demo
[Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/)
## Description
File Upload widget with multiple file selection, drag&amp;drop support, progress bars, validation and preview images, audio and video for jQuery.
Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
## Demo
[Demo File Upload](https://blueimp.github.io/jQuery-File-Upload/)
## ⚠️ Security Notice
Security related releases:
* [v9.25.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/v9.25.1) Mitigates some [Potential vulnerabilities with PHP+ImageMagick](VULNERABILITIES.md#potential-vulnerabilities-with-php+imagemagick).
* [v9.24.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/v9.24.1) Fixes a [Remote code execution vulnerability in the PHP component](VULNERABILITIES.md#remote-code-execution-vulnerability-in-the-php-component).
* v[9.10.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/9.10.1) Fixes an [Open redirect vulnerability in the GAE components](VULNERABILITIES.md#open-redirect-vulnerability-in-the-gae-components).
* Commit [4175032](https://github.com/blueimp/jQuery-File-Upload/commit/41750323a464e848856dc4c5c940663498beb74a) (*fixed in all tagged releases*) Fixes a [Cross-site scripting vulnerability in the Iframe Transport](VULNERABILITIES.md#cross-site-scripting-vulnerability-in-the-iframe-transport).
Please read the [SECURITY](SECURITY.md) document for instructions on how to securely configure your Webserver for file uploads.
## Setup
* [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
* [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin)
@@ -15,7 +25,7 @@ Supports cross-domain, chunked and resumable file uploads and client-side image
* **Multiple file upload:**
Allows to select multiple files at once and upload them simultaneously.
* **Drag & Drop support:**
Allows to upload files by dragging them from your desktop or filemanager and dropping them on your browser window.
Allows to upload files by dragging them from your desktop or file manager and dropping them on your browser window.
* **Upload progress bar:**
Shows a progress bar indicating the upload progress for individual files and for all uploads combined.
* **Cancelable uploads:**

View File

@@ -0,0 +1,133 @@
# File Upload Security
For an in-depth understanding of the potential security risks of providing file uploads and possible mitigations, please refer to the [OWASP - Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload) documentation.
To securely setup the project to serve uploaded files, please refer to the sample [Secure file upload serving configurations](#secure-file-upload-serving-configurations).
To mitigate potential vulnerabilities in image processing libraries, please refer to the [Secure image processing configurations](#secure-image-processing-configurations).
By default, all sample upload handlers allow only upload of image files, which mitigates some attack vectors, but should not be relied on as the only protection.
Please also have a look at the [list of fixed vulnerabilities](VULNERABILITIES.md) in jQuery File Upload, which relates mostly to the sample server-side upload handlers and how they have been configured.
## Purpose of this project
Please note that this project is not a complete file management product, but foremost a client-side file upload library for [jQuery](https://jquery.com/).
The server-side sample upload handlers are just examples to demonstrate the client-side file upload functionality.
To make this very clear, there is **no user authentication** by default:
* **everyone can upload files**
* **everyone can delete uploaded files**
In some cases this can be acceptable, but for most projects you will want to extend the sample upload handlers to integrate user authentication, or implement your own.
It is also up to you to configure your Webserver to securely serve the uploaded files, e.g. using the [sample server configurations](#secure-file-upload-serving-configurations).
## Mitigations against file upload risks
### Prevent code execution on the server
To prevent execution of scripts or binaries on server-side, the upload directory must be configured to not execute files in the upload directory (e.g. `server/php/files` as the default for the PHP upload handler) and only treat uploaded files as static content.
The recommended way to do this is to configure the upload directory path to point outside of the web application root.
Then the Webserver can be configured to serve files from the upload directory with their default static files handler only.
Limiting file uploads to a whitelist of safe file types (e.g. image files) also mitigates this issue, but should not be the only protection.
### Prevent code execution in the browser
To prevent execution of scripts on client-side, the following headers must
be sent when delivering generic uploaded files to the client:
```
Content-Type: application/octet-stream
X-Content-Type-Options: nosniff
```
The `Content-Type: application/octet-stream` header instructs browsers to display a download dialog instead of parsing it and possibly executing script content e.g. in HTML files.
The `X-Content-Type-Options: nosniff` header prevents browsers to try to detect the file mime type despite the given content-type header.
For known safe files, the content-type header can be adjusted using a **whitelist**, e.g. sending `Content-Type: image/png` for PNG files.
### Prevent distribution of malware
To prevent attackers from uploading and distributing malware (e.g. computer viruses), it is recommended to limit file uploads only to a whitelist of safe file types.
Please note that the detection of file types in the sample file upload handlers is based on the file extension and not the actual file content. This makes it still possible for attackers to upload malware by giving their files an image file extension, but should prevent automatic execution on client computers when opening those files.
It does not protect at all from exploiting vulnerabilities in image display programs, nor from users renaming file extensions to inadvertently execute the contained malicious code.
## Secure file upload serving configurations
The following configurations serve uploaded files as static files with the proper headers as [mitigation against file upload risks](#mitigations-against-file-upload-risks).
Please do not simply copy&paste these configurations, but make sure you understand what they are doing and that you have implemented them correctly.
> Always test your own setup and make sure that it is secure!
e.g. try uploading PHP scripts (as "example.php", "example.php.png" and "example.png") to see if they get executed by your Webserver.
### Apache config
Add the following directive to the Apache config, replacing the directory path with the absolute path to the upload directory:
```ApacheConf
<Directory "/path/to/project/server/php/files">
# To enable the Headers module, execute the following command and reload Apache:
# sudo a2enmod headers
# The following directives prevent the execution of script files
# in the context of the website.
# They also force the content-type application/octet-stream and
# force browsers to display a download dialog for non-image files.
SetHandler default-handler
ForceType application/octet-stream
Header set Content-Disposition attachment
# The following unsets the forced type and Content-Disposition headers
# for known image files:
<FilesMatch "(?i)\.(gif|jpe?g|png)$">
ForceType none
Header unset Content-Disposition
</FilesMatch>
# The following directive prevents browsers from MIME-sniffing the content-type.
# This is an important complement to the ForceType directive above:
Header set X-Content-Type-Options nosniff
</Directory>
```
### NGINX config
Add the following directive to the NGINX config, replacing the directory path with the absolute path to the upload directory:
```Nginx
location ^~ /path/to/project/server/php/files {
root html;
default_type application/octet-stream;
types {
image/gif gif;
image/jpeg jpg;
image/png png;
}
add_header X-Content-Type-Options 'nosniff';
if ($request_filename ~ /(((?!\.(jpg)|(png)|(gif)$)[^/])+$)) {
add_header Content-Disposition 'attachment; filename="$1"';
# Add X-Content-Type-Options again, as using add_header in a new context
# dismisses all previous add_header calls:
add_header X-Content-Type-Options 'nosniff';
}
}
```
## Secure image processing configurations
The following configuration mitigates [potential image processing vulnerabilities with ImageMagick](VULNERABILITIES.md#potential-vulnerabilities-with-php+imagemagick) by limiting the attack vectors to a small subset of image types (`GIF/JPEG/PNG`).
Please also consider using alternative, safer image processing libraries like [libvips](https://github.com/libvips/libvips) or [imageflow](https://github.com/imazen/imageflow).
## ImageMagick config
It is recommended to disable all non-required ImageMagick coders via [policy.xml](https://wiki.debian.org/imagemagick/security).
To do so, locate the ImageMagick `policy.xml` configuration file and add the following policies:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- ... -->
<policymap>
<!-- ... -->
<policy domain="delegate" rights="none" pattern="*" />
<policy domain="coder" rights="none" pattern="*" />
<policy domain="coder" rights="read | write" pattern="{GIF,JPEG,PNG}" />
</policymap>
```

View File

@@ -0,0 +1,65 @@
# ⚠️ List of fixed vulnerabilities
## Potential vulnerabilities with PHP+ImageMagick
> Mitigated: 2018-10-25 (GMT)
The sample [PHP upload handler](server/php/UploadHandler.php) before [v9.25.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/v9.25.1) did not validate file signatures before invoking [ImageMagick](https://www.imagemagick.org/) (via [Imagick](http://php.net/manual/en/book.imagick.php)).
Verifying those [magic bytes](https://en.wikipedia.org/wiki/List_of_file_signatures) mitigates potential vulnerabilities when handling input files other than `GIF/JPEG/PNG`.
Please also configure ImageMagick to only enable the coders required for `GIF/JPEG/PNG` processing, e.g. with the sample [ImageMagick config](SECURITY.md#imagemagick-config).
**Further information:**
* Commit containing the mitigation: [fe44d34](https://github.com/blueimp/jQuery-File-Upload/commit/fe44d34be43be32c6b8d507932f318dababb25dd)
* [ImageTragick](https://imagetragick.com/)
* [CERT Vulnerability Note VU#332928](https://www.kb.cert.org/vuls/id/332928)
* [ImageMagick CVE entries](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=imagemagick)
## Remote code execution vulnerability in the PHP component
> Fixed: 2018-10-23 (GMT)
The sample [PHP upload handler](server/php/UploadHandler.php) before [v9.24.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/v9.24.1) allowed to upload all file types by default.
This opens up a remote code execution vulnerability, unless the server is configured to not execute (PHP) files in the upload directory (`server/php/files`).
The provided [.htaccess](server/php/files/.htaccess) file includes instructions for Apache to disable script execution, however [.htaccess support](https://httpd.apache.org/docs/current/howto/htaccess.html) is disabled by default since Apache `v2.3.9` via [AllowOverride Directive](https://httpd.apache.org/docs/current/mod/core.html#allowoverride).
**You are affected if you:**
1. A) Uploaded jQuery File Upload < `v9.24.1` on a Webserver that executes files with `.php` as part of the file extension (e.g. "example.php.png"), e.g. Apache with `mod_php` enabled and the following directive (*not a recommended configuration*):
```ApacheConf
AddHandler php5-script .php
```
B) Uploaded jQuery File Upload < `v9.22.1` on a Webserver that executes files with the file extension `.php`, e.g. Apache with `mod_php` enabled and the following directive:
```ApacheConf
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
```
2. Did not actively configure your Webserver to not execute files in the upload directory (`server/php/files`).
3. Are running Apache `v2.3.9+` with the default `AllowOverride` Directive set to `None` or another Webserver with no `.htaccess` support.
**How to fix it:**
1. Upgrade to the latest version of jQuery File Upload.
2. Configure your Webserver to not execute files in the upload directory, e.g. with the [sample Apache configuration](SECURITY.md#apache-config)
**Further information:**
* Commits containing the security fix: [aeb47e5](https://github.com/blueimp/jQuery-File-Upload/commit/aeb47e51c67df8a504b7726595576c1c66b5dc2f), [ad4aefd](https://github.com/blueimp/jQuery-File-Upload/commit/ad4aefd96e4056deab6fea2690f0d8cf56bb2d7d)
* [Full disclosure post on Hacker News](https://news.ycombinator.com/item?id=18267309).
* [CVE-2018-9206](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-9206)
* [OWASP - Unrestricted File Upload](https://www.owasp.org/index.php/Unrestricted_File_Upload)
## Open redirect vulnerability in the GAE components
> Fixed: 2015-06-12 (GMT)
The sample Google App Engine upload handlers before v[9.10.1](https://github.com/blueimp/jQuery-File-Upload/releases/tag/9.10.1) accepted any URL as redirect target, making it possible to use the Webserver's domain for phishing attacks.
**Further information:**
* Commit containing the security fix: [f74d2a8](https://github.com/blueimp/jQuery-File-Upload/commit/f74d2a8c3e3b1e8e336678d2899facd5bcdb589f)
* [OWASP - Unvalidated Redirects and Forwards Cheat Sheet](https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet)
## Cross-site scripting vulnerability in the Iframe Transport
> Fixed: 2012-08-09 (GMT)
The [redirect page](cors/result.html) for the [Iframe Transport](js/jquery.iframe-transport.js) before commit [4175032](https://github.com/blueimp/jQuery-File-Upload/commit/41750323a464e848856dc4c5c940663498beb74a) (*fixed in all tagged releases*) allowed executing arbitrary JavaScript in the context of the Webserver.
**Further information:**
* Commit containing the security fix: [4175032](https://github.com/blueimp/jQuery-File-Upload/commit/41750323a464e848856dc4c5c940663498beb74a)
* [OWASP - Cross-site Scripting (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS))

View File

@@ -1,6 +1,6 @@
{
"name": "blueimp-file-upload",
"version": "9.23.0",
"version": "9.25.1",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&amp;drop support, progress bar, validation and preview images.",
"keywords": [

View File

@@ -0,0 +1,39 @@
{
"name": "blueimp/jquery-file-upload"
, "description": "File Upload widget for jQuery."
, "keywords": ["jquery",
"file",
"upload",
"widget",
"multiple",
"selection",
"drag",
"drop",
"progress",
"preview",
"cross-domain",
"cross-site",
"chunk",
"resume",
"gae",
"go",
"python",
"php",
"bootstrap"]
, "homepage": "https://github.com/blueimp/jQuery-File-Upload"
, "authors": [
{
"name": "Sebastian Tschan",
"homepage": "https://blueimp.net"
}
]
, "support": {
"forum": "https://groups.google.com/forum/#!forum/jquery-fileupload"
}
, "license": "MIT"
, "autoload": {
"classmap": [
"server/php/UploadHandler.php"
]
}
}

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -1,6 +1,6 @@
{
"name": "blueimp-file-upload",
"version": "9.23.0",
"version": "9.25.1",
"title": "jQuery File Upload",
"description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.",
"keywords": [

View File

@@ -1,5 +1,3 @@
application: jquery-file-upload
version: 2
runtime: go
api_version: go1

View File

@@ -1,5 +1,3 @@
application: jquery-file-upload
version: 1
runtime: python27
api_version: 1
threadsafe: true

View File

@@ -38,6 +38,10 @@ class UploadHandler
'image_resize' => 'Failed to resize image'
);
protected const IMAGETYPE_GIF = 1;
protected const IMAGETYPE_JPEG = 2;
protected const IMAGETYPE_PNG = 3;
protected $image_objects = array();
public function __construct($options = null, $initialize = true, $error_messages = null) {
@@ -89,17 +93,32 @@ class UploadHandler
'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
// Defines which files can be displayed inline when downloaded:
'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
// Defines which files (based on their names) are accepted for upload:
'accept_file_types' => '/.+$/i',
// Defines which files (based on their names) are accepted for upload.
// By default, only allows file uploads with image file extensions.
// Only change this setting after making sure that any allowed file
// types cannot be executed by the webserver in the files directory,
// e.g. PHP scripts, nor executed by the browser when downloaded,
// e.g. HTML files with embedded JavaScript code.
// Please also read the SECURITY.md document in this repository.
'accept_file_types' => '/\.(gif|jpe?g|png)$/i',
// Replaces dots in filenames with the given string.
// Can be disabled by setting it to false or an empty string.
// Note that this is a security feature for servers that support
// multiple file extensions, e.g. the Apache AddHandler Directive:
// https://httpd.apache.org/docs/current/mod/mod_mime.html#addhandler
// Before disabling it, make sure that files uploaded with multiple
// extensions cannot be executed by the webserver, e.g.
// "example.php.png" with embedded PHP code, nor executed by the
// browser when downloaded, e.g. "example.html.gif" with embedded
// JavaScript code.
'replace_dots_in_filenames' => '-',
// The php.ini settings upload_max_filesize and post_max_size
// take precedence over the following max_file_size setting:
'max_file_size' => null,
'min_file_size' => 1,
// The maximum number of files for the upload directory:
'max_number_of_files' => null,
// Defines which files are handled as image files:
'image_file_types' => '/\.(gif|jpe?g|png)$/i',
// Use exif_imagetype on all files to correct file extensions:
// Reads first file bytes to identify and correct file extensions:
'correct_image_extensions' => false,
// Image resolution restrictions:
'max_width' => null,
@@ -146,7 +165,7 @@ class UploadHandler
'max_width' => 800,
'max_height' => 600
),
*/
*/
'thumbnail' => array(
// Uncomment the following to use a defined directory for the thumbnails
// instead of a subdirectory based on the version identifier.
@@ -416,9 +435,8 @@ class UploadHandler
$min_width = @$this->options['min_width'];
$min_height = @$this->options['min_height'];
if (($max_width || $max_height || $min_width || $min_height)
&& preg_match($this->options['image_file_types'], $file->name)) {
&& $this->is_valid_image_file($uploaded_file)) {
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
// If we are auto rotating the image by default, do the checks on
// the correct orientation
if (
@@ -432,7 +450,6 @@ class UploadHandler
$img_height = $tmp;
unset($tmp);
}
}
if (!empty($img_width)) {
if ($max_width && $img_width > $max_width) {
@@ -494,16 +511,15 @@ class UploadHandler
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
$name .= '.'.$matches[1];
}
if ($this->options['correct_image_extensions'] &&
function_exists('exif_imagetype')) {
switch (@exif_imagetype($file_path)){
case IMAGETYPE_JPEG:
if ($this->options['correct_image_extensions']) {
switch ($this->imagetype($file_path)) {
case self::IMAGETYPE_JPEG:
$extensions = array('jpg', 'jpeg');
break;
case IMAGETYPE_PNG:
case self::IMAGETYPE_PNG:
$extensions = array('png');
break;
case IMAGETYPE_GIF:
case self::IMAGETYPE_GIF:
$extensions = array('gif');
break;
}
@@ -527,6 +543,16 @@ class UploadHandler
// into different directories or replacing hidden system files.
// Also remove control characters and spaces (\x00..\x20) around the filename:
$name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
// Replace dots in filenames to avoid security issues with servers
// that interpret multiple file extensions, e.g. "example.php.png":
$replacement = $this->options['replace_dots_in_filenames'];
if (!empty($replacement)) {
$parts = explode('.', $name);
if (count($parts) > 2) {
$ext = array_pop($parts);
$name = implode($replacement, $parts).'.'.$ext;
}
}
// Use a timestamp for empty filenames:
if (!$name) {
$name = str_replace('.', '-', microtime(true));
@@ -1036,15 +1062,27 @@ class UploadHandler
}
}
protected function imagetype($file_path) {
$fp = fopen($file_path, 'r');
$data = fread($fp, 4);
fclose($fp);
// GIF: 47 49 46
if (substr($data, 0, 3) === 'GIF') {
return self::IMAGETYPE_GIF;
}
// JPG: FF D8
if (bin2hex(substr($data, 0, 2)) === 'ffd8') {
return self::IMAGETYPE_JPEG;
}
// PNG: 89 50 4E 47
if (bin2hex(@$data[0]).substr($data, 1, 4) === '89PNG') {
return self::IMAGETYPE_PNG;
}
return false;
}
protected function is_valid_image_file($file_path) {
if (!preg_match($this->options['image_file_types'], $file_path)) {
return false;
}
if (function_exists('exif_imagetype')) {
return @exif_imagetype($file_path);
}
$image_info = $this->get_image_size($file_path);
return $image_info && $image_info[0] && $image_info[1];
return !!$this->imagetype($file_path);
}
protected function handle_image_file($file_path, $file) {

View File

@@ -0,0 +1,15 @@
<?php
/*
* jQuery File Upload Plugin PHP Example
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*/
exit;
error_reporting(E_ALL | E_STRICT);
require('UploadHandler.php');
$upload_handler = new UploadHandler();

View File

@@ -1,21 +1,56 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Composer
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
Source: https://github.com/composer/composer
Copyright (c) Nils Adermann, Jordi Boggiano
Files: *
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
Files: src/Composer/Util/TlsHelper.php
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
2013, Evan Coury <me@evancoury.com>
License: Expat and BSD-2-Clause
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
License: BSD-2-Clause
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
.
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -300,6 +300,7 @@ return array(
'League\\HTMLToMarkdown\\ElementInterface' => $vendorDir . '/league/html-to-markdown/src/ElementInterface.php',
'League\\HTMLToMarkdown\\Environment' => $vendorDir . '/league/html-to-markdown/src/Environment.php',
'League\\HTMLToMarkdown\\HtmlConverter' => $vendorDir . '/league/html-to-markdown/src/HtmlConverter.php',
'League\\HTMLToMarkdown\\HtmlConverterInterface' => $vendorDir . '/league/html-to-markdown/src/HtmlConverterInterface.php',
'Michelf\\Markdown' => $vendorDir . '/michelf/php-markdown/Michelf/Markdown.php',
'Michelf\\MarkdownExtra' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownExtra.php',
'Michelf\\MarkdownInterface' => $vendorDir . '/michelf/php-markdown/Michelf/MarkdownInterface.php',
@@ -804,6 +805,7 @@ return array(
'Text_LanguageDetect_Exception' => $vendorDir . '/pear/text_languagedetect/Text/LanguageDetect/Exception.php',
'Text_LanguageDetect_ISO639' => $vendorDir . '/pear/text_languagedetect/Text/LanguageDetect/ISO639.php',
'Text_LanguageDetect_Parser' => $vendorDir . '/pear/text_languagedetect/Text/LanguageDetect/Parser.php',
'UploadHandler' => $vendorDir . '/blueimp/jquery-file-upload/server/php/UploadHandler.php',
'Zotlabs\\Access\\AccessList' => $baseDir . '/Zotlabs/Access/AccessList.php',
'Zotlabs\\Access\\PermissionLimits' => $baseDir . '/Zotlabs/Access/PermissionLimits.php',
'Zotlabs\\Access\\PermissionRoles' => $baseDir . '/Zotlabs/Access/PermissionRoles.php',

View File

@@ -468,6 +468,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
'League\\HTMLToMarkdown\\ElementInterface' => __DIR__ . '/..' . '/league/html-to-markdown/src/ElementInterface.php',
'League\\HTMLToMarkdown\\Environment' => __DIR__ . '/..' . '/league/html-to-markdown/src/Environment.php',
'League\\HTMLToMarkdown\\HtmlConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/HtmlConverter.php',
'League\\HTMLToMarkdown\\HtmlConverterInterface' => __DIR__ . '/..' . '/league/html-to-markdown/src/HtmlConverterInterface.php',
'Michelf\\Markdown' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/Markdown.php',
'Michelf\\MarkdownExtra' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownExtra.php',
'Michelf\\MarkdownInterface' => __DIR__ . '/..' . '/michelf/php-markdown/Michelf/MarkdownInterface.php',
@@ -972,6 +973,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
'Text_LanguageDetect_Exception' => __DIR__ . '/..' . '/pear/text_languagedetect/Text/LanguageDetect/Exception.php',
'Text_LanguageDetect_ISO639' => __DIR__ . '/..' . '/pear/text_languagedetect/Text/LanguageDetect/ISO639.php',
'Text_LanguageDetect_Parser' => __DIR__ . '/..' . '/pear/text_languagedetect/Text/LanguageDetect/Parser.php',
'UploadHandler' => __DIR__ . '/..' . '/blueimp/jquery-file-upload/server/php/UploadHandler.php',
'Zotlabs\\Access\\AccessList' => __DIR__ . '/../..' . '/Zotlabs/Access/AccessList.php',
'Zotlabs\\Access\\PermissionLimits' => __DIR__ . '/../..' . '/Zotlabs/Access/PermissionLimits.php',
'Zotlabs\\Access\\PermissionRoles' => __DIR__ . '/../..' . '/Zotlabs/Access/PermissionRoles.php',
@@ -1503,6 +1505,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
'Zotlabs\\Update\\_1222' => __DIR__ . '/../..' . '/Zotlabs/Update/_1222.php',
'Zotlabs\\Update\\_1223' => __DIR__ . '/../..' . '/Zotlabs/Update/_1223.php',
'Zotlabs\\Update\\_1224' => __DIR__ . '/../..' . '/Zotlabs/Update/_1224.php',
'Zotlabs\\Update\\_1225' => __DIR__ . '/../..' . '/Zotlabs/Update/_1225.php',
'Zotlabs\\Web\\CheckJS' => __DIR__ . '/../..' . '/Zotlabs/Web/CheckJS.php',
'Zotlabs\\Web\\Controller' => __DIR__ . '/../..' . '/Zotlabs/Web/Controller.php',
'Zotlabs\\Web\\HTTPHeaders' => __DIR__ . '/../..' . '/Zotlabs/Web/HTTPHeaders.php',

View File

@@ -1,4 +1,61 @@
[
{
"name": "blueimp/jquery-file-upload",
"version": "v9.25.1",
"version_normalized": "9.25.1.0",
"source": {
"type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
"reference": "28891f9b2bc339bcc1ca8d548e5401e8563bf04b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/28891f9b2bc339bcc1ca8d548e5401e8563bf04b",
"reference": "28891f9b2bc339bcc1ca8d548e5401e8563bf04b",
"shasum": ""
},
"time": "2018-10-26T07:21:48+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"server/php/UploadHandler.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sebastian Tschan",
"homepage": "https://blueimp.net"
}
],
"description": "File Upload widget for jQuery.",
"homepage": "https://github.com/blueimp/jQuery-File-Upload",
"keywords": [
"bootstrap",
"chunk",
"cross-domain",
"cross-site",
"drag",
"drop",
"file",
"gae",
"go",
"jquery",
"multiple",
"php",
"preview",
"progress",
"python",
"resume",
"selection",
"upload",
"widget"
]
},
{
"name": "bshaffer/oauth2-server-php",
"version": "v1.10.0",
@@ -156,17 +213,17 @@
},
{
"name": "league/html-to-markdown",
"version": "4.7.0",
"version_normalized": "4.7.0.0",
"version": "4.8.0",
"version_normalized": "4.8.0.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "76c076483cef89860d32a3fd25312f5a42848a8c"
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/76c076483cef89860d32a3fd25312f5a42848a8c",
"reference": "76c076483cef89860d32a3fd25312f5a42848a8c",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/f9a879a068c68ff47b722de63f58bec79e448f9d",
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d",
"shasum": ""
},
"require": {
@@ -179,14 +236,14 @@
"phpunit/phpunit": "4.*",
"scrutinizer/ocular": "~1.1"
},
"time": "2018-05-19T23:47:12+00:00",
"time": "2018-09-18T12:18:08+00:00",
"bin": [
"bin/html-to-markdown"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.8-dev"
"dev-master": "4.9-dev"
}
},
"installation-source": "dist",
@@ -200,17 +257,17 @@
"MIT"
],
"authors": [
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "http://www.colinodell.com",
"role": "Lead Developer"
},
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
}
],
"description": "An HTML-to-markdown conversion helper for PHP",
@@ -533,17 +590,17 @@
},
{
"name": "sabre/dav",
"version": "3.2.2",
"version_normalized": "3.2.2.0",
"version": "3.2.3",
"version_normalized": "3.2.3.0",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516"
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/e987775e619728f12205606c9cc3ee565ffb1516",
"reference": "e987775e619728f12205606c9cc3ee565ffb1516",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"shasum": ""
},
"require": {
@@ -574,7 +631,7 @@
"ext-curl": "*",
"ext-pdo": "*"
},
"time": "2017-02-15T03:06:08+00:00",
"time": "2018-10-19T09:58:27+00:00",
"bin": [
"bin/sabredav",
"bin/naturalselection"
@@ -1029,23 +1086,23 @@
},
{
"name": "smarty/smarty",
"version": "v3.1.32",
"version_normalized": "3.1.32.0",
"version": "v3.1.33",
"version_normalized": "3.1.33.0",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459"
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/ac9d4b587e5bf53381e21881820a9830765cb459",
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"time": "2018-04-24T14:53:33+00:00",
"time": "2018-09-12T20:54:16+00:00",
"type": "library",
"extra": {
"branch-alias": {

View File

@@ -4,6 +4,24 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip
## [Unreleased][unreleased]
## [4.8.0] - 2018-09-18
### Added
- Added support for email auto-linking
- Added a new interface (`HtmlConverterInterface`) for the main `HtmlConverter` class
- Added additional test cases (#14)
### Changed
- The `italic_style` option now defaults to `'*'` so that in-word emphasis is handled properly (#75)
### Fixed
- Fixed several issues of `<code>` and `<pre>` tags not converting to blocks or inlines properly (#26, #70, #102, #140, #161, #162)
- Fixed in-word emphasis using underscores as delimiter (#75)
- Fixed character escaping inside of `<div>` elements
- Fixed header edge cases
### Deprecated
- The `bold_style` and `italic_style` options have been deprecated (#75)
## [4.7.0] - 2018-05-19
### Added
- Added `setOptions()` function for chainable calling (#149)
@@ -217,7 +235,8 @@ not ideally set, so this releases fixes that. Moving forwards this should reduce
### Added
- Initial release
[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/4.7.0...master
[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/4.8.0...master
[4.8.0]: https://github.com/thephpleague/html-to-markdown/compare/4.7.0...4.8.0
[4.7.0]: https://github.com/thephpleague/html-to-markdown/compare/4.6.2...4.7.0
[4.6.2]: https://github.com/thephpleague/html-to-markdown/compare/4.6.1...4.6.2
[4.6.1]: https://github.com/thephpleague/html-to-markdown/compare/4.6.0...4.6.1

View File

@@ -9,7 +9,7 @@
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "http://www.colinodell.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
},
{
@@ -42,7 +42,7 @@
"bin": ["bin/html-to-markdown"],
"extra": {
"branch-alias": {
"dev-master": "4.8-dev"
"dev-master": "4.9-dev"
}
}
}

View File

@@ -12,6 +12,8 @@ class Configuration
public function __construct(array $config = array())
{
$this->config = $config;
$this->checkForDeprecatedOptions($config);
}
/**
@@ -19,6 +21,7 @@ class Configuration
*/
public function merge(array $config = array())
{
$this->checkForDeprecatedOptions($config);
$this->config = array_replace_recursive($this->config, $config);
}
@@ -27,6 +30,7 @@ class Configuration
*/
public function replace(array $config = array())
{
$this->checkForDeprecatedOptions($config);
$this->config = $config;
}
@@ -36,6 +40,7 @@ class Configuration
*/
public function setOption($key, $value)
{
$this->checkForDeprecatedOptions(array($key => $value));
$this->config[$key] = $value;
}
@@ -57,4 +62,15 @@ class Configuration
return $this->config[$key];
}
private function checkForDeprecatedOptions(array $config)
{
foreach ($config as $key => $value) {
if ($key === 'bold_style' && $value !== '**') {
@trigger_error('Customizing the bold_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED);
} elseif ($key === 'italic_style' && $value !== '*') {
@trigger_error('Customizing the italic_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED);
}
}
}
}

View File

@@ -13,7 +13,7 @@ class CodeConverter implements ConverterInterface
*/
public function convert(ElementInterface $element)
{
$language = null;
$language = '';
// Checking for language class on the code block
$classes = $element->getAttribute('class');
@@ -24,8 +24,7 @@ class CodeConverter implements ConverterInterface
foreach ($classes as $class) {
if (strpos($class, 'language-') !== false) {
// Found one, save it as the selected language and stop looping over the classes.
// The space after the language avoids gluing the actual code with the language tag
$language = str_replace('language-', '', $class) . ' ';
$language = str_replace('language-', '', $class);
break;
}
}
@@ -39,14 +38,13 @@ class CodeConverter implements ConverterInterface
$code = preg_replace('/<code\b[^>]*>/', '', $code);
$code = str_replace('</code>', '', $code);
// Checking if the code has multiple lines
$lines = preg_split('/\r\n|\r|\n/', $code);
if (count($lines) > 1) {
// Multiple lines detected, adding three backticks and newlines
$markdown .= '```' . $language . "\n" . $code . "\n" . '```' . "\n\n";
// Checking if it's a code block or span
if ($this->shouldBeBlock($element, $code)) {
// Code block detected, newlines will be added in parent
$markdown .= '```' . $language . "\n" . $code . "\n" . '```';
} else {
// One line of code, wrapping it on one backtick.
$markdown .= '`' . $language . $code . '`';
// One line of code, wrapping it on one backtick, removing new lines
$markdown .= '`' . preg_replace('/\r\n|\r|\n/', '', $code) . '`';
}
return $markdown;
@@ -59,4 +57,23 @@ class CodeConverter implements ConverterInterface
{
return array('code');
}
/**
* @param ElementInterface $element
* @param string $code
*
* @return bool
*/
private function shouldBeBlock(ElementInterface $element, $code)
{
if ($element->getParent()->getTagName() == 'pre') {
return true;
}
if (preg_match('/[^\s]` `/', $code)) {
return true;
}
return false;
}
}

View File

@@ -34,6 +34,10 @@ class HeaderConverter implements ConverterInterface, ConfigurationAwareInterface
$level = (int) substr($element->getTagName(), 1, 1);
$style = $this->config->getOption('header_style', self::STYLE_SETEXT);
if (strlen($element->getValue()) === 0) {
return '';
}
if (($level === 1 || $level === 2) && !$element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) {
return $this->createSetextHeader($level, $element->getValue());
}

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