From: Banana <banana@optimus.de> Date: Sun, 25 Dec 2016 11:45:31 +0000 (+0100) Subject: submitting a new URL and finding the info via curl. X-Git-Tag: 2.1-alpha-2019-0-29~57 X-Git-Url: http://91.132.146.200/gitweb/?a=commitdiff_plain;h=647111b9c067c56503482bada1f197430013ca23;p=insipid.git submitting a new URL and finding the info via curl. --- diff --git a/webroot/asset/css/app.css b/webroot/asset/css/app.css index e69de29..3e8e7f6 100644 --- a/webroot/asset/css/app.css +++ b/webroot/asset/css/app.css @@ -0,0 +1,3 @@ +.linkthumbnail { + max-height: 200px; +} \ No newline at end of file diff --git a/webroot/index.php b/webroot/index.php index c8bd963..af5a94d 100644 --- a/webroot/index.php +++ b/webroot/index.php @@ -55,6 +55,7 @@ else { require('config.php'); require('lib/summoner.class.php'); +require('lib/management.class.php'); ## main vars $Summoner = new Summoner(); @@ -74,6 +75,9 @@ if ($DB->connect_errno) exit('Can not connect to MySQL Server'); $DB->set_charset("utf8mb4"); $DB->query("SET collation_connection = 'utf8mb4_bin'"); +# management needs the DB object +$Management = new Management($DB); + /* if(isset($_GET['p']) && !empty($_GET['p'])) { $_requestMode = trim($_GET['p']); diff --git a/webroot/lib/management.class.php b/webroot/lib/management.class.php new file mode 100644 index 0000000..dbdcb71 --- /dev/null +++ b/webroot/lib/management.class.php @@ -0,0 +1,81 @@ +<?php +/** + * Insipid + * Personal web-bookmark-system + * + * Copyright 2016-2017 Johannes KeÃler + * + * Development starting from 2011: Johannes KeÃler + * https://www.bananas-playground.net/projekt/insipid/ + * + * creator: + * Luke Reeves <luke@neuro-tech.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0. + * + */ + +class Management { + /** + * the database object + * @var object + */ + private $DB; + + public function __construct($databaseConnectionObject) { + $this->DB = $databaseConnectionObject; + } + + /** + * get all the available categories from the DB. + * optinal limit + * @param int $limit + */ + public function categories($limit=false) { + $ret = array(); + + $queryStr = "SELECT * FROM `".DB_PREFIX."_category` ORDER BY `name`"; + if(!empty($limit)) { + $queryStr .= " LIMIT $limit"; + } + $query = $this->DB->query($queryStr); + if(!empty($query)) { + $ret = $query->fetch_all(MYSQLI_ASSOC); + } + + return $ret; + } + + /** + * get all the available tags from the DB. + * optional limit + * @param int $limit + */ + public function tags($limit=false) { + $ret = array(); + + $queryStr = "SELECT * FROM `".DB_PREFIX."_tag` ORDER BY `name`"; + if(!empty($limit)) { + $queryStr .= " LIMIT $limit"; + } + $query = $this->DB->query($queryStr); + if(!empty($query)) { + $ret = $query->fetch_all(MYSQLI_ASSOC); + } + + return $ret; + } +} + +?> \ No newline at end of file diff --git a/webroot/lib/summoner.class.php b/webroot/lib/summoner.class.php index ce66c6d..dac6c0f 100644 --- a/webroot/lib/summoner.class.php +++ b/webroot/lib/summoner.class.php @@ -156,7 +156,7 @@ class Summoner { * execute a curl call to the fiven $url * @param string $curl The request url */ - static function curlCall($url,$port=80) { + static function curlCall($url,$port=false) { $ret = false; $ch = curl_init(); @@ -165,14 +165,18 @@ class Summoner { curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); curl_setopt($ch, CURLOPT_TIMEOUT, 30); - curl_setopt($ch, CURLOPT_PORT, $port); + if(!empty($port)) { + curl_setopt($ch, CURLOPT_PORT, $port); + } $do = curl_exec($ch); + if(is_string($do) === true) { $ret = $do; } else { $ret = false; + error_log(var_export(curl_error($ch),true)); } curl_close($ch); @@ -220,6 +224,113 @@ class Summoner { static function ifset($array,$key) { return isset($array[$key]) ? $array[$key] : false; } + + /** + * try to gather meta information from given URL + * @param string $url + */ + static function gatherInfoFromURL($url) { + $ret = false; + + if(self::validate($url,'url')) { + $data = self::curlCall($url); + if(!empty($data)) { + $ret = self::socialMetaInfos($data); + } + } + + return $ret; + } + + /** + * get as much as possible solcial meta infos from given string + * the string is usually a HTML source + * @param string $string + */ + static function socialMetaInfos($string) { + #http://www.w3bees.com/2013/11/fetch-facebook-og-meta-tags-with-php.html + #http://www.9lessons.info/2014/01/social-meta-tags-for-google-twitter-and.html + #http://ogp.me/ + #https://moz.com/blog/meta-data-templates-123 + + $dom = new DomDocument; + # surpress invalid html warnings + @$dom->loadHTML($string); + + $xpath = new DOMXPath($dom); + $metas = $xpath->query('//*/meta'); + + $mediaInfos = array(); + + # meta tags + foreach($metas as $meta) { + if($meta->getAttribute('property')) { + $prop = $meta->getAttribute('property'); + $prop = mb_strtolower($prop); + + # minimum required information + # http://ogp.me/#metadata + if($prop == "og:title") { + + $mediaInfos['title'] = $meta->getAttribute('content'); + } + elseif($prop == "og:image") { + $mediaInfos['image'] = $meta->getAttribute('content'); + } + elseif($prop == "og:url") { + $mediaInfos['link'] = $meta->getAttribute('content'); + } + elseif($prop == "og:description") { + $mediaInfos['description'] = $meta->getAttribute('content'); + } + } + elseif($meta->getAttribute('name')) { + $name = $meta->getAttribute('name'); + $name = mb_strtolower($name); + + # twitter + # https://dev.twitter.com/cards/overview + + if($name == "twitter:title") { + $mediaInfos['title'] = $meta->getAttribute('content'); + } + elseif($name == "twitter:description") { + $mediaInfos['description'] = $meta->getAttribute('content'); + } + elseif($name == "twitter:image") { + $mediaInfos['image'] = $meta->getAttribute('content'); + } + elseif($name == "description") { + $mediaInfos['description'] = $meta->getAttribute('content'); + } + + } + elseif($meta->getAttribute('itemprop')) { + $itemprop = $meta->getAttribute('itemprop'); + $itemprop = mb_strtolower($itemprop); + + # google plus + if($itemprop == "name") { + $mediaInfos['title'] = $meta->getAttribute('content'); + } + elseif($itemprop == "description") { + $mediaInfos['description'] = $meta->getAttribute('content'); + } + elseif($itemprop == "image") { + $mediaInfos['image'] = $meta->getAttribute('content'); + } + + } + } + + + if(!isset($mediaInfos['title'])) { + $titleDom = $xpath->query('//html/head/title'); + $mediaInfos['title'] = $titleDom->item(0)->nodeValue; + } + + return $mediaInfos; + } } ?> diff --git a/webroot/lib/tag.class.php b/webroot/lib/tag.class.php new file mode 100644 index 0000000..6f33597 --- /dev/null +++ b/webroot/lib/tag.class.php @@ -0,0 +1,28 @@ +<?php +/** + * Insipid + * Personal web-bookmark-system + * + * Copyright 2016-2017 Johannes KeÃler + * + * Development starting from 2011: Johannes KeÃler + * https://www.bananas-playground.net/projekt/insipid/ + * + * creator: + * Luke Reeves <luke@neuro-tech.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0. + * + */ + ?> \ No newline at end of file diff --git a/webroot/view/home.inc.php b/webroot/view/home.inc.php index 3f63929..af4b756 100644 --- a/webroot/view/home.inc.php +++ b/webroot/view/home.inc.php @@ -33,8 +33,14 @@ $queryStr = false; $searchResult = false; $showAddForm = false; $formData = false; +$honeypotCheck = false; -if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch'])) { +if((isset($_POST['password']) && !empty($_POST['password'])) || (isset($_POST['username']) && !empty($_POST['username']))) { + # those are hidden fields. A robot my input these. A valid user does not. + $honeypotCheck = true; +} + +if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch']) && $honeypotCheck === false) { $searchValue = trim($_POST['data']['searchfield']); $isUrl = Summoner::validate($searchValue,'url'); if($isUrl === true) { @@ -55,8 +61,18 @@ if(isset($_POST['data']) && !empty($_POST['data']) && isset($_POST['submitsearch # new one? if(empty($searchResult) && $isUrl === true) { + # try to gather some information automatically + $linkInfo = Summoner::gatherInfoFromURL($searchValue); + if(!empty($linkInfo)) { + $formData['description'] = $linkInfo['description']; + $formData['title'] = $linkInfo['title']; + $formData['image'] = $linkInfo['image']; + } # show the add form $showAddForm = true; $formData['url'] = $searchValue; } -} \ No newline at end of file +} + +$existingCategories = $Management->categories(); +$existingTags = $Management->tags(); \ No newline at end of file diff --git a/webroot/view/home.php b/webroot/view/home.php index be4fbd1..60ff137 100644 --- a/webroot/view/home.php +++ b/webroot/view/home.php @@ -35,6 +35,8 @@ <div class="row"> <div class="large-12 columns"> <form method="post"> + <input type="hidden" name="password" /> + <input type="hidden" name="username" /> <div class="input-group"> <span class="input-group-label"><i class="fi-link"></i></span> <input class="input-group-field" type="url" name="data[searchfield]"> @@ -66,6 +68,8 @@ <?php if($showAddForm) { ?> <form method="post"> + <input type="hidden" name="password" /> + <input type="hidden" name="username" /> <div class="row"> <div class="large-12 columns"> <h3>This URL was not found. Want to add it?</h3> @@ -82,35 +86,73 @@ <div class="row"> <div class="large-6 columns"> <label> - Username - <input type="text" name="data[username]" /> + Description + <input type="text" name="data[description]" value="<?php echo Summoner::ifset($formData, 'description'); ?>" /> </label> </div> + <div class="large-6 columns"> + <label> + Title + <input type="text" name="data[title]" value="<?php echo Summoner::ifset($formData, 'title'); ?>" /> + </label> + </div> + </div> + <div class="row"> <div class="large-6 columns"> <label> - Password - <input type="password" name="data[password]" /> + Image Link + <input type="url" name="data[image]" value="<?php echo Summoner::ifset($formData, 'image'); ?>" /> </label> </div> + <div class="large-6 columns"> + <img class="linkthumbnail" src="<?php echo Summoner::ifset($formData, 'image'); ?>" alt="Image from provided link" /> + </div> </div> - <div class="row"> <div class="large-6 columns"> <label> Category - <select name="data[category]"></select> + <input type="text" name="data[category]" list="categorylist" /> + <datalist id="categorylist"> + <?php foreach($existingCategories as $c) { ?> + <option value="<?php echo $c; ?>"> + <?php } ?> + </datalist> </label> </div> <div class="large-6 columns"> <label> Tag - <select name="data[tag]"></select> + <input type="text" name="data[tag]" list="taglist" /> + <datalist id="taglist"> + <?php foreach($existingTags as $t) { ?> + <option value="<?php echo $t; ?>"> + <?php } ?> + </datalist> </label> </div> </div> <div class="row"> - <div class="large-12 columns"> + <div class="large-6 columns"> + <label> + Username + <input type="text" name="data[username]" /> + </label> + </div> + <div class="large-6 columns"> + <label> + Password + <input type="password" name="data[password]" /> + </label> + </div> + </div> + + <div class="row"> + <div class="large-8 columns"> + <input type="checkbox" name="data[private]" value="1" /><label>Private</label> + </div> + <div class="large-4 columns text-right" > <input type="submit" class="button" value="Add new Link"> </div> </div>