├── .gitignore ├── .htaccess ├── 1x1_spacer.gif ├── COPYRIGHT.txt ├── LICENSE.txt ├── README.md ├── config ├── .htaccess ├── access.json └── config.php.dist ├── controllers ├── .htaccess ├── access.php ├── gpu.php ├── main.php ├── notify.php └── pools.php ├── cron.php ├── includes ├── .htaccess ├── APIException.class.php ├── APIRequestException.class.php ├── AccessConfig.class.php ├── AccessControl.class.php ├── AjaxModul.php ├── Config.class.php ├── Controller.class.php ├── Db.class.php ├── ErrorHandler.class.php ├── HttpClient.class.php ├── InfoException.class.php ├── PHPMailer.class.php ├── PHPMinerException.class.php ├── PHPMinerRPC.class.php ├── ParamStruct.class.php ├── PasswordHash.class.php ├── PoolConfig.class.php ├── RapidPush.class.php ├── SMTP.class.php ├── Session.class.php ├── Updates.class.php ├── common.php ├── pool_apis │ ├── PoolAPI.class.php │ └── mpos.class.php └── validators │ ├── AbstractHtmlValidator.class.php │ ├── FilterValidator.php │ ├── FunctionValidator.class.php │ ├── IsNumberValidator.class.php │ ├── IssetValidator.class.php │ ├── LengthValidator.class.php │ ├── RegexpValidator.class.php │ ├── RequiredValidator.class.php │ └── UrlValidator.class.php ├── index.php ├── linux_setup.sh ├── phpminer_rpcclient ├── .htaccess ├── config.dist.php ├── config.php ├── includes │ ├── APIException.class.php │ ├── APIRequestException.class.php │ ├── CGMinerAPI.class.php │ ├── Config.class.php │ ├── RPCClientApi.class.php │ ├── RPCClientConnection.class.php │ ├── RPCClientServer.class.php │ └── common.php ├── index.php ├── linux_rpcclient_setup.sh ├── phpminer_rpcclient ├── rpcclient_cron.sh └── test_api_commands.php ├── scrypt130511Pitcairnglg2tc8128w256l8.bin ├── templates ├── .htaccess ├── ajax-loader.gif ├── bootstrap │ ├── config.json │ ├── css │ │ ├── bootstrap.css │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js ├── css │ ├── OpenSans-CondensedBold.woff │ ├── OpenSans-CondensedLight.woff │ ├── OpenSans-CondensedLightItalic.woff │ ├── jquery.nouislider.css │ ├── main.css │ ├── popup.css │ ├── reset.css │ └── status_box.css ├── fontello │ ├── LICENSE.txt │ ├── README.txt │ ├── config.json │ ├── css │ │ ├── animation.css │ │ ├── phpminer-codes.css │ │ ├── phpminer-embedded.css │ │ ├── phpminer-ie7-codes.css │ │ ├── phpminer-ie7.css │ │ └── phpminer.css │ ├── demo.html │ └── font │ │ ├── phpminer.eot │ │ ├── phpminer.svg │ │ ├── phpminer.ttf │ │ └── phpminer.woff ├── html.tpl.php ├── js │ ├── common.js │ ├── core.js │ ├── jquery-1.10.2.min.js │ ├── jquery.nouislider.js │ ├── jquery.nouislider.min.js │ └── jquery.tablednd.js ├── status_message.tpl.php └── x-editable │ ├── CHANGELOG.txt │ ├── LICENSE-MIT │ ├── README.md │ ├── bootstrap3-editable │ ├── css │ │ └── bootstrap-editable.css │ ├── img │ │ ├── clear.png │ │ └── loading.gif │ └── js │ │ ├── bootstrap-editable.js │ │ └── bootstrap-editable.min.js │ └── inputs-ext │ ├── address │ ├── address.css │ └── address.js │ ├── typeaheadjs │ ├── lib │ │ ├── typeahead.js │ │ └── typeahead.js-bootstrap.css │ └── typeaheadjs.js │ └── wysihtml5 │ ├── bootstrap-wysihtml5-0.0.2 │ ├── bootstrap-wysihtml5-0.0.2.css │ ├── bootstrap-wysihtml5-0.0.2.js │ ├── bootstrap-wysihtml5-0.0.2.min.js │ ├── wysihtml5-0.3.0.js │ ├── wysihtml5-0.3.0.min.js │ └── wysiwyg-color.css │ └── wysihtml5.js └── views ├── .htaccess ├── access ├── index.css ├── index.js ├── index.tpl.php └── user_add.tpl.php ├── main ├── fix_pool_manual.css ├── fix_pool_manual.js ├── fix_pool_manual.tpl.php ├── init.css ├── init.js ├── init.tpl.php ├── settings.css ├── settings.js └── settings.tpl.php ├── notify ├── settings.css ├── settings.js └── settings.tpl.php ├── pools ├── main.css ├── main.js └── main.tpl.php └── system ├── setup.js └── setup.tpl.php /.gitignore: -------------------------------------------------------------------------------- 1 | config/config.json 2 | config/config.php 3 | config/phpminer.db 4 | config/pools.json 5 | config/notify.json 6 | phpminer_rpcclient/config.php 7 | phpminer_rpcclient/config.json 8 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | AddDefaultCharset utf-8 2 | Options +FollowSymLinks 3 | Options -Indexes 4 | 5 | # Various rewrite rules. 6 | 7 | 8 | RewriteEngine on 9 | RewriteRule "(^|/)\." - [F] 10 | 11 | RewriteEngine on 12 | RewriteRule ^cron\.php$ - [R=404] 13 | 14 | RewriteEngine on 15 | RewriteBase / 16 | RewriteCond %{REQUEST_FILENAME} !-f 17 | RewriteCond %{REQUEST_FILENAME} !-d 18 | RewriteCond %{REQUEST_URI} !=/favicon.ico 19 | RewriteCond %{REQUEST_URI} !=/favicon.gif 20 | RewriteRule ^ index.php [L] 21 | 22 | 23 | # Rules to correctly serve gzip compressed CSS and JS files. 24 | # Requires both mod_rewrite and mod_headers to be enabled. 25 | 26 | # Serve gzip compressed CSS files if they exist and the client accepts gzip. 27 | RewriteCond %{HTTP:Accept-encoding} gzip 28 | RewriteCond %{REQUEST_FILENAME}\.gz -s 29 | RewriteRule ^(.*)\.css $1\.css\.gz [QSA] 30 | 31 | # Serve gzip compressed JS files if they exist and the client accepts gzip. 32 | RewriteCond %{HTTP:Accept-encoding} gzip 33 | RewriteCond %{REQUEST_FILENAME}\.gz -s 34 | RewriteRule ^(.*)\.js $1\.js\.gz [QSA] 35 | 36 | # Serve correct content types, and prevent mod_deflate double gzip. 37 | RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1] 38 | RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1] 39 | 40 | 41 | # Serve correct encoding type. 42 | Header append Content-Encoding gzip 43 | # Force proxies to cache gzipped & non-gzipped css/js files separately. 44 | Header append Vary Accept-Encoding 45 | 46 | 47 | -------------------------------------------------------------------------------- /1x1_spacer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/1x1_spacer.gif -------------------------------------------------------------------------------- /COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | All PHPMiner code is Copyright 2014 - 2016 by the original authors. 2 | 3 | Author: Christian Ackermann 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or (at 8 | your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, but 11 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 | for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program as the file LICENSE.txt; if not, please see 17 | http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 18 | 19 | PHPMiner includes works under other copyright notices and distributed 20 | according to the terms of the GNU General Public License or a compatible 21 | license, including: 22 | 23 | - jQuery - Copyright (c) 2008 - 2009 John Resig 24 | - PHPMailer - PHP email class - Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. - Copyright (c) 2001-2003, Brent R. Matzelle 25 | - Bootstrap - Code licensed under Apache License v2.0, documentation under CC BY 3.0. 26 | - Fontello - All license are included at the file templates/fontello/LICENSE.txt 27 | - x-editable - Copyright (c) 2012 Vitaliy Potapov 28 | - jquery nouislider - WTFPL http://www.wtfpl.net/about/ -------------------------------------------------------------------------------- /config/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule .* - [R=404] -------------------------------------------------------------------------------- /config/access.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/config/access.json -------------------------------------------------------------------------------- /config/config.php.dist: -------------------------------------------------------------------------------- 1 | 'mysql', 4 | 'server' => 'localhost', 5 | 'database' => 'phpminer', 6 | 'username' => 'phpminer', 7 | 'password' => '', 8 | ); 9 | -------------------------------------------------------------------------------- /controllers/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule .* - [R=404] -------------------------------------------------------------------------------- /controllers/access.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | require_once 'includes/validators/FunctionValidator.class.php'; 8 | class access extends Controller { 9 | 10 | 11 | /** 12 | * Display a list of all users 13 | */ 14 | public function index() { 15 | 16 | if (!AccessControl::getInstance()->is_enabled()) { 17 | throw new AccessException('Access control is disabled, if you working alone with your own rigs you don\'t need access control, otherweise enable it first within the main settings'); 18 | } 19 | $users = array(); 20 | $groups = array(); 21 | try { 22 | AccessControl::check_permission(AccessControl::PERM_MANAGE_USERS); 23 | foreach ($this->access_control->get_config()->user_get() AS $user) { 24 | $users[$user] = $this->access_control->get_config()->user_get($user); 25 | unset($users[$user]['password']); 26 | } 27 | foreach ($this->access_control->get_config()->group_get() AS $group) { 28 | $groups[$group] = $this->access_control->get_config()->group_get($group); 29 | $groups[$group]['permissions'] = $this->access_control->get_config()->group_get_permission($group); 30 | } 31 | } catch (Exception $e) { 32 | $users = false; 33 | $groups = false; 34 | } 35 | $this->js_config('users', $users); 36 | $this->js_config('groups', $groups); 37 | 38 | $this->js_config('possible_permissions', AccessControl::get_permission_array()); 39 | } 40 | 41 | 42 | /** 43 | * Delete a user. 44 | */ 45 | public function delete_user() { 46 | AccessControl::check_permission(AccessControl::PERM_MANAGE_USERS); 47 | $params = new ParamStruct(); 48 | $params->add_required_param('username', PDT_STRING); 49 | 50 | $params->fill(); 51 | if (!$params->is_valid()) { 52 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER); 53 | } 54 | 55 | $this->access_control->get_config()->user_del($params->username); 56 | AjaxModul::return_code(AjaxModul::SUCCESS); 57 | } 58 | 59 | /** 60 | * Add/Change a user. 61 | */ 62 | public function user_add() { 63 | AccessControl::check_permission(AccessControl::PERM_MANAGE_USERS); 64 | $params = new ParamStruct(); 65 | $params->add_param('old_user', PDT_STRING, ''); 66 | $params->add_param('group', PDT_STRING, null); 67 | $params->add_required_param('username', PDT_STRING); 68 | $params->add_param('password', PDT_STRING, null); 69 | 70 | $params->fill(); 71 | 72 | if (!$params->is_valid()) { 73 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER); 74 | } 75 | 76 | if ($params->username !== $params->old_user && AccessControl::getInstance()->get_config()->user_exists($params->username)) { 77 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER, null, true, 'This user already exists.'); 78 | } 79 | 80 | if (empty($params->old_user)) { 81 | if (empty($params->password)) { 82 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER, null, true, 'Password can only be left empty when you edit a user'); 83 | } 84 | } 85 | $current_users = $this->access_control->get_config()->user_get(); 86 | if (!empty($current_users)) { 87 | $group = $params->group; 88 | if (empty($group)) { 89 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER, null, true, "You didn't provided a access group"); 90 | } 91 | } 92 | $old_user = $params->old_user; 93 | if (empty($old_user)) { 94 | if (empty($current_users)) { 95 | if (!$this->access_control->get_config()->group_exists('admin')) { 96 | $this->access_control->get_config()->group_add('admin'); 97 | } 98 | $group = 'admin'; 99 | $this->access_control->get_config()->group_grant_permission('admin', '*'); 100 | } 101 | $result = $this->access_control->get_config()->user_add($params->username, $params->password, $group); 102 | } 103 | else { 104 | $result = $this->access_control->get_config()->user_update($params->old_user, $params->username, (empty($params->password)) ? null : $params->password, $params->group); 105 | } 106 | if ($result) { 107 | AjaxModul::return_code(AjaxModul::SUCCESS); 108 | } 109 | AjaxModul::return_code(AjaxModul::ERROR_DEFAULT, null, true, 'Could not add or update the user'); 110 | } 111 | 112 | /** 113 | * Delete a user group. 114 | */ 115 | public function delete_group() { 116 | AccessControl::check_permission(AccessControl::PERM_MANAGE_USERS); 117 | $params = new ParamStruct(); 118 | $params->add_required_param('name', PDT_STRING); 119 | 120 | $params->fill(); 121 | if (!$params->is_valid()) { 122 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER); 123 | } 124 | 125 | $this->access_control->get_config()->group_delete($params->name); 126 | AjaxModul::return_code(AjaxModul::SUCCESS); 127 | } 128 | 129 | /** 130 | * Add/Change a group. 131 | */ 132 | public function group_add() { 133 | AccessControl::check_permission(AccessControl::PERM_MANAGE_USERS); 134 | $params = new ParamStruct(); 135 | $params->add_param('old_name', PDT_STRING, ''); 136 | $params->add_required_param('name', PDT_STRING); 137 | $params->add_param('permissions', PDT_ARR, array()); 138 | 139 | $params->fill(); 140 | if (!$params->is_valid()) { 141 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER); 142 | } 143 | 144 | $old = $params->old_name; 145 | 146 | if ($params->name !== $old && AccessControl::getInstance()->get_config()->group_exists($params->name)) { 147 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER, null, true, 'This group already exists.'); 148 | } 149 | 150 | if (empty($old)) { 151 | $result = $this->access_control->get_config()->group_add($params->name); 152 | } 153 | else { 154 | $this->access_control->get_config()->group_revoke_all_permission($old); 155 | $result = $this->access_control->get_config()->group_change($old, $params->name); 156 | } 157 | 158 | 159 | 160 | foreach ($params->permissions AS $permission) { 161 | $this->access_control->get_config()->group_grant_permission($params->name, $permission); 162 | } 163 | 164 | if ($result) { 165 | AjaxModul::return_code(AjaxModul::SUCCESS); 166 | } 167 | AjaxModul::return_code(AjaxModul::ERROR_DEFAULT, null, true, 'Could not add or update the user'); 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /controllers/notify.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | require_once 'includes/validators/FunctionValidator.class.php'; 8 | class notify extends Controller { 9 | 10 | 11 | public function settings() { 12 | AccessControl::check_permission(AccessControl::PERM_CHANGE_NOTIFICATION_SETTINGS); 13 | $this->assign('config', $this->config->get_config('notify')); 14 | $this->assign('rigs', array_keys($this->config->rigs)); 15 | } 16 | 17 | /** 18 | * Ajax request to save new configuration settings. 19 | */ 20 | public function save_settings() { 21 | AccessControl::check_permission(AccessControl::PERM_CHANGE_NOTIFICATION_SETTINGS); 22 | $params = new ParamStruct(); 23 | $params->add_required_param('settings', PDT_ARR); 24 | 25 | $params->fill(); 26 | if (!$params->is_valid()) { 27 | AjaxModul::return_code(AjaxModul::ERROR_INVALID_PARAMETER); 28 | } 29 | db::getInstance()->begin(); 30 | foreach ($params->settings AS $key => $val) { 31 | $this->config->set_value($key, $val, 'notify'); 32 | } 33 | db::getInstance()->commit(); 34 | AjaxModul::return_code(AjaxModul::SUCCESS); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /includes/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule .* - [R=404] -------------------------------------------------------------------------------- /includes/APIException.class.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | class APIException extends Exception { 7 | const CODE_SOCKET_CREATE_ERROR = 501; 8 | const CODE_SOCKET_CONNECT_ERROR = 502; 9 | const CODE_SOCKET_NOT_CONNECTED = 503; 10 | const CODE_INVALID_PARAMETER = 504; 11 | } -------------------------------------------------------------------------------- /includes/APIRequestException.class.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | class APIRequestException extends Exception { 7 | } -------------------------------------------------------------------------------- /includes/AjaxModul.php: -------------------------------------------------------------------------------- 1 | 5 | * This needed for ajax action to return needed json encoded string 6 | * 7 | * @copyright Christian Ackermann (c) 2013 - End of life 8 | * @author Christian Ackermann 9 | * @category Ajax 10 | */ 11 | abstract class AjaxModul 12 | { 13 | /** 14 | * Define constances 15 | */ 16 | const SUCCESS = 200; 17 | const SUCCESS_NO_CHANGES = 201; 18 | const SUCCESS_CANCEL = 205; 19 | const SUCCESS_RELOAD = 206; 20 | 21 | const SUCCESS_REDIRECT = 301; 22 | 23 | const ERROR_INVALID_PARAMETER = 405; 24 | const ERROR_MISSING_PARAMETER = 406; 25 | const ERROR_DATABASE_ERROR = 407; 26 | 27 | const ERROR_DEFAULT = 501; 28 | const ERROR_MODULE_NOT_FOUND = 502; 29 | const ERROR_SECURITY_LOCK = 550; 30 | const ERROR_AJAX_ERROR = 560; 31 | 32 | const ERROR_NOT_LOGGEDIN = 602; 33 | const ERROR_NO_RIGHTS = 601; 34 | 35 | const NEED_CONFIRM = 701; 36 | 37 | /** 38 | * Will return an array with
39 | * array("code" => $code, "desc" => $desc, "data" => $data) 40 | * if $die is set to true it will print out the json encoded string for that array 41 | * and directly die 42 | * 43 | * @param int $code 44 | * the return code, use one AjaxModul::* 45 | * @param mixed $data 46 | * the additional data to be returned (optional, default = null) 47 | * @param boolean $die 48 | * whether to output the data and die or to return the data (optional, default = true) 49 | * @param string $desc 50 | * the error description (optional, default = '') 51 | * 52 | * @return array the returning array with format array("code" => $code, "desc" => $desc, "data" => $data) 53 | */ 54 | static function return_code($code, $data = null, $die = true, $desc = "") { 55 | global $phpminer_error_handler_messages; 56 | $current_output = ob_get_clean(); 57 | ob_start(); 58 | if (!empty($current_output)) { 59 | $code = AjaxModul::ERROR_AJAX_ERROR; 60 | $data = sys_get_temp_dir() . '/phpminer_' . uniqid() . '.bugreport'; 61 | $die = true; 62 | file_put_contents($data, $current_output); 63 | } 64 | switch ((int)$code) { 65 | default: $return = array("code" => $code, "desc" => $desc, "data" => $data); 66 | } 67 | if ($die === null) { 68 | $die = true; 69 | } 70 | if ($die == true) { 71 | if (empty($phpminer_error_handler_messages)) { 72 | echo json_encode($return); 73 | } 74 | die(); 75 | } 76 | return $return; 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /includes/Db.class.php: -------------------------------------------------------------------------------- 1 | "; 28 | $msg .= "

Hey dude,

"; 29 | $msg .= "It looks like you have just upgraded from an old version or you have just installed PHPMiner.
"; 30 | $msg .= "This new version of PHPMiner requires a mysql database. If you don't know how to install it. Please search for it on the net. It's not so complex.
"; 31 | $msg .= "When you are on debian based system it's quite simple. Just type apt-get install mysql-server.
"; 32 | $msg .= "The problem I have is, you didn't configurated the mysql credentials within config.php.
"; 33 | $msg .= "Please copy the provided config.php.dist to config.php and provide your mysql connection details.
"; 34 | $msg .= "Don't worry about your data. The old data from the *.json files will be imported.
"; 35 | $msg .= ""; 36 | throw new InfoException($msg); 37 | } 38 | 39 | $this->db = new PDO($db['type'] . ':host=' . $db['server'] . ';dbname=' . $db['database'] . ';charset=utf8', $db['username'], $db['password']); 40 | try { 41 | if ($db['type'] === 'mysql') { 42 | $this->db->exec("SET SESSION SQL_MODE=ANSI_QUOTES;"); 43 | } 44 | if ($db['type'] === 'mssql') { 45 | $this->db->exec("SET QUOTED_IDENTIFIER ON;"); 46 | } 47 | } catch (Exception $ex) { 48 | 49 | } 50 | } 51 | 52 | /** 53 | * Singleton. 54 | * 55 | * @return Db 56 | * The instance object. 57 | */ 58 | public static function getInstance() { 59 | if (self::$instance === null) { 60 | self::$instance = new Db(); 61 | } 62 | 63 | return self::$instance; 64 | } 65 | 66 | /** 67 | * Alias of exec. 68 | * 69 | * @param string $query 70 | * The query. 71 | * @param array $args 72 | * The args. (Optional, default = array()) 73 | * 74 | * @return PDOStatement 75 | */ 76 | public function exec($query, $args = array()) { 77 | $statement = $this->db->prepare($query); 78 | $statement->execute($args); 79 | return $statement; 80 | } 81 | 82 | /** 83 | * Alias of exec. 84 | * 85 | * @param string $query 86 | * The query. 87 | * @param array $args 88 | * The args. (Optional, default = array()) 89 | * 90 | * @return PDOStatement 91 | */ 92 | public function query($query, $args = array()) { 93 | return $this->exec($query, $args); 94 | } 95 | 96 | /** 97 | * 98 | * @param string $query 99 | * The query. 100 | * @param boolean $entire_row 101 | * Set to true if all columns should be returned, else the value of the first found column is returned. (Optional, default = false) 102 | * @param array $args 103 | * The args. (Optional, default = array()) 104 | * 105 | * @return mixed 106 | * The value of the first column if entire row is set to false, else all columns. 107 | */ 108 | public function querySingle($query, $entire_row = false, $args = array()) { 109 | $result = $this->exec($query, $args); 110 | 111 | $row = $result->fetch(PDO::FETCH_ASSOC); 112 | if (!$entire_row) { 113 | if (!is_array($row)) { 114 | return $row; 115 | } 116 | $row = reset($row); 117 | } 118 | return $row; 119 | } 120 | 121 | public function begin() { 122 | $this->db->exec("BEGIN"); 123 | } 124 | public function commit() { 125 | $this->db->exec("COMMIT"); 126 | } 127 | public function rollback() { 128 | $this->db->exec("ROLLBACK"); 129 | } 130 | } -------------------------------------------------------------------------------- /includes/ErrorHandler.class.php: -------------------------------------------------------------------------------- 1 | 7 | * @category Tools 8 | */ 9 | class ErrorHandler 10 | { 11 | /** 12 | * Replace the standard php error handler ( this is a callback functions) 13 | * 14 | * @param int $number 15 | * the error number 16 | * @param string $message 17 | * The error message 18 | * @param string $file 19 | * the file where there error appeared 20 | * @param string $line 21 | * the line where the appeared 22 | * @param string $variables 23 | * the variables 24 | * 25 | * @return string the error string. 26 | */ 27 | public static function cc_error_handler($errno = E_NOTICE, $errstr = "", $errfile = "", $errline = "", $variables = "", $from_shutdown = false, $stack = null) { 28 | global $phpminer_error_handler_messages, $phpminer_error_handler_suppressed_messages; 29 | $supress_check = md5($errno.$errstr.$errfile.$errline); 30 | if (error_reporting() == 0 || (($errno & error_reporting()) == 0 ) || isset($phpminer_error_handler_suppressed_messages[$supress_check])) { 31 | $phpminer_error_handler_suppressed_messages[$supress_check] = true; 32 | return false; 33 | } 34 | 35 | // check if function has been called by an exception 36 | if (func_num_args() == 1) { 37 | // caught exception 38 | $exc = func_get_arg(0); 39 | $errno = $exc->getCode(); 40 | $errstr = $exc->getMessage(); 41 | $errfile = $exc->getFile(); 42 | $errline = $exc->getLine(); 43 | 44 | $backtrace = $exc->getTrace(); 45 | } 46 | else { 47 | // called by trigger_error() 48 | $exception = null; 49 | if ($stack !== null) { 50 | $backtrace = $stack; 51 | } 52 | else { 53 | $backtrace = debug_backtrace(); 54 | unset($backtrace[0]); 55 | } 56 | $backtrace = array_reverse($backtrace); 57 | } 58 | 59 | $errorType = array( 60 | E_ERROR => 'ERROR', 61 | E_WARNING => 'WARNING', 62 | E_PARSE => 'PARSING ERROR', 63 | E_NOTICE => 'NOTICE', 64 | E_CORE_ERROR => 'CORE ERROR', 65 | E_CORE_WARNING => 'CORE WARNING', 66 | E_COMPILE_ERROR => 'COMPILE ERROR', 67 | E_COMPILE_WARNING => 'COMPILE WARNING', 68 | E_USER_ERROR => 'USER ERROR', 69 | E_USER_WARNING => 'USER WARNING', 70 | E_USER_NOTICE => 'USER NOTICE', 71 | E_STRICT => 'STRICT NOTICE', 72 | E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR' 73 | ); 74 | 75 | $ignoreErrorType = array( 76 | 77 | E_CORE_ERROR => 'CORE ERROR', 78 | E_CORE_WARNING => 'CORE WARNING', 79 | E_COMPILE_ERROR => 'COMPILE ERROR', 80 | E_COMPILE_WARNING => 'COMPILE WARNING', 81 | E_STRICT => 'STRICT NOTICE', 82 | E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR' 83 | ); 84 | 85 | // create error message 86 | if (isset($errorType[$errno])) { 87 | if (isset($ignoreErrorType[$errno])) { 88 | return false; 89 | } 90 | $err = $errorType[$errno]; 91 | } 92 | else { 93 | if ($exception !== null && $exception instanceof Exception) { 94 | $err = 'UNCAUGHT EXCEPTION ' . get_class($exception) . '(' . $errno . ')'; 95 | } 96 | else { 97 | $err = 'UNCAUGHT EXCEPTION (' . $errno . ')'; 98 | } 99 | } 100 | 101 | $errMsgPlain = ""; 102 | $lastfile = ''; 103 | $errMsgPlain.= "Error: " . $err . ": " . $errstr . " in " . $errfile . " on line " . $errline . "
\n"; 104 | 105 | $errMsgPlain .= "Backtrace:
\n"; 106 | foreach ($backtrace as $row) { 107 | if (empty($row['file'])) 108 | $row['file'] = '(unknown)'; 109 | if (empty($row['line'])) 110 | $row['line'] = '(unknown)'; 111 | if ($lastfile != $row['file']) { 112 | $errMsgPlain .= "File: " . $row['file'] . "
\n"; 113 | } 114 | 115 | 116 | $lastfile = $row['file']; 117 | $errMsgPlain .= " Line: " . $row['line'] . ": "; 118 | if (!empty($row['class'])) { 119 | 120 | $errMsgPlain .= $row['class'] . $row['type'] . $row['function']; 121 | } 122 | elseif (isset($row['function'])) { 123 | $errMsgPlain .= $row['function']; 124 | } 125 | else { 126 | $errMsgPlain .= 'Unknown function or method'; 127 | } 128 | 129 | if (empty($row['args'])) { 130 | $errMsgPlain .= ' (no args)'; 131 | } 132 | else { 133 | $errMsgPlain .= ' (Args: '; 134 | $separator = ''; 135 | foreach ($row['args'] as $arg) { 136 | 137 | $value = self::getArgument($arg); 138 | 139 | 140 | $errMsgPlain .= $separator . $value; 141 | $separator = ', '; 142 | } 143 | $errMsgPlain .= ')'; 144 | } 145 | $errMsgPlain .= "
\n"; 146 | } 147 | 148 | 149 | if ($from_shutdown) { 150 | ob_get_clean(); 151 | ob_start(); 152 | $phpminer_error_handler_messages[] = $errMsgPlain; 153 | return $phpminer_error_handler_messages; 154 | } 155 | 156 | if (ini_get("display_errors")) { 157 | global $phpminer_request_is_ajax; 158 | if (!$phpminer_request_is_ajax) { 159 | $phpminer_error_handler_messages[] = '
' . $errMsgPlain . '
'; 160 | } 161 | else { 162 | $phpminer_error_handler_messages[] = $errMsgPlain; 163 | } 164 | } 165 | 166 | if (ini_get('log_errors')) { 167 | error_log($errMsgPlain); 168 | } 169 | return $phpminer_error_handler_messages; 170 | } 171 | 172 | /** 173 | * Parses a value to a string which is more preciser than var_export. 174 | * 175 | * @param mixed $arg 176 | * the value 177 | * 178 | * @return string the formated argument 179 | */ 180 | public static function getArgument($arg) { 181 | switch (strtolower(gettype($arg))) { 182 | case 'string': 183 | return( '"' . str_replace(array("
\n"), array(''), $arg) . '"' ); 184 | 185 | case 'boolean': 186 | return (bool) $arg; 187 | 188 | case 'object': 189 | return 'object(' . get_class($arg) . ')'; 190 | 191 | case 'array': 192 | $ret = 'array('; 193 | $separtor = ''; 194 | 195 | foreach ($arg as $k => $v) { 196 | #$ret .= $separtor . self::getArgument($k) . ' => ' . self::getArgument($v); 197 | $separtor = ', '; 198 | } 199 | $ret .= ')'; 200 | 201 | return $ret; 202 | 203 | case 'resource': 204 | return 'resource(' . get_resource_type($arg) . ')'; 205 | 206 | default: 207 | return var_export($arg, true); 208 | } 209 | } 210 | 211 | } -------------------------------------------------------------------------------- /includes/InfoException.class.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | class PHPMinerException extends Exception { 7 | const CODE_CONFIG_NOT_READABLE = 502; 8 | const CODE_CONFIG_NOT_WRITEABLE = 503; 9 | const CODE_CONFIG_INVALID_JSON = 504; 10 | } -------------------------------------------------------------------------------- /includes/RapidPush.class.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | class RapidPush { 10 | 11 | /** 12 | * Defines the RapidPush API-Service URL. 13 | */ 14 | const API_SERVICE_URL = 'https://rapidpush.net/api'; 15 | 16 | /** 17 | * Holds the API-Key. 18 | * 19 | * @var string 20 | */ 21 | private $api_key = ''; 22 | 23 | /** 24 | * Constructs the RapidPush object with the given api key. 25 | * 26 | * @param string $api_key 27 | * The api key. 28 | */ 29 | public function __construct($api_key) { 30 | $this->api_key = $api_key; 31 | } 32 | 33 | /** 34 | * Sends a broadcast notification to the channel. 35 | * 36 | * @param string $title 37 | * The title. 38 | * @param string $message 39 | * The message. 40 | * @param string $channel 41 | * The channel 42 | * 43 | * @return array The response array. 44 | */ 45 | public function broadcast($title, $message, $channel) { 46 | return $this->execute('broadcast', array( 47 | 'title' => $title, 48 | 'message' => $message, 49 | 'channel' => $channel, 50 | )); 51 | } 52 | 53 | /** 54 | * Sends a notification. 55 | * 56 | * @param string $title 57 | * The title. 58 | * @param string $message 59 | * The message. 60 | * @param int $priority 61 | * The priority. (optional, default = 2) 62 | * @param string $category 63 | * The category. (optional, default = 'default') 64 | * @param string $group 65 | * The device group. (optional, default = '') 66 | * 67 | * @return array The response array. 68 | */ 69 | public function notify($title, $message, $priority = 2, $category = "default", $group = "") { 70 | return $this->execute('notify', array( 71 | 'title' => $title, 72 | 'message' => $message, 73 | 'priority' => $priority, 74 | 'category' => $category, 75 | 'group' => $group, 76 | )); 77 | } 78 | 79 | /** 80 | * Schedule a notification. 81 | * 82 | * @param int when 83 | * The local timestamp. 84 | * @param string $title 85 | * The title. 86 | * @param string $message 87 | * The message. 88 | * @param int $priority 89 | * The priority. (optional, default = 2) 90 | * @param string $category 91 | * The category. (optional, default = 'default') 92 | * @param string $group 93 | * The device group. (optional, default = '') 94 | * 95 | * @return array The response array. 96 | */ 97 | public function schedule($when, $title, $message, $priority = 2, $category = "default", $group = "") { 98 | return $this->execute('notify', array( 99 | 'title' => $title, 100 | 'message' => $message, 101 | 'priority' => $priority, 102 | 'category' => $category, 103 | 'group' => $group, 104 | 'schedule_at' => gmdate("Y-m-d H:i:00", $when), 105 | )); 106 | } 107 | 108 | /** 109 | * Get the configurated device groups. 110 | * 111 | * @return array The response array, where the groups will be within the data key. 112 | */ 113 | public function get_groups() { 114 | return $this->execute('get_groups', array()); 115 | } 116 | 117 | /** 118 | * Makes an API call. 119 | * 120 | * @param string $command 121 | * The API-Command 122 | * @param array $data 123 | * The data to be send. 124 | * @param boolean $post 125 | * Whether we want to do a POST (set to true )or GET (set to false). (optional, default = true) 126 | * 127 | * @return array The response array. 128 | */ 129 | private function execute($command, $data, $post = true) { 130 | 131 | $ch = curl_init(); 132 | curl_setopt($ch, CURLOPT_URL, self::API_SERVICE_URL); 133 | 134 | if ($post === true) { 135 | curl_setopt($ch, CURLOPT_POST, true); 136 | curl_setopt($ch, CURLOPT_POSTFIELDS, array( 137 | 'apikey' => $this->api_key, 138 | 'command' => $command, 139 | 'data' => json_encode($data), 140 | )); 141 | } 142 | 143 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 144 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); 145 | curl_setopt($ch, CURLOPT_HEADER, 0); 146 | curl_setopt($ch, CURLOPT_USERAGENT, "RapidPush PHP-Library"); 147 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 148 | curl_setopt($ch, CURLOPT_MAXREDIRS, 15); 149 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 150 | 151 | $result = curl_exec($ch); 152 | 153 | curl_close($ch); 154 | return json_decode($result, true); 155 | } 156 | } -------------------------------------------------------------------------------- /includes/Session.class.php: -------------------------------------------------------------------------------- 1 | 8 | * @category Security 9 | */ 10 | class Session 11 | { 12 | /** 13 | * Define constances 14 | */ 15 | const SESSION_KEY_USER_ID = 'user_id'; 16 | const SESSION_KEY_USER_USERNAME = 'username'; 17 | const SESSION_KEY_USER_PASSWORD = 'password'; 18 | 19 | /** 20 | * The php session id 21 | * 22 | * @var string 23 | */ 24 | private $session_id = null; 25 | 26 | /** 27 | * hold the session keys for an user login 28 | * @var array 29 | */ 30 | private $session_keys = array( 31 | "id" => "user_id", 32 | "user" => "username", 33 | "pass" => "password", 34 | ); 35 | 36 | /** 37 | * Construct 38 | * 39 | * Creating a session object will always creates a session if not already exist 40 | * 41 | * @param Core &$core 42 | * the core object to setup (This is needed because globals core maybe does not exists (optional, default = null) 43 | */ 44 | public function __construct() { 45 | $this->start_session(); 46 | } 47 | 48 | /** 49 | * Set session variable keys 50 | * 51 | * @param string $key 52 | * the array key 53 | * @param string $value 54 | * the value to be set 55 | * 56 | * @return Session Self returning. 57 | */ 58 | public function &set($key, $value) { 59 | $_SESSION[$key] = $value; 60 | return $this; 61 | } 62 | 63 | /** 64 | * Get session variable keys 65 | * 66 | * @param string $key 67 | * the array key 68 | * @param string $default_value 69 | * return this value if key not found (optional, default = null) 70 | * 71 | * @return mixed return the value from given key, if key not exists return $default_value 72 | */ 73 | public function get($key, $default_value = null) { 74 | return (isset($_SESSION[$key])) ? $_SESSION[$key] : $default_value; 75 | } 76 | 77 | /** 78 | * Deletes the given key from session 79 | * 80 | * @param string $key 81 | * The session key 82 | */ 83 | public function delete($key) { 84 | if (isset($_SESSION[$key])) { 85 | unset($_SESSION[$key]); 86 | } 87 | } 88 | 89 | /** 90 | * Start a php session, it will start it only if no session_id exists 91 | */ 92 | public function start_session() { 93 | //Get current session id 94 | $tmp_sessid = session_id(); 95 | 96 | //If we have no session id we start the session 97 | if (empty($tmp_sessid)) { 98 | session_start(); 99 | $this->session_id = session_id(); 100 | } 101 | else if (empty($this->session_id)) { 102 | $this->session_id = $tmp_sessid; 103 | } 104 | } 105 | 106 | /** 107 | * Closes the session for write operations, this will speed up reads. 108 | */ 109 | public function close_write() { 110 | session_write_close(); 111 | } 112 | 113 | /** 114 | * Returns the current session id 115 | * 116 | * @return string the current session id 117 | */ 118 | public function get_session_id() { 119 | return $this->session_id; 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /includes/common.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | ini_set('display_errors', 'on'); 11 | error_reporting(E_ALL); 12 | 13 | define("TIME_NOW", time()); 14 | define("TIME_NOW_GMT", strtotime(gmdate("Y-m-d H:i:s", TIME_NOW))); 15 | define("DB_DATE", "Y-m-d"); 16 | define("DB_DATETIME", "Y-m-d H:i:s"); 17 | define("DB_TIME", "H:i:s"); 18 | 19 | mb_internal_encoding('UTF-8'); 20 | 21 | /** 22 | * This is not a primitive datatype but it can be used as a real not set variable, so if we realy want to check if a 23 | * parameter was provided to a function/method we can default assign NS so if we pass "", null or something similar to empty 24 | * it is also a allowed "provided" value. The value behind NS is choosen with a string which should never be a value provided by a user 25 | */ 26 | define("NS", "-||notset||-"); 27 | 28 | /** 29 | * Define our primitive datatypes, these are used in several ways. 30 | * Most use is within parameter type checks. 31 | */ 32 | $i = 1; 33 | define("PDT_INT", $i++, true); 34 | define("PDT_FLOAT", $i++, true); 35 | define("PDT_STRING", $i++, true); 36 | define("PDT_DECIMAL", $i++, true); 37 | define("PDT_DATE", $i++, true); 38 | define("PDT_OBJ", $i++, true); 39 | define("PDT_ARR", $i++, true); 40 | define("PDT_BOOL", $i++, true); 41 | define("PDT_INET", $i++, true); 42 | define("PDT_SQLSTRING", $i++, true); 43 | define("PDT_JSON", $i++, true); 44 | define("PDT_PASSWORD", $i++, true); 45 | define("PDT_ENUM", $i++, true); 46 | define("PDT_TEXT", $i++, true); 47 | define("PDT_TINYINT", $i++, true); 48 | define("PDT_MEDIUMINT", $i++, true); 49 | define("PDT_BIGINT", $i++, true); 50 | define("PDT_SMALLINT", $i++, true); 51 | define("PDT_DATETIME", $i++, true); 52 | define("PDT_TIME", $i++, true); 53 | define("PDT_FILE", $i++, true); 54 | define("PDT_LANGUAGE", $i++, true); 55 | define("PDT_LANGUAGE_ENABLED", $i++, true); 56 | define("PDT_SERIALIZED", $i++, true); 57 | define("PDT_BLOB", $i++, true); 58 | 59 | require 'InfoException.class.php'; 60 | require 'Db.class.php'; 61 | require 'Updates.class.php'; 62 | require 'HttpClient.class.php'; 63 | require 'PHPMinerRPC.class.php'; 64 | require 'Controller.class.php'; 65 | 66 | 67 | $system_conf['version'] = array(1, 3, 1); 68 | 69 | // Prevent error message that directory is not set. 70 | $system_conf['directory'] = ''; 71 | if (isset($_SERVER['REQUEST_URI']) && preg_match("/^(.+)?\/(main\/|gpu\/|access\/|notify\/|pools\/|$|index.php)/",$_SERVER['REQUEST_URI'], $matches)) { 72 | $system_conf['directory'] = $matches[1]; 73 | } 74 | 75 | function murl($controller, $action = null, $data = null, $is_json = false) { 76 | global $system_conf; 77 | 78 | if (empty($system_conf['directory']) || $system_conf['directory'] === '/') { 79 | $url = '/' . $controller; 80 | if ($action != null) { 81 | $url .= '/' . $action; 82 | 83 | if ($data != null) { 84 | $url .= '/' . $data; 85 | } 86 | } 87 | if ($is_json) { 88 | $url .= '.json'; 89 | } 90 | return $url; 91 | } 92 | else { 93 | $url = $system_conf['directory'] . '/index.php?controller=' . $controller; 94 | if ($action != null) { 95 | $url .= '&action=' . $action; 96 | 97 | if ($data != null) { 98 | $url .= '&data=' . $data; 99 | } 100 | } 101 | if ($is_json) { 102 | $url .= '&type=json'; 103 | } 104 | return $url; 105 | } 106 | } -------------------------------------------------------------------------------- /includes/pool_apis/PoolAPI.class.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | abstract class PoolAPI { 8 | 9 | /** 10 | * Holds the user's pool api key. 11 | * 12 | * @var string 13 | */ 14 | protected $api_key = null; 15 | 16 | /** 17 | * Holds the api url for the pool. 18 | * 19 | * @var string 20 | */ 21 | protected $pool_url = null; 22 | 23 | /** 24 | * Creates a new pool api instance. 25 | * 26 | * @param string $pool_url 27 | * The pool url. 28 | * @param string $api_key 29 | * The pool api key from the user. 30 | */ 31 | public function __construct($pool_url, $api_key) { 32 | $this->pool_url = $pool_url; 33 | $this->api_key = $api_key; 34 | } 35 | 36 | /** 37 | * Makes a api request. 38 | * 39 | * @param string $method 40 | * The api command. 41 | * 42 | * @return array 43 | * The api response data. 44 | */ 45 | protected function call($method) { 46 | return $this->request($method); 47 | } 48 | /** 49 | * This will be called when a request is made. 50 | * 51 | * @param string $method 52 | * The api command. 53 | * 54 | * @return array 55 | * The api response data. 56 | */ 57 | abstract protected function request($method); 58 | } -------------------------------------------------------------------------------- /includes/pool_apis/mpos.class.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | require_once 'PoolAPI.class.php'; 8 | 9 | class mpos extends PoolAPI { 10 | 11 | /** 12 | * Magic method to easy handle mpos api call. 13 | * They all just accept one parameter, the api key. 14 | * Only the command method change. 15 | * 16 | * @param string $name 17 | * The method which was called. 18 | * @param mixed $arguments 19 | * The arguments. 20 | * 21 | * @return array 22 | * The api response data. 23 | */ 24 | public function __call($name, $arguments) { 25 | switch ($name) { 26 | case 'getblockcount': 27 | case 'getblocksfound': 28 | case 'getcurrentworkers': 29 | case 'getdashboarddata': 30 | case 'getdifficulty': 31 | case 'getestimatedtime': 32 | case 'gethourlyhashrates': 33 | case 'getnavbardata': 34 | case 'getpoolhashrate': 35 | case 'getpoolsharerate': 36 | case 'getpoolstatus': 37 | case 'gettimesincelastblock': 38 | case 'gettopcontributors': 39 | case 'getuserbalance': 40 | case 'getuserhashrate': 41 | case 'getusersharerate': 42 | case 'getuserstatus': 43 | case 'getuserworkers': 44 | case 'public': 45 | return $this->call($name); 46 | } 47 | throw new Exception('No such method'); 48 | } 49 | 50 | /** 51 | * This will be called when a request is made. 52 | * 53 | * @param string $method 54 | * The api command. 55 | * 56 | * @return array 57 | * The api response data. 58 | */ 59 | protected function request($method) { 60 | $http_client = new HttpClient(); 61 | $result = $http_client->do_get($this->pool_url . '/index.php', array( 62 | 'page' => 'api', 63 | 'action' => $method, 64 | 'api_key' => $this->api_key, 65 | 66 | )); 67 | 68 | return json_decode($result, true); 69 | } 70 | } -------------------------------------------------------------------------------- /includes/validators/AbstractHtmlValidator.class.php: -------------------------------------------------------------------------------- 1 | 7 | * @category Form.Validators 8 | */ 9 | abstract class AbstractHtmlValidator 10 | { 11 | /** 12 | * The value for that element 13 | * 14 | * @var string 15 | */ 16 | private $value = NS; 17 | 18 | /** 19 | * The options for the element 20 | * 21 | * @var mixed 22 | */ 23 | private $options; 24 | 25 | /** 26 | * The error message 27 | * 28 | * @var string 29 | */ 30 | private $error; 31 | 32 | /** 33 | * If set to true then this validator will be always valid 34 | * 35 | * @var boolean 36 | */ 37 | protected $is_always_valid = false; 38 | 39 | /** 40 | * Determines if we have provided manually a error message or not. 41 | * @var boolean 42 | */ 43 | protected $own_error = false; 44 | /** 45 | * constructor 46 | * 47 | * @param string $error 48 | * the error message (optional, default = "") 49 | * @param mixed $options 50 | * the options (optional, default = null) 51 | */ 52 | public function __construct($error = "", $options = null) { 53 | $this->error = &$error; 54 | $this->options = &$options; 55 | $this->own_error = !empty($error); 56 | } 57 | 58 | /** 59 | * Returns whether we have provided a own error message or not. 60 | * 61 | * @return boolean true if we have setup our own error message manually, else false. 62 | */ 63 | public function has_own_error() { 64 | return $this->own_error; 65 | } 66 | /** 67 | * Returns the error message if it's invalid 68 | * 69 | * @return string the error message 70 | */ 71 | public function get_error() { 72 | return $this->error; 73 | } 74 | 75 | /** 76 | * Set the error message 77 | * 78 | * @param string &$val 79 | * The error 80 | */ 81 | public function set_error($val) { 82 | $this->error = &$val; 83 | } 84 | 85 | /** 86 | * Returns the value 87 | * 88 | * @return string the value 89 | */ 90 | public function get_value() { 91 | return $this->value; 92 | } 93 | 94 | /** 95 | * Set the value 96 | * 97 | * @param string &$val 98 | * The value 99 | */ 100 | public function set_value(&$val) { 101 | $this->value = $val; 102 | } 103 | 104 | /** 105 | * Returns the options 106 | * 107 | * @return array the options 108 | */ 109 | public function get_options() { 110 | return $this->options; 111 | } 112 | 113 | /** 114 | * Set the options 115 | * 116 | * @param string &$val 117 | * The options 118 | */ 119 | public function set_options(&$val) { 120 | $this->options = $val; 121 | } 122 | 123 | /** 124 | * Get the validator type 125 | * 126 | * @return string The Validator typ 127 | */ 128 | public function get_type() { 129 | return $this->__toString(); 130 | } 131 | 132 | /** 133 | * Set this validator to always be valid 134 | */ 135 | public function set_valid() { 136 | $this->is_always_valid = true; 137 | } 138 | 139 | /** 140 | * Returns whether the validator should be always valid or not 141 | * 142 | * @return boolean if this validator is always valid return true, else false 143 | */ 144 | public function is_always_valid() { 145 | return $this->is_always_valid; 146 | } 147 | 148 | /** 149 | * Returns whether the validator is valid or not 150 | * 151 | * @return boolean true on valid, else false 152 | */ 153 | abstract function is_valid(); 154 | 155 | /** 156 | * Returns the classname of the current object 157 | * 158 | * @return string 159 | * the classname 160 | */ 161 | public function __tostring() { 162 | return get_class($this); 163 | } 164 | } -------------------------------------------------------------------------------- /includes/validators/FilterValidator.php: -------------------------------------------------------------------------------- 1 | the value to be checked 8 | * options => the filter args, single value and array are possible, use one of FILTER_VALIDATE_* (http://ch2.php.net/manual/de/filter.constants.php) 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class FilterValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the rules 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | $val = $this->get_value(); 27 | $options = $this->get_options(); 28 | if (!is_array($options)) { 29 | $options = array($options); 30 | } 31 | if (empty($val)) { 32 | return true; 33 | } 34 | $args = array(); 35 | foreach ($options AS $filter_arg) { 36 | $args[] = $filter_arg; 37 | } 38 | return call_user_func_array("filter_var", $args); 39 | } 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /includes/validators/FunctionValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be provied as first parameter to the function 8 | * options => the function name 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class FunctionValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the rules 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | $options = $this->get_options(); 27 | if(!is_object($options)) { 28 | list ($obj, $method) = $options; 29 | $call = array($obj, $method.""); 30 | } 31 | else { 32 | $call = $options; 33 | } 34 | return call_user_func_array($call, array($this->get_value(), $this)); 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /includes/validators/IsNumberValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be checked 9 | * options => not used 10 | * 11 | * @copyright Christian Ackermann (c) 2010 - End of life 12 | * @author Christian Ackermann 13 | * @category Form.Validators 14 | */ 15 | class IsNumberValidator extends AbstractHtmlValidator 16 | { 17 | 18 | /** 19 | * Validates the value against the rules 20 | * 21 | * @return boolean if valid true, else false 22 | */ 23 | function is_valid() { 24 | if ($this->is_always_valid()) { 25 | return true; 26 | } 27 | if (is_numeric($this->get_value())) { 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /includes/validators/IssetValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be checked 8 | * options => not used 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class IssetValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the rules 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | return ($this->get_value() !== NS); 27 | } 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /includes/validators/LengthValidator.class.php: -------------------------------------------------------------------------------- 1 | the value to be checked 8 | * options => an array with ('min' => int, 'max' => '0') 9 | * if min is not provided 0 will be used 10 | * if max is not provided the strlen of given value will be used 11 | * 12 | * @copyright Christian Ackermann (c) 2010 - End of life 13 | * @author Christian Ackermann 14 | * @category Form.Validators 15 | */ 16 | class LengthValidator extends AbstractHtmlValidator 17 | { 18 | 19 | /** 20 | * Validates the value against the rules 21 | * 22 | * @return boolean if valid true, else false 23 | */ 24 | function is_valid() { 25 | if ($this->is_always_valid()) { 26 | return true; 27 | } 28 | $options = $this->get_options(); 29 | $val = $this->get_value(); 30 | if (!isset($options['min'])) { 31 | $options['min'] = 0; 32 | } 33 | if (!isset($options['max'])) { 34 | $options['max'] = strlen($val); 35 | } 36 | if (empty($val) || (strlen($val) >= $options['min'] && strlen($val) <= $options['max'])) { 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /includes/validators/RegexpValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be checked 8 | * options => single string which will be used as the pure reqexp, you need to escape it self. 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class RegexpValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the regular expression 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | return (preg_match($this->get_options(), $this->get_value()) > 0); 27 | } 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /includes/validators/RequiredValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be checked 8 | * options => not used 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class RequiredValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the rules 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | $val = $this->get_value(); 27 | if(!is_array($val) && $val."" === "0") { 28 | return true; 29 | } 30 | if ($val === NS) { 31 | return false; 32 | } 33 | return !empty($val); 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /includes/validators/UrlValidator.class.php: -------------------------------------------------------------------------------- 1 | the value which will be checked 8 | * options => not used 9 | * 10 | * @copyright Christian Ackermann (c) 2010 - End of life 11 | * @author Christian Ackermann 12 | * @category Form.Validators 13 | */ 14 | class UrlValidator extends AbstractHtmlValidator 15 | { 16 | 17 | /** 18 | * Validates the value against the rules 19 | * 20 | * @return boolean if valid true, else false 21 | */ 22 | function is_valid() { 23 | if ($this->is_always_valid()) { 24 | return true; 25 | } 26 | 27 | $filter_validator = new FilterValidator($this->get_value(), array(FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)); 28 | return $filter_validator->is_valid(); 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | ' : '::'; 26 | } 27 | if (isset($row['params'])) { 28 | $row['args'] = $row['params']; 29 | } 30 | $stack[] = $row; 31 | } 32 | } 33 | 34 | if ($error !== NULL) { 35 | $errno = $error["type"]; 36 | $errfile = $error["file"]; 37 | $errline = $error["line"]; 38 | $errstr = $error["message"]; 39 | } 40 | global $phpminer_request_is_ajax, $phpminer_error_handler_messages; 41 | 42 | ErrorHandler::cc_error_handler($errno, $errstr, $errfile, $errline, "", true, $stack); 43 | $error = $phpminer_error_handler_messages; 44 | 45 | if (empty($error)) { 46 | return; 47 | } 48 | if ($phpminer_request_is_ajax) { 49 | $code = 560; 50 | $data = sys_get_temp_dir() . '/phpminer_' . uniqid() . '.bugreport'; 51 | $return = array("code" => $code, "desc" => null, "data" => $data); 52 | if (is_array($error)) { 53 | $error = implode("\n", $error); 54 | } 55 | file_put_contents($data, "PHPMiner version: " . implode('.', $system_conf['version']) . "\n" . $error); 56 | echo json_encode($return); 57 | die(); 58 | } 59 | echo implode("
", $error); 60 | die(); 61 | } 62 | register_shutdown_function("fatal_handler"); 63 | 64 | require 'includes/common.php'; 65 | 66 | 67 | if (isset($_GET['controller'])) { 68 | $url = '/' . $_GET['controller']; 69 | if (isset($_GET['action'])) { 70 | $url .= '/' . $_GET['action']; 71 | } 72 | if (isset($_GET['data'])) { 73 | $url .= '/' . $_GET['data']; 74 | } 75 | if (isset($_GET['type']) && $_GET['type'] === 'json') { 76 | $url .= '.json'; 77 | } 78 | $_SERVER['REQUEST_URI'] = urlencode($url); 79 | } 80 | 81 | $request_uri = urldecode($_SERVER['REQUEST_URI']); 82 | if ($system_conf['directory'] !== '/') { 83 | $request_uri = str_replace($system_conf['directory'], '', $request_uri); 84 | } 85 | 86 | // Get the request current path. 87 | $url_decoded_request_array = parse_url($request_uri); 88 | 89 | // Get request type. .json is handled as json, anything else as html. 90 | if (preg_match("/\.json$/", $url_decoded_request_array['path'])) { 91 | $phpminer_request_is_ajax = true; 92 | 93 | // We only need ajax within ajax requests. 94 | include './includes/AjaxModul.php'; 95 | 96 | // Remove the .json ending. 97 | $url_decoded_request_array['path'] = preg_replace("/\.json$/", "", $url_decoded_request_array['path']); 98 | 99 | // Set type to json / ajax. 100 | $set_request_type = 'json'; 101 | } else { 102 | // Set type to normal html. 103 | $set_request_type = 'html'; 104 | } 105 | 106 | // Get all params as an array. 107 | $params = explode("/", $url_decoded_request_array['path']); 108 | 109 | // Remove special chars. 110 | foreach ($params AS &$param) { 111 | $param = preg_replace("/\W/", "", $param); 112 | } 113 | // Get the controller. 114 | array_shift($params); 115 | if (empty($params[0])) { 116 | $params = array('main'); 117 | } 118 | 119 | // Check if controller exist 120 | if (!file_exists('controllers/' . $params[0] . '.php')) { 121 | $controller = new Controller(); 122 | $controller->no_such_controller(); 123 | unset($controller); 124 | exit(); 125 | } 126 | 127 | // Include the controller. 128 | include './controllers/' . $params[0] . '.php'; 129 | 130 | // Create controller instance. 131 | $controller_name = strtolower($params[0]); 132 | $controller = new $controller_name(); 133 | 134 | try { 135 | // Set request type. 136 | $controller->set_request_type($set_request_type); 137 | 138 | // Get the controller action. 139 | array_shift($params); 140 | if (!isset($params[0])) { 141 | $params[0] = 'init'; 142 | } 143 | $method = strtolower($params[0]); 144 | array_shift($params); 145 | 146 | // Check if controller action exists. 147 | if (!method_exists($controller, $method)) { 148 | $controller->no_such_method(); 149 | } else { 150 | 151 | // Provide the view the controller and action name. 152 | $controller->set_controller_name($controller_name); 153 | $controller->set_action_name($method); 154 | 155 | // Try to init the controller. This will also create the api class and check for needec config files. 156 | $controller->setup_controller(); 157 | 158 | // Call the controller action with optional additional params. 159 | call_user_func_array(array($controller, $method), $params); 160 | } 161 | } catch (Exception $e) { 162 | if ($set_request_type === 'html') { 163 | 164 | if ($e instanceof AccessException) { 165 | $controller->fatal_error($e->getMessage(), true); 166 | } 167 | 168 | $controller->add_message($e->getMessage(), ($e instanceof InfoException) ? Controller::MESSAGE_TYPE_INFO : Controller::MESSAGE_TYPE_ERROR); 169 | } else { 170 | AjaxModul::return_code(AjaxModul::ERROR_DEFAULT, null, true, $e->getMessage()); 171 | } 172 | } 173 | // Display the view. 174 | unset($controller); 175 | -------------------------------------------------------------------------------- /linux_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ "$(id -u)" != "0" ]; then 3 | echo "This script must be run as root" 1>&2 4 | exit 1 5 | fi 6 | 7 | # Instal required software. 8 | echo "Install required software." 9 | apt-get install -y apache2 libapache2-mod-php5 php5-cli php5-mcrypt php5-mhash curl php5-curl 10 | apt-get install -y php5-json 11 | 12 | echo "Mysql server will now be installed, if it is not already, you will be asked for the password for the 'root' user. Choose a good one. After installation you will be asked for this again. This will make sure this install script can create the required user and database for phpminer." 13 | apt-get install -y mysql-server php5-mysql 14 | 15 | echo "Please enter the mysql password for the user root:" 16 | read MYSQL_ROOT 17 | if [ -n "$MYSQL_ROOT" ]; then 18 | echo "Ok." 19 | else 20 | echo "You really have to provide the password. One more chance." 21 | 22 | echo "Please enter the mysql password for the user root:" 23 | read MYSQL_ROOT 24 | if [ -n "$MYSQL_ROOT" ]; then 25 | echo "Ok." 26 | else 27 | echo "Password can not be empty." 28 | exit 1; 29 | fi 30 | fi 31 | 32 | PW_GOOD=`echo "SELECT 1" | mysql -u root --password=$MYSQL_ROOT 2>&1` 33 | 34 | echo $PW_GOOD 35 | if echo "$PW_GOOD" | grep -q ".*Access denied.*" 36 | then 37 | echo $PW_GOOD 38 | exit 1; 39 | fi 40 | 41 | echo "Please enter the database username for phpminer, this user will be created afterwards and must not exists (Default=phpminer):" 42 | read DB_USER 43 | if [ -n "$DB_USER" ]; then 44 | echo "Using database user: $DB_USER" 45 | else 46 | DB_USER="phpminer" 47 | echo "Using database user: $DB_USER" 48 | fi 49 | 50 | echo "Please enter the password for phpminer user which you provided above (REQUIRED):" 51 | read DB_PASS 52 | if [ -n "$DB_PASS" ]; then 53 | echo "Using database pass: ****** (not shown)" 54 | else 55 | echo "Database pass is required" 56 | exit 1; 57 | fi 58 | 59 | echo "Please enter the database name for phpminer, this database will be created afterwards and the database user will be granted with all permissions. (Default=phpminer):" 60 | read DB_NAME 61 | if [ -n "$DB_NAME" ]; then 62 | echo "Using database: $DB_NAME" 63 | else 64 | DB_NAME="phpminer" 65 | echo "Using database: $DB_NAME" 66 | fi 67 | 68 | echo "Creating database and user" 69 | echo "CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';GRANT USAGE ON *.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;CREATE DATABASE IF NOT EXISTS \`$DB_NAME\`;GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'localhost';" | mysql -u root --password=$MYSQL_ROOT 70 | 71 | # Setup required variables. 72 | echo "Setup required variables." 73 | PHPMINER_PATH=`readlink -f $0` 74 | PHPMINER_PATH=`dirname $PHPMINER_PATH` 75 | 76 | HOSTNAME=`hostname` 77 | DOMAIN="phpminer.$HOSTNAME" 78 | APACHE_USER=`cat /etc/apache2/envvars | grep APACHE_RUN_USER | awk -F= '{print $2}'` 79 | APACHE_GROUP=`cat /etc/apache2/envvars | grep APACHE_RUN_GROUP | awk -F= '{print $2}'` 80 | APACHE_PORT=`cat /etc/apache2/ports.conf | grep NameVirtualHost | grep -v "add NameVirtualHost" | awk -F : '{print $2}'` 81 | 82 | PHPMINER_DB_CFG_PATH="$PHPMINER_PATH/config/config2.php" 83 | 84 | # Create config.php 85 | echo " 'mysql', 88 | 'server' => 'localhost', 89 | 'database' => '$DB_NAME', 90 | 'username' => '$DB_USER', 91 | 'password' => '$DB_PASS', 92 | ); 93 | " > $PHPMINER_DB_CFG_PATH; 94 | 95 | echo "chown $APACHE_USER:$APACHE_GROUP $PHPMINER_DB_CFG_PATH" | sh 96 | 97 | # Install cronjob 98 | echo "Install cronjob." 99 | echo "# /etc/cron.d/phpminer: crontab fragment for phpminer" > /etc/cron.d/phpminer 100 | echo "# This will run the cronjob script for phpminer to send notifications and other periodic tasks." >> /etc/cron.d/phpminer 101 | echo "* * * * * $APACHE_USER php -f $PHPMINER_PATH/cron.php" >> /etc/cron.d/phpminer 102 | 103 | # Install apache vhost 104 | echo "Install apache2 vhost." 105 | echo " 106 | ServerAdmin webmaster@$DOMAIN 107 | ServerName $DOMAIN 108 | 109 | DocumentRoot $PHPMINER_PATH 110 | 111 | Options FollowSymLinks 112 | AllowOverride None 113 | 114 | 115 | Options Indexes FollowSymLinks MultiViews 116 | AllowOverride All 117 | 118 | 119 | ErrorLog \${APACHE_LOG_DIR}/error.log 120 | 121 | # Possible values include: debug, info, notice, warn, error, crit, 122 | # alert, emerg. 123 | LogLevel warn 124 | 125 | CustomLog \${APACHE_LOG_DIR}/access.log combined 126 | " > /etc/apache2/sites-available/phpminer 127 | a2ensite phpminer 128 | a2enmod rewrite 129 | service apache2 restart 130 | 131 | echo "chown $APACHE_USER:$APACHE_GROUP $PHPMINER_PATH/config" | sh 132 | sed -i "s/localhost/localhost $DOMAIN/g" /etc/hosts 133 | 134 | 135 | echo "PHPMiner installation finshed." 136 | echo "" 137 | echo "Now you have to install phpminer_rpcclient on each rig you want to control." 138 | echo "" 139 | echo "If you are running phpminer webinterface from a different machine than your normal pc" 140 | echo "then add the network ip-address (the one you got from DHCP or which you manually configurated) from the phpminer webinterface server to your hostfile" 141 | echo "" 142 | echo "if phpminer webinterface runs on your normal pc then add 127.0.0.1 to your host file" 143 | echo "" 144 | echo "The domain for the hostfile is $DOMAIN" 145 | echo "" 146 | echo "example entry for hostfile is '127.0.0.1 $DOMAIN'" 147 | echo "" 148 | echo "After installing all phpminer_rpclient's you can open phpminer within a browser at http://$DOMAIN:$APACHE_PORT" -------------------------------------------------------------------------------- /phpminer_rpcclient/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule .* - [R=404] -------------------------------------------------------------------------------- /phpminer_rpcclient/config.dist.php: -------------------------------------------------------------------------------- 1 | array( 22 | 23 | // The ip to the miner api (which is configured at miner.conf as api-allow (This needs W: prefix for priviledge access) 24 | 'ip' => '127.0.0.1', 25 | 26 | // The miner api port. 27 | 'port' => 4028, 28 | 29 | // Miner, can be cgminer or sgminer 30 | 'miner' => 'cgminer', 31 | 32 | // Miner binary, this can be left empty if the binary is the same as the miner. For example miner = cgminer, miner_binary = cgminer or on windows cgminer.exe 33 | 'miner_binary' => '', 34 | 35 | // The path + file where the cgminer.conf is. 36 | // Please make sure that the user which run's this script has the permission to edit this file. 37 | 'cgminer_config_path' => '/opt/cgminer/cgminer.conf', 38 | 39 | // The path where the cgminer executable is. 40 | // Please make sure that the user which run's this script has the permission to start cgminer. 41 | 'cgminer_path' => '/opt/miners/cgminer', 42 | 43 | // Path to AMD SDK if available (Normally this is only needed within Linux and can be ommited also on linux) 44 | 'amd_sdk' => '', 45 | ), 46 | ); 47 | 48 | // Here you can define custom start,stop and reboot commands. 49 | // This is optional, if you let it empty it will call the following command: 50 | // Stop: 51 | // Linux: 52 | // kill -9 {process_id} 53 | // Windows 54 | // taskkill /F /PID {process_id} 55 | // 56 | // Reboot: 57 | // Linux: 58 | // shutdown -r now (or if not user root it tries sudo shutdown -r now) 59 | // Windows 60 | // shutdown /r /t 1 61 | // 62 | // Start: 63 | // Linux: 64 | // #!/bin/bash 65 | // export GPU_MAX_ALLOC_PERCENT=100; 66 | // export GPU_USE_SYNC_OBJECTS=1; 67 | // export DISPLAY=:0; 68 | // export LD_LIBRARY_PATH={amd_sdk}; # Only if configurated. 69 | // cd {cgminer_path}; 70 | // screen -d -m -S {miner} ./{miner_binary} -c {cgminer_config_path}; # If {miner_binary} is empty it will use {miner} 71 | // Windows 72 | // setx GPU_MAX_ALLOC_PERCENT 100 73 | // setx GPU_USE_SYNC_OBJECTS 1 74 | // cd {cgminer_path} 75 | // {miner_binary} -c {cgminer_config_path}; # If {miner_binary} is empty it will use {miner}.exe 76 | // 77 | // You can include the process id with %pid% within the stop request. 78 | // 79 | // For linux users: 80 | // You can provide any command which is available under bash 81 | // For windows users: 82 | // You can provide any command which is available within a .bat file. 83 | // 84 | // Example 1: Interupt instead of kill on linux machine 85 | // 86 | // $config['commands'] = array( 87 | // 'start' => null, 88 | // 'stop' => 'kill -15 %pid%', 89 | // 'reboot' => null, 90 | // ); 91 | // 92 | // Example 2: Use smos/bamt mine start / mine stop 93 | // 94 | // $config['commands'] = array( 95 | // 'start' => 'mine start', 96 | // 'stop' => 'mine stop', 97 | // 'reboot' => null, 98 | // ); 99 | $config['commands'] = array( 100 | 'start' => null, 101 | 'stop' => null, 102 | 'reboot' => null, 103 | ); 104 | 105 | // Here you can define custom commands which you can execute from the webinterface on this rig. 106 | $config['custom_commands'] = array( 107 | 'get_date' => array( 108 | 'title' => 'Get date', 109 | 'command' => 'date', 110 | 'confirmation_required' => false, 111 | 'has_response' => true, 112 | ) 113 | ); 114 | 115 | /* * ********* CONFIG END ************* */ 116 | -------------------------------------------------------------------------------- /phpminer_rpcclient/config.php: -------------------------------------------------------------------------------- 1 | array( 37 | 'title' => 'Get date', 38 | 'command' => 'date', 39 | 'confirmation_required' => false, 40 | 'has_response' => true, 41 | ) 42 | ); 43 | /* * ********* CONFIG END ************* */ 44 | -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/APIException.class.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | class APIException extends Exception { 7 | const CODE_SOCKET_CREATE_ERROR = 501; 8 | const CODE_SOCKET_CONNECT_ERROR = 502; 9 | const CODE_SOCKET_NOT_CONNECTED = 503; 10 | const CODE_INVALID_PARAMETER = 504; 11 | } -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/APIRequestException.class.php: -------------------------------------------------------------------------------- 1 | 5 | */ 6 | class APIRequestException extends Exception { 7 | } -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/Config.class.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | /** 9 | * Represents the config of php cgminer. 10 | */ 11 | class Config { 12 | 13 | /** 14 | * Holds the config values. 15 | * 16 | * @var array 17 | */ 18 | protected $config = array(); 19 | 20 | /** 21 | * The path to the config file. 22 | * 23 | * @var string 24 | */ 25 | private $config_path = ""; 26 | 27 | /** 28 | * Creates a new config instance and load the config. 29 | * 30 | * @param string $config_path 31 | * The path to the config file. 32 | */ 33 | public function __construct($config_path) { 34 | $this->config_path = $config_path; 35 | $this->reload(); 36 | } 37 | 38 | /** 39 | * Reloads/Loads the config. 40 | * 41 | * @throws PHPMinerException 42 | */ 43 | public function reload() { 44 | // Check if config file exists, if not try to create it. 45 | if (!file_exists($this->config_path)) { 46 | // Config directory is not writeable. 47 | if (!is_writable(dirname($this->config_path))) { 48 | throw new Exception('Config file directoy is not writeable: ' . dirname($this->config_path)); 49 | } 50 | touch($this->config_path); 51 | } 52 | 53 | // Config file not readable.... 54 | if (!is_readable($this->config_path)) { 55 | throw new Exception('Config file not found: ' . $this->config_path); 56 | } 57 | 58 | // Config file not writeable... 59 | if (!is_writable($this->config_path)) { 60 | throw new Exception('Config not writeable: ' . $this->config_path); 61 | } 62 | 63 | // Get the data of the config file. 64 | $config_data = file_get_contents($this->config_path); 65 | 66 | // If the config file is empty, nothing is bad, just not configured yet. 67 | if (empty($config_data)) { 68 | $this->config = array(); 69 | return; 70 | } 71 | 72 | // Try to decode the existing data from json. 73 | $this->config = json_decode($config_data, true); 74 | 75 | // Check for invalid json. 76 | if ($this->config === null) { 77 | throw new Exception('Config file can not be parsed, no valid json found.'); 78 | } 79 | } 80 | 81 | /** 82 | * Returns wether the config file is empty or not. 83 | * 84 | * @return boolean 85 | * True if config is empty, else false. 86 | */ 87 | public function is_empty() { 88 | return empty($this->config); 89 | } 90 | 91 | /** 92 | * Retrieves config the value. 93 | * 94 | * @param string $name 95 | * The config key. 96 | * 97 | * @return null|mixed 98 | * Null if config key does not exist, else the value. 99 | */ 100 | public function __get($name) { 101 | return $this->get_value($name); 102 | } 103 | 104 | /** 105 | * Retrieves config the value. 106 | * 107 | * @param string $name 108 | * The config key. 109 | * 110 | * @return null|mixed 111 | * Null if config key does not exist, else the value. 112 | */ 113 | public function get_value($name) { 114 | if (!isset($this->config[$name])) { 115 | return null; 116 | } 117 | return $this->config[$name]; 118 | } 119 | 120 | /** 121 | * Returns the hole config. 122 | * 123 | * @return array 124 | * The config array.- 125 | */ 126 | public function get_config() { 127 | return $this->config; 128 | } 129 | 130 | /** 131 | * Set the config key and write the new config file directly. 132 | * 133 | * @param string $name 134 | * The config key to set. 135 | * @param mixed $value 136 | * The value. 137 | */ 138 | public function __set($name, $value) { 139 | $this->set_value($name, $value); 140 | } 141 | 142 | /** 143 | * Set the config key and write the new config file directly. 144 | * 145 | * @param string $name 146 | * The config key to set. 147 | * @param mixed $value 148 | * The value. 149 | */ 150 | public function set_value($name, $value) { 151 | $this->config[$name] = $value; 152 | $this->save(); 153 | } 154 | 155 | /** 156 | * Returns wether the config key exists or not. 157 | * 158 | * @param string $name 159 | * The config key. 160 | * 161 | * @return boolean 162 | * True if config key is set, else false. 163 | */ 164 | public function __isset($name) { 165 | return isset($this->config[$name]); 166 | } 167 | 168 | /** 169 | * Returns wether the config file is writeable or not. 170 | * 171 | * @return boolean 172 | * True if path is writeable, else false. 173 | */ 174 | public function is_writeable() { 175 | return is_writable($this->config_path); 176 | } 177 | 178 | /** 179 | * Write the config to the file. 180 | * 181 | * @return boolean|int 182 | * Returns false if the file could not be writte, else the bytes which were written. 183 | */ 184 | protected function save() { 185 | return file_put_contents($this->config_path, str_replace('\\/', '/', $this->prettyPrint(json_encode($this->config)))); 186 | } 187 | 188 | /** 189 | * Format a json string into pretty looking. 190 | * 191 | * @param string $json 192 | * The json which needs to be formated. 193 | * 194 | * @return string 195 | * The pretty printed json. 196 | */ 197 | private function prettyPrint($json) { 198 | $result = ''; 199 | $level = 0; 200 | $prev_char = ''; 201 | $in_quotes = false; 202 | $ends_line_level = NULL; 203 | $json_length = strlen($json); 204 | 205 | for ($i = 0; $i < $json_length; $i++) { 206 | $char = $json[$i]; 207 | $new_line_level = NULL; 208 | $post = ""; 209 | if ($ends_line_level !== NULL) { 210 | $new_line_level = $ends_line_level; 211 | $ends_line_level = NULL; 212 | } 213 | if ($char === '"' && $prev_char != '\\') { 214 | $in_quotes = !$in_quotes; 215 | } else if (!$in_quotes) { 216 | switch ($char) { 217 | case '}': case ']': 218 | $level--; 219 | $ends_line_level = NULL; 220 | $new_line_level = $level; 221 | break; 222 | 223 | case '{': case '[': 224 | $level++; 225 | case ',': 226 | $ends_line_level = $level; 227 | break; 228 | 229 | case ':': 230 | $post = " "; 231 | break; 232 | 233 | case " ": case "\t": case "\n": case "\r": 234 | $char = ""; 235 | $ends_line_level = $new_line_level; 236 | $new_line_level = NULL; 237 | break; 238 | } 239 | } 240 | if ($new_line_level !== NULL) { 241 | $result .= "\n" . str_repeat("\t", $new_line_level); 242 | } 243 | $result .= $char . $post; 244 | $prev_char = $char; 245 | } 246 | 247 | return $result; 248 | } 249 | 250 | } -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/RPCClientConnection.class.php: -------------------------------------------------------------------------------- 1 | id = uniqid(); 30 | $this->socket = $client_socket; 31 | } 32 | 33 | /** 34 | * Returns the uniq client id. 35 | * 36 | * @return string 37 | * The unique id. 38 | */ 39 | public function getId() { 40 | return $this->id; 41 | } 42 | 43 | /** 44 | * Process the connection / API Command. 45 | * 46 | * @param array $config 47 | * The config of this rpc client. 48 | */ 49 | public function process_connection($config) { 50 | 51 | // Read the data from phpminer. 52 | $data = $this->read_buffer(); 53 | 54 | // Check if client really sent some data. 55 | $bytes = strlen($data); 56 | if ($bytes === 0 || $data === false) { 57 | return $this->response('No data', true); 58 | } 59 | 60 | // Parse the json data. PHPMiner always send json. 61 | $rpc_data = json_decode($data, true); 62 | 63 | // Verify that incoming data was json. 64 | if (empty($rpc_data)) { 65 | return $this->response('No data', true); 66 | } 67 | 68 | // Verify rpc key is included and match with the configurated one. 69 | if (!isset($rpc_data) || !isset($rpc_data['rpc_key']) || $rpc_data['rpc_key'] !== $config['rpc_key']) { 70 | log_console('Incoming data request'); 71 | return $this->response('RPC Key not found or invalid.', true); 72 | } 73 | 74 | // Verify required parameter: command 75 | if (!isset($rpc_data['command'])) { 76 | log_console('Incoming data request'); 77 | return $this->response('No command specified', true); 78 | } 79 | 80 | //Only log incoming command when it is not a ping. 81 | if ($rpc_data['command'] !== 'ping') { 82 | log_console('Incoming data request: ' . $rpc_data['command']); 83 | } 84 | 85 | $client_api = null; 86 | 87 | $config['rpc_config']->reload(); 88 | $current_miner = $config['rpc_config']->current_miner; 89 | if (!isset($config['miners'][$current_miner])) { 90 | $current_miner_config = reset($config['miners']); 91 | } 92 | else { 93 | $current_miner_config = $config['miners'][$current_miner]; 94 | } 95 | 96 | $config['miner_api_ip'] = $current_miner_config['ip']; 97 | $config['miner_api_port'] = $current_miner_config['port']; 98 | $config['miner'] = $current_miner_config['miner']; 99 | $config['miner_binary'] = $current_miner_config['miner_binary']; 100 | $config['cgminer_config_path'] = $current_miner_config['cgminer_config_path']; 101 | $config['cgminer_path'] = $current_miner_config['cgminer_path']; 102 | $config['amd_sdk'] = $current_miner_config['amd_sdk']; 103 | 104 | 105 | // Check which api is required. 106 | if (!isset($rpc_data['api_proxy']) || empty($rpc_data['api_proxy'])) { 107 | // Get the rpc api. 108 | $client_api = new RPCClientApi($config); 109 | } 110 | else { 111 | // Get miner api 112 | $client_api = new CGMinerAPI($config['miner_api_ip'], $config['miner_api_port']); 113 | } 114 | 115 | // Get the method which will be called. 116 | $method = $rpc_data['command']; 117 | 118 | // Verify api command exists. 119 | if (method_exists($client_api, $method)) { 120 | 121 | // Try to call the api command. 122 | try { 123 | $result = null; 124 | 125 | 126 | if (!empty($rpc_data['data']) || (!is_array($rpc_data['data']) && $rpc_data['data'] !== "0")) { 127 | 128 | if (!isset($rpc_data['api_proxy']) || empty($rpc_data['api_proxy'])) { 129 | $result = call_user_method($method, $client_api, $rpc_data['data']); 130 | } 131 | else { 132 | $call_args = $rpc_data['data']; 133 | if (empty($call_args) && !is_array($call_args) && $call_args . "" !== "0") { 134 | $call_args = array(); 135 | } 136 | else if (!is_array($call_args)) { 137 | $call_args = array($call_args); 138 | } 139 | $result = call_user_method_array($method, $client_api, $call_args); 140 | } 141 | } 142 | else { 143 | $result = call_user_method($method, $client_api); 144 | } 145 | 146 | // When result is empty but not an empty string, replace it with default 'ok' 147 | if (empty($result) && $result !== '') { 148 | $result = 'ok'; 149 | } 150 | 151 | // Sent success response. 152 | return $this->response($result, false); 153 | } catch (Exception $ex) { 154 | 155 | // Send error response. 156 | return $this->response($ex->getMessage(), true); 157 | } 158 | } 159 | } 160 | 161 | /** 162 | * Disconnects the client. 163 | */ 164 | public function disconnect() { 165 | // Shutdown socket. 166 | @socket_shutdown($this->socket, 2); 167 | @socket_close($this->socket); 168 | } 169 | 170 | /** 171 | * Read data from phpminer ressource. 172 | * 173 | * @return boolean|string 174 | * Returns the read string, boolean false on error. 175 | */ 176 | private function read_buffer() { 177 | 178 | $buffer = ''; 179 | $buffsize = 8192; 180 | $buf = null; 181 | 182 | $res = socket_recv($this->socket, $buf, $buffsize,0); 183 | if($res == null) { 184 | log_console("Couldn't Receive Data."); 185 | return false; 186 | } 187 | else { 188 | $buffer = $buf; 189 | } 190 | while ($res >= $buffsize) { 191 | $buffer .= $buf; 192 | $buf = null; 193 | $res = socket_recv($this->socket, $buf, $buffsize, 0); 194 | } 195 | 196 | return $buffer; 197 | } 198 | 199 | /** 200 | * Writes the given data to the phpminer resource. 201 | * 202 | * @param string $string 203 | * The data to write. 204 | * 205 | * @return boolean|int 206 | * Returns the written bytes as an integer, boolean false on error. 207 | */ 208 | private function write_buffer($string) { 209 | 210 | $tmpBuf = $string; 211 | $iBufLen = strlen($tmpBuf); 212 | $res = socket_write($this->socket, $tmpBuf, $iBufLen); 213 | 214 | if ($res === false) { 215 | log_console("Couldn't send Data."); 216 | return false; 217 | } 218 | else if ($res < $iBufLen) { 219 | $tmpBuf = substr($tmpBuf, $res); 220 | $this->write_buffer($tmpBuf); 221 | } 222 | 223 | return $res; 224 | } 225 | 226 | /** 227 | * Send a response to a phpminer connection. 228 | * 229 | * @param string $msg 230 | * The message which will send to phpminer. 231 | * @param boolean $error 232 | * When set to true, the response had errors. (Optional, default = false) 233 | */ 234 | private function response($msg = 'ok', $error = false) { 235 | // Build response. 236 | $buffer = json_encode(array( 237 | 'msg' => $msg, 238 | 'error' => $error, 239 | )); 240 | // Send to client. 241 | $this->write_buffer($buffer); 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/RPCClientServer.class.php: -------------------------------------------------------------------------------- 1 | config = $config; 43 | } 44 | 45 | /** 46 | * Start server. 47 | */ 48 | public function start() { 49 | log_console('Starting RPC Server at ' . $this->config['ip'] . ' on port ' . $this->config['port']); 50 | $errno = 0; 51 | $err = ""; 52 | $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); 53 | 54 | // Non block socket type 55 | socket_set_option($this->master, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 10, "usec" => 0)); 56 | socket_set_option($this->master, SOL_SOCKET, SO_LINGER, array('l_onoff' => 1, 'l_linger' => 0)); 57 | socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1); 58 | 59 | @socket_bind($this->master, $this->config['ip'], $this->config['port']); 60 | while (socket_last_error() === 98) { 61 | log_console("Socket terminated but address already in use, wait 2 sec's and try again."); 62 | sleep(2); 63 | @socket_bind($this->master, $this->config['ip'], $this->config['port']); 64 | } 65 | 66 | $listen = socket_listen($this->master); 67 | if($listen === FALSE) { 68 | unlock(); 69 | log_console("Can't listen on socket."); 70 | exit; 71 | } 72 | 73 | 74 | $this->listen(); 75 | } 76 | 77 | /** 78 | * Closes main socket 79 | */ 80 | public function close() { 81 | if ($this->client !== null) { 82 | $this->client->disconnect(); 83 | $this->client = null; 84 | } 85 | @socket_shutdown($this->master, 2); 86 | @socket_close($this->master); 87 | $this->stop_request = true; 88 | } 89 | 90 | /** 91 | * Listen for incoming connections. 92 | */ 93 | public function listen() { 94 | while (!$this->stop_request) { 95 | 96 | // Check for changed sockets. 97 | $socket = @socket_accept($this->master); 98 | if($socket != null) { 99 | 100 | // Get the client which send the data. 101 | $this->client =new RPCClientConnection($socket); 102 | 103 | // Proccess client. 104 | if ($this->client) { 105 | $this->client->process_connection($this->config); 106 | 107 | // Disconnection client. 108 | $this->client->disconnect(); 109 | $this->client = null; 110 | } 111 | } 112 | else { 113 | #log_console('Socket error: ' . socket_strerror(socket_last_error($this->master))); 114 | continue; 115 | } 116 | 117 | } 118 | @socket_shutdown($this->master, 2); 119 | @socket_close($this->master); 120 | } 121 | } -------------------------------------------------------------------------------- /phpminer_rpcclient/includes/common.php: -------------------------------------------------------------------------------- 1 | $v) { 18 | if (!isset($config[$k])) { 19 | $config[$k] = $v; 20 | } 21 | } 22 | 23 | define('SITEPATH', dirname(__FILE__)); 24 | 25 | include dirname(__FILE__) . '/includes/common.php'; 26 | include dirname(__FILE__) . '/includes/CGMinerAPI.class.php'; 27 | include dirname(__FILE__) . '/includes/RPCClientApi.class.php'; 28 | include dirname(__FILE__) . '/includes/RPCClientConnection.class.php'; 29 | include dirname(__FILE__) . '/includes/RPCClientServer.class.php'; 30 | include dirname(__FILE__) . '/includes/Config.class.php'; 31 | 32 | $is_windows = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'); 33 | 34 | // Generate miner array when having old single miner version. 35 | if (!isset($config['miners'])) { 36 | $config['miners'] = array(); 37 | $config['miners'][$config['miner']] = array( 38 | 'ip' => $config['miner_api_ip'], 39 | 'port' => $config['miner_api_port'], 40 | 'miner' => $config['miner'], 41 | 'miner_binary' => $config['miner_binary'], 42 | 'cgminer_config_path' => $config['cgminer_config_path'], 43 | 'cgminer_path' => $config['cgminer_path'], 44 | 'amd_sdk' => $config['amd_sdk'], 45 | ); 46 | } 47 | 48 | foreach ($config['miners'] AS $k => $miner_entry) { 49 | // When no miner is configurated, fallback to cgminer. 50 | if (empty($miner_entry['miner'])) { 51 | $miner_entry['miner'] = 'cgminer'; 52 | } 53 | 54 | // When no miner binaray is configurated or invalid one, fallback to .exe on windows 55 | if (empty($miner_entry['miner_binary'])) { 56 | $miner_entry['miner_binary'] = $miner_entry['miner']; 57 | if ($is_windows) { 58 | $miner_entry['miner_binary'] .= '.exe'; 59 | } 60 | } 61 | $config['miners'][$k] = $miner_entry; 62 | } 63 | 64 | $rpc_config = new Config(SITEPATH . '/config.json'); 65 | $current_miner = $rpc_config->current_miner; 66 | if (empty($current_miner)) { 67 | reset($config['miners']); 68 | $current_miner = key($config['miners']); 69 | } 70 | $rpc_config->current_miner = $current_miner; 71 | 72 | $config['rpc_config'] = $rpc_config; 73 | 74 | // Make sure array index keys exists. 75 | if (!isset($config['commands'])) { 76 | $config['commands'] = array(); 77 | } 78 | 79 | if (!isset($config['commands']['start'])) { 80 | $config['commands']['start'] = null; 81 | } 82 | 83 | if (!isset($config['commands']['stop'])) { 84 | $config['commands']['stop'] = null; 85 | } 86 | 87 | if (!isset($config['commands']['reboot'])) { 88 | $config['commands']['reboot'] = null; 89 | } 90 | 91 | // Create server, we need this here in order to close all sockets when pressing ctrl+c 92 | $rpc_server = new RPCClientServer($config); 93 | 94 | // If on linux, we can create a little helper to prevent double starts. 95 | // We also register the handler on pressing ctrl+c / ctrl+d to make sure the lock file will be removed. 96 | if (function_exists('pcntl_signal')) { 97 | $check_file = '/tmp/phpminer_rpcclient.pid'; 98 | function sig_handler($signo) { 99 | global $check_file; 100 | switch ($signo) { 101 | case SIGTERM: 102 | case SIGINT: 103 | unlock(); 104 | exit; 105 | } 106 | } 107 | 108 | pcntl_signal(SIGTERM, "sig_handler"); 109 | pcntl_signal(SIGINT, "sig_handler"); 110 | 111 | if (file_exists($check_file)) { 112 | exit; 113 | } 114 | 115 | file_put_contents($check_file, getmypid()); 116 | 117 | function unlock() { 118 | global $check_file, $rpc_server; 119 | $rpc_server->close(); 120 | @unlink($check_file); 121 | } 122 | } 123 | else { 124 | function unlock() { 125 | global $rpc_server; 126 | $rpc_server->close(); 127 | } 128 | } 129 | 130 | // Start server. 131 | $rpc_server->start(); 132 | 133 | // Just make sure that tmp pid file is removed after script end. (Linux only) 134 | unlock(); 135 | -------------------------------------------------------------------------------- /phpminer_rpcclient/phpminer_rpcclient: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: phpminer_rpcclient 5 | # Required-Start: $local_fs $remote_fs $network 6 | # Required-Stop: $local_fs $remote_fs $network 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: Start PHPMiner RPC CLient 10 | # Description: Start PHPMiner RPC Client service. 11 | ### END INIT INFO 12 | if [ "$(id -u)" != "0" ]; then 13 | echo "This script must be run as root" 1>&2 14 | exit 1 15 | fi 16 | 17 | [ -f /etc/default/rcS ] && . /etc/default/rcS 18 | PATH=/bin:/usr/bin:/sbin:/usr/sbin 19 | 20 | # for example this should look like PROGRAM=/var/www/php_cgminer/phpminer_rpcclient/index.php 21 | PROGRAM={/PATH/TO/phpminer_rpcclient}/index.php 22 | 23 | # for example this should look like USER=myriguser 24 | USER={USER} 25 | 26 | case "$1" in 27 | start) 28 | screen -d -m -S phpminer_rpcclient su $USER -c "php -f $PROGRAM" 29 | ;; 30 | stop) 31 | if [ -f /tmp/phpminer_rpcclient.pid ]; then 32 | cat /tmp/phpminer_rpcclient.pid | awk '{ print "kill "$1; }' | sh 33 | fi 34 | ;; 35 | force-reload|restart) 36 | $0 stop 37 | $0 start 38 | ;; 39 | status) 40 | if [ -f /tmp/phpminer_rpcclient.pid ]; then 41 | echo "PHPMiner RPC Client is running" 42 | else 43 | echo "PHPMiner RPC Client is not running" 44 | fi 45 | exit 0 46 | ;; 47 | *) 48 | echo "Usage: /etc/init.d/phpminer_rpcclient {start|stop|restart|status}" 49 | exit 1 50 | esac 51 | 52 | exit 0 -------------------------------------------------------------------------------- /phpminer_rpcclient/rpcclient_cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -f /tmp/phpminer_rpcclient.pid ]; then 4 | RUNNING=`cat /tmp/phpminer_rpcclient.pid | awk '{print "ps -p "$1" -f"}' | sh | grep "phpminer"` 5 | if [ -z "$RUNNING" ]; then 6 | echo "PHPMiner RPC-Client not running. Restarting" 7 | PHPSCREEN=`screen -list | grep "phpminer" | awk '{print $1}' | awk -F . '{print $1}'` 8 | if [ -z "$PHPSCREEN" ]; then 9 | echo "No screen found, good" 10 | else 11 | echo "Screen still running, killing it" 12 | kill -9 $PHPSCREEN 13 | fi 14 | rm /tmp/phpminer_rpcclient.pid 15 | /etc/init.d/phpminer_rpcclient start 16 | fi 17 | else 18 | echo "RPCMiner didn't started yet, start it" 19 | /etc/init.d/phpminer_rpcclient start 20 | fi 21 | -------------------------------------------------------------------------------- /phpminer_rpcclient/test_api_commands.php: -------------------------------------------------------------------------------- 1 | $v) { 13 | if (!isset($config[$k])) { 14 | $config[$k] = $v; 15 | } 16 | } 17 | 18 | include dirname(__FILE__) . '/includes/common.php'; 19 | include dirname(__FILE__) . '/includes/CGMinerAPI.class.php'; 20 | include dirname(__FILE__) . '/includes/RPCClientApi.class.php'; 21 | 22 | function assertCmdExists($msg, $value, $success = 'OK', $error = 'ERROR') { 23 | assertTrue($msg, !empty($value) && isset($value[0]) && isset($value[0]['Exists']) && $value[0]['Exists'] === 'Y', $success = 'OK', $error = 'ERROR'); 24 | } 25 | 26 | function assertTrue($msg, $value, $success = 'OK', $error = 'ERROR') { 27 | log_console($msg . ': ' . (($value === true) ? $success : $error)); 28 | if ($value !== true) { 29 | log_console('Value: ' . var_export($value, true)); 30 | log_console('Please fix the error above'); 31 | die(); 32 | } 33 | } 34 | 35 | 36 | function assertOne($msg, $value, $success = 'OK', $error = 'ERROR') { 37 | assertTrue($msg, $value === 1, $success, $error); 38 | } 39 | function assertIsset($msg, $value, $key, $success = '', $error = 'ERROR') { 40 | 41 | if (!isset($value[$key])) { 42 | log_console($msg . ': ' . $error); 43 | log_console('Please fix the error above'); 44 | die(); 45 | } 46 | else { 47 | if (empty($success)) { 48 | $success = "OK value = " . $value[$key]; 49 | } 50 | log_console($msg . ': ' . $success); 51 | } 52 | } 53 | 54 | $rpc_api = new RPCClientApi($config); 55 | $miner_api = new CGMinerAPI($config['miner_api_ip'], $config['miner_api_port']); 56 | 57 | assertTrue('Check for provileged access', $miner_api->is_privileged()); 58 | 59 | 60 | $gpu_device_key_check = array 61 | ( 62 | 'GPU', 63 | 'Enabled', 64 | 'Status', 65 | 'Temperature', 66 | 'Fan Speed', 67 | 'Fan Percent', 68 | 'GPU Clock', 69 | 'Memory Clock', 70 | 'GPU Voltage', 71 | 'GPU Activity', 72 | #'Powertune', 73 | 'MHS av', 74 | 'MHS 5s', 75 | 'Accepted', 76 | 'Rejected', 77 | 'Hardware Errors', 78 | 'Utility', 79 | 'Intensity', 80 | 'Last Share Pool', 81 | #'Last Share Time', 82 | #'Total MH', 83 | #'Diff1 Work', 84 | #'Difficulty Accepted', 85 | #'Difficulty Rejected', 86 | #'Last Share Difficulty', 87 | #'Last Valid Work', 88 | #'Device Hardware%', 89 | #'Device Rejected%', 90 | #'Device Elapsed', 91 | ); 92 | 93 | $pool_key_check = Array 94 | ( 95 | 'POOL', 96 | 'URL', 97 | 'Status', 98 | 'Priority', 99 | 'Quota', 100 | #'Long Poll', 101 | #'Getworks', 102 | #'Accepted', 103 | #'Rejected', 104 | #'Works', 105 | #'Discarded', 106 | #'Stale', 107 | #'Get Failures', 108 | #'Remote Failures', 109 | #'User', 110 | #'Last Share Time', 111 | #'Diff1 Shares', 112 | #'Proxy Type', 113 | #'Proxy', 114 | #'Difficulty Accepted', 115 | #'Difficulty Rejected', 116 | #'Difficulty Stale', 117 | #'Last Share Difficulty', 118 | #'Has Stratum', 119 | #'Stratum Active', 120 | #'Stratum URL', 121 | #'Has GBT', 122 | #'Best Share', 123 | #'Pool Rejected%', 124 | #'Pool Stale%', 125 | ); 126 | 127 | $device_details_key_check = Array 128 | ( 129 | 'DEVDETAILS', 130 | 'Name', 131 | 'ID', 132 | #'Driver', 133 | 'Kernel', 134 | 'Model', 135 | #'Device Path', 136 | ); 137 | 138 | log_console(''); 139 | $devices = $miner_api->get_devices(); 140 | assertTrue("GPU's found", !empty($devices), count($devices) . ' found', 'ERROR: ' . count($devices) . ' found'); 141 | foreach ($devices AS $index => $gpu_details) { 142 | log_console(''); 143 | log_console('Verify GPU ' . ($index + 1)); 144 | log_console(''); 145 | log_console(' Verify response keys for command get_devices'); 146 | foreach ($gpu_device_key_check AS $key) { 147 | assertIsset(" Search for GPU " . $key, $gpu_details, $key); 148 | } 149 | 150 | $gpu = $miner_api->get_gpu($gpu_details['GPU']); 151 | log_console(''); 152 | assertTrue(' Check if get_gpu is valid', !empty($gpu) && isset($gpu[0]) && !empty($gpu[0])); 153 | $gpu = $gpu[0]; 154 | log_console(''); 155 | log_console(' Verify response keys for command get_gpu'); 156 | foreach ($gpu_device_key_check AS $key) { 157 | assertIsset(" Search for GPU " . $key, $gpu, $key); 158 | } 159 | 160 | log_console(''); 161 | assertOne(' Check set fan speed', $miner_api->set_gpufan($gpu_details['GPU'], $gpu_details['Fan Percent'])); 162 | usleep(500); 163 | assertOne(' Check set intensity', $miner_api->set_gpuintensity($gpu_details['GPU'], $gpu_details['Intensity'])); 164 | usleep(500); 165 | assertOne(' Check set voltage', $miner_api->set_gpuvddc($gpu_details['GPU'], $gpu_details['GPU Voltage'])); 166 | usleep(500); 167 | assertOne(' Check set memory clock', $miner_api->set_gpumem($gpu_details['GPU'], $gpu_details['Memory Clock'])); 168 | usleep(500); 169 | assertOne(' Check set engine clock', $miner_api->set_gpuengine($gpu_details['GPU'], $gpu_details['GPU Clock'])); 170 | usleep(500); 171 | assertOne(' Check gpu disable', $miner_api->gpudisable($gpu_details['GPU'])); 172 | usleep(500); 173 | assertOne(' Check gpu enable', $miner_api->gpuenable($gpu_details['GPU'])); 174 | usleep(500); 175 | log_console(''); 176 | 177 | 178 | } 179 | 180 | $device_details = $miner_api->get_devices_details(); 181 | assertTrue("Devices's found", !empty($device_details), count($device_details) . ' found', 'ERROR: ' . count($device_details) . ' found'); 182 | log_console(''); 183 | foreach ($device_details AS $index => $dev_details) { 184 | log_console('Verify device ' . ($index + 1)); 185 | foreach ($device_details_key_check AS $key) { 186 | assertIsset(" Search for device " . $key, $dev_details, $key); 187 | } 188 | } 189 | 190 | 191 | log_console(''); 192 | $pools = $miner_api->get_pools(); 193 | assertTrue("Pools's found", !empty($pools), count($pools) . ' found', 'ERROR: ' . count($pools) . ' found'); 194 | log_console(''); 195 | foreach ($pools AS $index => $pool_details) { 196 | log_console('Verify Pool ' . ($index + 1)); 197 | foreach ($pool_key_check AS $key) { 198 | assertIsset(" Search for Pool " . $key, $pool_details, $key); 199 | } 200 | } 201 | log_console(''); 202 | 203 | assertCmdExists("Check if command switchpool exists", $miner_api->check('switchpool')); 204 | assertCmdExists("Check if command removepool exists", $miner_api->check('removepool')); 205 | assertCmdExists("Check if command addpool exists", $miner_api->check('addpool')); 206 | assertOne("Check command zero", $miner_api->zero()); 207 | log_console('The given miner api is compatible with PHPMiner and fully functional'); 208 | -------------------------------------------------------------------------------- /scrypt130511Pitcairnglg2tc8128w256l8.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/scrypt130511Pitcairnglg2tc8128w256l8.bin -------------------------------------------------------------------------------- /templates/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule \.(php)$ - [R=404] -------------------------------------------------------------------------------- /templates/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/ajax-loader.gif -------------------------------------------------------------------------------- /templates/bootstrap/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "vars": {}, 3 | "css": [ 4 | "print.less", 5 | "type.less", 6 | "code.less", 7 | "grid.less", 8 | "tables.less", 9 | "forms.less", 10 | "buttons.less", 11 | "glyphicons.less", 12 | "button-groups.less", 13 | "input-groups.less", 14 | "navs.less", 15 | "navbar.less", 16 | "breadcrumbs.less", 17 | "pagination.less", 18 | "pager.less", 19 | "labels.less", 20 | "badges.less", 21 | "jumbotron.less", 22 | "thumbnails.less", 23 | "alerts.less", 24 | "progress-bars.less", 25 | "media.less", 26 | "list-group.less", 27 | "panels.less", 28 | "wells.less", 29 | "close.less", 30 | "dropdowns.less", 31 | "tooltip.less", 32 | "popovers.less", 33 | "modals.less", 34 | "carousel.less", 35 | "utilities.less", 36 | "responsive-utilities.less", 37 | "component-animations.less" 38 | ], 39 | "js": [ 40 | "alert.js", 41 | "button.js", 42 | "carousel.js", 43 | "dropdown.js", 44 | "modal.js", 45 | "tooltip.js", 46 | "popover.js", 47 | "tab.js", 48 | "affix.js", 49 | "collapse.js", 50 | "scrollspy.js", 51 | "transition.js" 52 | ] 53 | } -------------------------------------------------------------------------------- /templates/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /templates/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /templates/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /templates/css/OpenSans-CondensedBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/css/OpenSans-CondensedBold.woff -------------------------------------------------------------------------------- /templates/css/OpenSans-CondensedLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/css/OpenSans-CondensedLight.woff -------------------------------------------------------------------------------- /templates/css/OpenSans-CondensedLightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/css/OpenSans-CondensedLightItalic.woff -------------------------------------------------------------------------------- /templates/css/jquery.nouislider.css: -------------------------------------------------------------------------------- 1 | 2 | /* Functional styling; 3 | * These styles are required for noUiSlider to function. 4 | * You don't need to change these rules to apply your design. 5 | */ 6 | .noUi-target, 7 | .noUi-target * { 8 | -webkit-touch-callout: none; 9 | -webkit-user-select: none; 10 | -ms-touch-action: none; 11 | -ms-user-select: none; 12 | -moz-user-select: none; 13 | -moz-box-sizing: border-box; 14 | box-sizing: border-box; 15 | } 16 | .noUi-base { 17 | width: 100%; 18 | height: 100%; 19 | position: relative; 20 | } 21 | .noUi-origin { 22 | position: absolute; 23 | right: 0; 24 | top: 0; 25 | left: 0; 26 | bottom: 0; 27 | } 28 | .noUi-handle { 29 | position: relative; 30 | z-index: 1; 31 | } 32 | .noUi-stacking .noUi-handle { 33 | /* This class is applied to the lower origin when 34 | its values is > 50%. */ 35 | z-index: 10; 36 | } 37 | .noUi-stacking + .noUi-origin { 38 | /* Fix stacking order in IE7, which incorrectly 39 | creates a new context for the origins. */ 40 | *z-index: -1; 41 | } 42 | .noUi-state-tap .noUi-origin { 43 | -webkit-transition: left 0.3s, top 0.3s; 44 | transition: left 0.3s, top 0.3s; 45 | } 46 | .noUi-state-drag * { 47 | cursor: inherit !important; 48 | } 49 | 50 | /* Slider size and handle placement; 51 | */ 52 | .noUi-horizontal { 53 | height: 10px; 54 | } 55 | .noUi-horizontal .noUi-handle { 56 | width: 25px; 57 | height: 20px; 58 | left: -17px; 59 | top: -6px; 60 | } 61 | .noUi-horizontal.noUi-extended { 62 | padding: 0 15px; 63 | } 64 | .noUi-horizontal.noUi-extended .noUi-origin { 65 | right: -15px; 66 | } 67 | .noUi-vertical { 68 | width: 18px; 69 | } 70 | .noUi-vertical .noUi-handle { 71 | width: 28px; 72 | height: 34px; 73 | left: -6px; 74 | top: -17px; 75 | } 76 | .noUi-vertical.noUi-extended { 77 | padding: 15px 0; 78 | } 79 | .noUi-vertical.noUi-extended .noUi-origin { 80 | bottom: -15px; 81 | } 82 | 83 | /* Styling; 84 | */ 85 | .noUi-background { 86 | background: #FAFAFA; 87 | box-shadow: inset 0 1px 1px #f0f0f0; 88 | } 89 | .noUi-connect { 90 | background: #3FB8AF; 91 | box-shadow: inset 0 0 3px rgba(51,51,51,0.45); 92 | -webkit-transition: background 450ms; 93 | transition: background 450ms; 94 | } 95 | .noUi-origin { 96 | border-radius: 2px; 97 | } 98 | .noUi-target { 99 | border-radius: 4px; 100 | border: 1px solid #D3D3D3; 101 | box-shadow: inset 0 1px 1px #F0F0F0, 0 3px 6px -5px #BBB; 102 | margin-top: 13px; 103 | margin-left: 10px; 104 | margin-right: 10px; 105 | width: 70%; 106 | display: inline-block; 107 | } 108 | .noUi-target.noUi-connect { 109 | box-shadow: inset 0 0 3px rgba(51,51,51,0.45), 0 3px 6px -5px #BBB; 110 | } 111 | 112 | /* Handles and cursors; 113 | */ 114 | .noUi-dragable { 115 | cursor: w-resize; 116 | } 117 | .noUi-vertical .noUi-dragable { 118 | cursor: n-resize; 119 | } 120 | .noUi-handle { 121 | border: 1px solid #D9D9D9; 122 | border-radius: 3px; 123 | background: #FFF; 124 | cursor: pointer; 125 | } 126 | .noUi-active { 127 | box-shadow: inset 0 0 1px #FFF, 128 | inset 0 1px 7px #DDD, 129 | 0 3px 6px -3px #BBB; 130 | } 131 | 132 | /* Handle stripes; 133 | */ 134 | .noUi-handle:before, 135 | .noUi-handle:after { 136 | content: ""; 137 | display: block; 138 | position: absolute; 139 | height: 12px; 140 | width: 1px; 141 | background: #E8E7E6; 142 | left: 10px; 143 | top: 3px; 144 | } 145 | .noUi-handle:after { 146 | left: 13px; 147 | } 148 | .noUi-vertical .noUi-handle:before, 149 | .noUi-vertical .noUi-handle:after { 150 | width: 14px; 151 | height: 1px; 152 | left: 6px; 153 | top: 14px; 154 | } 155 | .noUi-vertical .noUi-handle:after { 156 | top: 17px; 157 | } 158 | 159 | /* Disabled state; 160 | */ 161 | [disabled].noUi-connect, 162 | [disabled] .noUi-connect { 163 | background: #B8B8B8; 164 | } 165 | [disabled] .noUi-handle { 166 | cursor: not-allowed; 167 | } 168 | 169 | /* Blocked state; 170 | */ 171 | .noUi-state-blocked.noUi-connect, 172 | .noUi-state-blocked .noUi-connect { 173 | background: #4FDACF; 174 | } 175 | -------------------------------------------------------------------------------- /templates/css/popup.css: -------------------------------------------------------------------------------- 1 | #popup_container { 2 | background: #FFF; 3 | border: solid 1px #999; 4 | box-shadow: 0px 0px 34px 0px #3C3C3C; 5 | color: #000; 6 | -moz-border-radius: 5px; 7 | -webkit-border-radius: 5px; 8 | border-radius: 5px; 9 | width: 400px; 10 | opacity: 0; 11 | } 12 | 13 | #popup_title { 14 | font-size: 14px; 15 | font-weight: bold; 16 | text-align: center; 17 | line-height: 1.75em; 18 | background: #9B2C17 linear-gradient(#D82121,#9B2C17); 19 | color: #FFF; 20 | border: solid 1px rgba(255, 255, 255, 0.74); 21 | border-bottom: solid 1px #999; 22 | cursor: default; 23 | border-top-left-radius: 5px; 24 | border-top-right-radius: 5px; 25 | padding: 0em; 26 | height: 28px; 27 | margin: 0em; 28 | } 29 | 30 | #popup_titletxt i { 31 | margin-right: 5px; 32 | } 33 | #popup_titletxt { 34 | text-align: left; 35 | width: 355px; 36 | padding: 0em; 37 | margin: 0em; 38 | padding-left: 5px; 39 | float: left; 40 | line-height: 28px; 41 | } 42 | #popup_cancel_corner { 43 | float: right; 44 | width: 30px; 45 | text-align: right; 46 | cursor: pointer; 47 | } 48 | 49 | #popup_cancel_corner:hover { 50 | color: #CFCFCF; 51 | } 52 | 53 | #popup_content { 54 | text-align: left; 55 | padding: 1em 1.75em; 56 | margin: 0em; 57 | clear: both; 58 | } 59 | 60 | div#popup_container input, 61 | div#popup_container textarea, 62 | div#popup_container select { 63 | width: auto; 64 | } 65 | 66 | #popup_panel { text-align: center; margin-top: 1em; } 67 | #popup_prompt { margin: .5em 0em; } 68 | -------------------------------------------------------------------------------- /templates/css/reset.css: -------------------------------------------------------------------------------- 1 | /* 2 | html5doctor.com Reset Stylesheet v1.6.1 3 | Last Updated: 2010-09-17 4 | Author: Richard Clark - http://richclarkdesign.com 5 | */ 6 | html, body, div, span, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | abbr, address, cite, code, 9 | del, dfn, em, img, ins, kbd, q, samp, 10 | small, strong, sub, sup, var, 11 | b, i, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, figcaption, figure, 16 | footer, header, hgroup, menu, nav, section, summary, 17 | time, mark, audio, video { 18 | margin:0; 19 | padding:0; 20 | border:0; 21 | outline:0; 22 | vertical-align:baseline; 23 | background:transparent; 24 | } 25 | body { 26 | line-height:1; 27 | } 28 | article,aside,details,figcaption,figure, 29 | footer,header,hgroup,menu,nav,section { 30 | display:block; 31 | } 32 | nav ul { 33 | list-style:none; 34 | } 35 | blockquote, q { 36 | quotes:none; 37 | } 38 | blockquote:before, blockquote:after, 39 | q:before, q:after { 40 | content:''; 41 | content:none; 42 | } 43 | a { 44 | margin:0; 45 | padding:0; 46 | font-size:100%; 47 | vertical-align:baseline; 48 | background:transparent; 49 | } 50 | /* change colours to suit your needs */ 51 | ins { 52 | background-color:#ff9; 53 | color:#000; 54 | text-decoration:none; 55 | } 56 | /* change colours to suit your needs */ 57 | mark { 58 | background-color:#ff9; 59 | color:#000; 60 | font-style:italic; 61 | font-weight:bold; 62 | } 63 | del { 64 | text-decoration: line-through; 65 | } 66 | abbr[title], dfn[title] { 67 | border-bottom:1px dotted; 68 | cursor:help; 69 | } 70 | table { 71 | border-collapse:collapse; 72 | border-spacing:0; 73 | } 74 | /* change border colour to suit your needs */ 75 | hr { 76 | display:block; 77 | height:1px; 78 | border:0; 79 | border-top:1px solid #cccccc; 80 | margin:1em 0; 81 | padding:0; 82 | } 83 | input, select { 84 | vertical-align:middle; 85 | } -------------------------------------------------------------------------------- /templates/css/status_box.css: -------------------------------------------------------------------------------- 1 | /* Default box */ 2 | .defaultBox { 3 | border-width: 1px; 4 | border-style: solid; 5 | border-color: black; 6 | margin: 0px auto; 7 | background-color: #FAFAFA; 8 | margin-bottom: 10px; 9 | color: #FFF; 10 | } 11 | 12 | .defaultBox ul { 13 | margin: 0px; 14 | } 15 | .defaultBox b { 16 | color: #FFF; 17 | } 18 | .defaultBox #description { 19 | padding: 7px; 20 | font-size: 15px; 21 | color: #FFF; 22 | } 23 | 24 | .defaultBox a { 25 | font-weight: bold; 26 | } 27 | 28 | .defaultBox ul li { 29 | margin-left: 30px; 30 | } 31 | 32 | .defaultBox_success #description { background: #3D800D linear-gradient(#3D800D,#34680E); } 33 | .defaultBox_success { border-color: green; } 34 | .defaultBox_success a { color: #0AFF00; } 35 | 36 | .defaultBox_error #description { background: #790000 linear-gradient(#790000,#630000); } 37 | .defaultBox_error { border-color: #CC0000; } 38 | .defaultBox_error a { color: #F00; } 39 | 40 | .defaultBox_info #description { background: #995C25 linear-gradient(#995C25,#A25006); } 41 | .defaultBox_info { border-color: #FFCC00; } 42 | .defaultBox_info a { color: #FFE000; } -------------------------------------------------------------------------------- /templates/fontello/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Font Awesome 5 | 6 | Copyright (C) 2012 by Dave Gandy 7 | 8 | Author: Dave Gandy 9 | License: SIL () 10 | Homepage: http://fortawesome.github.com/Font-Awesome/ 11 | 12 | 13 | ## Elusive 14 | 15 | Copyright (C) 2013 by Aristeides Stathopoulos 16 | 17 | Author: Aristeides Stathopoulos 18 | License: SIL (http://scripts.sil.org/OFL) 19 | Homepage: http://aristeides.com/ 20 | 21 | 22 | ## Entypo 23 | 24 | Copyright (C) 2012 by Daniel Bruce 25 | 26 | Author: Daniel Bruce 27 | License: CC BY-SA (http://creativecommons.org/licenses/by-sa/2.0/) 28 | Homepage: http://www.entypo.com 29 | 30 | 31 | ## MFG Labs 32 | 33 | Copyright (C) 2012 by Daniel Bruce 34 | 35 | Author: MFG Labs 36 | License: SIL (http://scripts.sil.org/OFL) 37 | Homepage: http://www.mfglabs.com/ 38 | 39 | 40 | -------------------------------------------------------------------------------- /templates/fontello/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by http://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licences, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publically available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require to make clickable links on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Comments on archive content 20 | --------------------------- 21 | 22 | - /font/* - fonts in different formats 23 | 24 | - /css/* - different kinds of css, for all situations. Should be ok with 25 | twitter bootstrap. Also, you can skip style and assign icon classes 26 | directly to text elements, if you don't mind about IE7. 27 | 28 | - demo.html - demo file, to show your webfont content 29 | 30 | - LICENSE.txt - license info about source fonts, used to build your one. 31 | 32 | - config.json - keeps your settings. You can import it back to fontello anytime, 33 | to continue your work 34 | 35 | 36 | Why so many CSS files ? 37 | ----------------------- 38 | 39 | Because we like to fit all your needs :) 40 | 41 | - basic file, .css - is usually enougth, in contains @font-face 42 | and character codes definition 43 | 44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes 45 | directly into html 46 | 47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face 48 | rules, but still wish to benefit of css generation. That can be very 49 | convenient for automated assets build systems. When you need to update font - 50 | no needs to manually edit files, just override old version with archive 51 | content. See fontello source codes for example. 52 | 53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid 54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. 55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` 56 | server headers. But if you ok with dirty hack - this file is for you. Note, 57 | that data url moved to separate @font-face to avoid problems with 2 | 3 | 4 | PHPMiner - Mine better 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | get_variable('cssfiles') AS $file): ?> 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | get_variable('jsfiles') AS $file): ?> 32 | 33 | 34 | 35 | has_variable('jsconfig')): ?> 36 | 40 | 41 | 42 | 43 | 44 |
45 | 65 |
66 |
67 |
68 | has_variable('messages')): ?> 69 | get_variable('messages') AS $type => $message_arrray): ?> 70 | 71 | 72 | 73 |
74 |
75 | fatal_error) && file_exists(SITEPATH . '/views/' . $this->controller_name . '/' . $this->action_name . '.tpl.php')): ?> 76 | controller_name . '/' . $this->action_name . '.tpl.php'; ?> 77 | 78 |
79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /templates/status_message.tpl.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | <?php echo 'Success'; ?> 7 | 8 | <?php echo 'Error'; ?> 9 | 10 | <?php echo 'Info'; ?> 11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 |
26 |
    27 | 28 |
  • 29 | 30 |
31 |
32 |
-------------------------------------------------------------------------------- /templates/x-editable/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Vitaliy Potapov 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /templates/x-editable/README.md: -------------------------------------------------------------------------------- 1 | # X-editable 2 | 3 | In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery. 4 | 5 | ## Live demo 6 | **http://vitalets.github.io/x-editable/demo.html** 7 | 8 | ## Documentation 9 | **http://vitalets.github.io/x-editable** 10 | 11 | ## How to get it 12 | 13 | ### Manual download 14 | Use **http://vitalets.github.io/x-editable** main page. 15 | 16 | ### Bower 17 | ```` 18 | bower install x-editable 19 | ```` 20 | 21 | ### CDN 22 | Bootstrap 3 build: 23 | ````js 24 | 25 | 26 | ```` 27 | 28 | Bootstrap 2 build: 29 | ````js 30 | 31 | 32 | ```` 33 | 34 | jQuery UI build: 35 | ````js 36 | 37 | 38 | ```` 39 | 40 | jQuery only build: 41 | ````js 42 | 43 | 44 | ```` 45 | 46 | 47 | ## Reporting issues 48 | Please **provide jsFiddle** when creating issues! 49 | It's really saves much time. Use these as template: 50 | 1. [jsFiddle Bootstrap 3](http://jsfiddle.net/xBB5x/2265/) 51 | 2. [jsFiddle Bootstrap 2](http://jsfiddle.net/xBB5x/1817/) 52 | 3. [jsFiddle jQuery-ui](http://jsfiddle.net/xBB5x/2511/) 53 | 4. [jsFiddle jQuery](http://jsfiddle.net/xBB5x/197) 54 | Your feedback is very appreciated! 55 | 56 | ## Contribution 57 | A few steps how to start contributing. 58 | Assuming you have [Node.js](http://nodejs.org/) already installed. 59 | 60 | 1.Fork *X-editable* on github and clone it to your local mashine: 61 | ```` 62 | git clone https://github.com//x-editable.git -b dev 63 | ```` 64 | 2.Install *grunt-cli* globally (if not yet): 65 | ```` 66 | npm i -g grunt-cli 67 | ```` 68 | 3.Install dependencies: 69 | ```` 70 | cd x-editable 71 | npm i 72 | ```` 73 | 4.Make your changes: 74 | ```` 75 | vim editable-form.js 76 | ```` 77 | 5.Write some tests for your changes: 78 | ```` 79 | vim /test/unit/*.js 80 | ```` 81 | 6.Run tests in cli: 82 | ```` 83 | grunt test 84 | ```` 85 | or directly in browser: 86 | ```` 87 | grunt server 88 | ```` 89 | and open http://127.0.0.1:8000/test 90 | By default test run on bootstrap 3 popup version, but you can test any other build: 91 | 92 | * bootstrap 3 93 | * popup: http://127.0.0.1:8000/test/?f=bootstrap3&c=popup 94 | * inline: http://127.0.0.1:8000/test/?f=bootstrap3&c=inline 95 | * bootstrap 2 96 | * popup: http://127.0.0.1:8000/test/?f=bootstrap2&c=popup 97 | * inline: http://127.0.0.1:8000/test/?f=bootstrap2&c=inline 98 | * jquery-ui 99 | * popup: http://127.0.0.1:8000/test/?f=jqueryui&c=popup 100 | * inline: http://127.0.0.1:8000/test/?f=jqueryui&c=inline 101 | * jquery + poshytip 102 | * popup: http://127.0.0.1:8000/test/?f=plain&c=popup 103 | * inline: http://127.0.0.1:8000/test/?f=plain&c=inline 104 | 105 | 7.Commit and push back on github: 106 | ```` 107 | git add . 108 | git commit -m'refactor editable form, fix #123' 109 | git push origin 110 | ```` 111 | 8.Make pull request on github (to `dev` branch). 112 | 113 | Thanks for your support! 114 | 115 | ### Local build 116 | To build x-editable locally please run: 117 | ```` 118 | grunt build 119 | ```` 120 | Result will appear in `dist` directory. 121 | 122 | ## License 123 | Copyright (c) 2012 Vitaliy Potapov 124 | Licensed under the MIT license. -------------------------------------------------------------------------------- /templates/x-editable/bootstrap3-editable/img/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/x-editable/bootstrap3-editable/img/clear.png -------------------------------------------------------------------------------- /templates/x-editable/bootstrap3-editable/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prdatur/phpminer/2cb2cf11c34c3e5aaee4c5314699cb295cdeeb8a/templates/x-editable/bootstrap3-editable/img/loading.gif -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/address/address.css: -------------------------------------------------------------------------------- 1 | .editable-address { 2 | display: block; 3 | margin-bottom: 5px; 4 | } 5 | 6 | .editable-address span { 7 | width: 70px; 8 | display: inline-block; 9 | } -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/address/address.js: -------------------------------------------------------------------------------- 1 | /** 2 | Address editable input. 3 | Internally value stored as {city: "Moscow", street: "Lenina", building: "15"} 4 | 5 | @class address 6 | @extends abstractinput 7 | @final 8 | @example 9 | awesome 10 | 23 | **/ 24 | (function ($) { 25 | "use strict"; 26 | 27 | var Address = function (options) { 28 | this.init('address', options, Address.defaults); 29 | }; 30 | 31 | //inherit from Abstract input 32 | $.fn.editableutils.inherit(Address, $.fn.editabletypes.abstractinput); 33 | 34 | $.extend(Address.prototype, { 35 | /** 36 | Renders input from tpl 37 | 38 | @method render() 39 | **/ 40 | render: function() { 41 | this.$input = this.$tpl.find('input'); 42 | }, 43 | 44 | /** 45 | Default method to show value in element. Can be overwritten by display option. 46 | 47 | @method value2html(value, element) 48 | **/ 49 | value2html: function(value, element) { 50 | if(!value) { 51 | $(element).empty(); 52 | return; 53 | } 54 | var html = $('
').text(value.city).html() + ', ' + $('
').text(value.street).html() + ' st., bld. ' + $('
').text(value.building).html(); 55 | $(element).html(html); 56 | }, 57 | 58 | /** 59 | Gets value from element's html 60 | 61 | @method html2value(html) 62 | **/ 63 | html2value: function(html) { 64 | /* 65 | you may write parsing method to get value by element's html 66 | e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"} 67 | but for complex structures it's not recommended. 68 | Better set value directly via javascript, e.g. 69 | editable({ 70 | value: { 71 | city: "Moscow", 72 | street: "Lenina", 73 | building: "15" 74 | } 75 | }); 76 | */ 77 | return null; 78 | }, 79 | 80 | /** 81 | Converts value to string. 82 | It is used in internal comparing (not for sending to server). 83 | 84 | @method value2str(value) 85 | **/ 86 | value2str: function(value) { 87 | var str = ''; 88 | if(value) { 89 | for(var k in value) { 90 | str = str + k + ':' + value[k] + ';'; 91 | } 92 | } 93 | return str; 94 | }, 95 | 96 | /* 97 | Converts string to value. Used for reading value from 'data-value' attribute. 98 | 99 | @method str2value(str) 100 | */ 101 | str2value: function(str) { 102 | /* 103 | this is mainly for parsing value defined in data-value attribute. 104 | If you will always set value by javascript, no need to overwrite it 105 | */ 106 | return str; 107 | }, 108 | 109 | /** 110 | Sets value of input. 111 | 112 | @method value2input(value) 113 | @param {mixed} value 114 | **/ 115 | value2input: function(value) { 116 | if(!value) { 117 | return; 118 | } 119 | this.$input.filter('[name="city"]').val(value.city); 120 | this.$input.filter('[name="street"]').val(value.street); 121 | this.$input.filter('[name="building"]').val(value.building); 122 | }, 123 | 124 | /** 125 | Returns value of input. 126 | 127 | @method input2value() 128 | **/ 129 | input2value: function() { 130 | return { 131 | city: this.$input.filter('[name="city"]').val(), 132 | street: this.$input.filter('[name="street"]').val(), 133 | building: this.$input.filter('[name="building"]').val() 134 | }; 135 | }, 136 | 137 | /** 138 | Activates input: sets focus on the first field. 139 | 140 | @method activate() 141 | **/ 142 | activate: function() { 143 | this.$input.filter('[name="city"]').focus(); 144 | }, 145 | 146 | /** 147 | Attaches handler to submit form in case of 'showbuttons=false' mode 148 | 149 | @method autosubmit() 150 | **/ 151 | autosubmit: function() { 152 | this.$input.keydown(function (e) { 153 | if (e.which === 13) { 154 | $(this).closest('form').submit(); 155 | } 156 | }); 157 | } 158 | }); 159 | 160 | Address.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 161 | tpl: '
'+ 162 | '
'+ 163 | '
', 164 | 165 | inputclass: '' 166 | }); 167 | 168 | $.fn.editabletypes.address = Address; 169 | 170 | }(window.jQuery)); -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/typeaheadjs/lib/typeahead.js-bootstrap.css: -------------------------------------------------------------------------------- 1 | .twitter-typeahead .tt-query, 2 | .twitter-typeahead .tt-hint { 3 | margin-bottom: 0; 4 | } 5 | 6 | .tt-dropdown-menu { 7 | min-width: 160px; 8 | margin-top: 2px; 9 | padding: 5px 0; 10 | background-color: #fff; 11 | border: 1px solid #ccc; 12 | border: 1px solid rgba(0,0,0,.2); 13 | *border-right-width: 2px; 14 | *border-bottom-width: 2px; 15 | -webkit-border-radius: 6px; 16 | -moz-border-radius: 6px; 17 | border-radius: 6px; 18 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 19 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 20 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 21 | -webkit-background-clip: padding-box; 22 | -moz-background-clip: padding; 23 | background-clip: padding-box; 24 | } 25 | 26 | .tt-suggestion { 27 | display: block; 28 | padding: 3px 20px; 29 | } 30 | 31 | .tt-suggestion.tt-is-under-cursor { 32 | color: #fff; 33 | background-color: #0081c2; 34 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 35 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 36 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 37 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 38 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 39 | background-repeat: repeat-x; 40 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0) 41 | } 42 | 43 | .tt-suggestion.tt-is-under-cursor a { 44 | color: #fff; 45 | } 46 | 47 | .tt-suggestion p { 48 | margin: 0; 49 | } 50 | -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/typeaheadjs/typeaheadjs.js: -------------------------------------------------------------------------------- 1 | /** 2 | Typeahead.js input, based on [Twitter Typeahead](http://twitter.github.io/typeahead.js). 3 | It is mainly replacement of typeahead in Bootstrap 3. 4 | 5 | 6 | @class typeaheadjs 7 | @extends text 8 | @since 1.5.0 9 | @final 10 | @example 11 | 12 | 30 | **/ 31 | (function ($) { 32 | "use strict"; 33 | 34 | var Constructor = function (options) { 35 | this.init('typeaheadjs', options, Constructor.defaults); 36 | }; 37 | 38 | $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.text); 39 | 40 | $.extend(Constructor.prototype, { 41 | render: function() { 42 | this.renderClear(); 43 | this.setClass(); 44 | this.setAttr('placeholder'); 45 | this.$input.typeahead(this.options.typeahead); 46 | 47 | // copy `input-sm | input-lg` classes to placeholder input 48 | if($.fn.editableform.engine === 'bs3') { 49 | if(this.$input.hasClass('input-sm')) { 50 | this.$input.siblings('input.tt-hint').addClass('input-sm'); 51 | } 52 | if(this.$input.hasClass('input-lg')) { 53 | this.$input.siblings('input.tt-hint').addClass('input-lg'); 54 | } 55 | } 56 | } 57 | }); 58 | 59 | Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, { 60 | /** 61 | @property tpl 62 | @default 63 | **/ 64 | tpl:'', 65 | /** 66 | Configuration of typeahead itself. 67 | [Full list of options](https://github.com/twitter/typeahead.js#dataset). 68 | 69 | @property typeahead 70 | @type object 71 | @default null 72 | **/ 73 | typeahead: null, 74 | /** 75 | Whether to show `clear` button 76 | 77 | @property clear 78 | @type boolean 79 | @default true 80 | **/ 81 | clear: true 82 | }); 83 | 84 | $.fn.editabletypes.typeaheadjs = Constructor; 85 | 86 | }(window.jQuery)); -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css: -------------------------------------------------------------------------------- 1 | ul.wysihtml5-toolbar { 2 | margin: 0; 3 | padding: 0; 4 | display: block; 5 | } 6 | 7 | ul.wysihtml5-toolbar::after { 8 | clear: both; 9 | display: table; 10 | content: ""; 11 | } 12 | 13 | ul.wysihtml5-toolbar > li { 14 | float: left; 15 | display: list-item; 16 | list-style: none; 17 | margin: 0 5px 10px 0; 18 | } 19 | 20 | ul.wysihtml5-toolbar a[data-wysihtml5-command=bold] { 21 | font-weight: bold; 22 | } 23 | 24 | ul.wysihtml5-toolbar a[data-wysihtml5-command=italic] { 25 | font-style: italic; 26 | } 27 | 28 | ul.wysihtml5-toolbar a[data-wysihtml5-command=underline] { 29 | text-decoration: underline; 30 | } 31 | 32 | ul.wysihtml5-toolbar a.btn.wysihtml5-command-active { 33 | background-image: none; 34 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 35 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 36 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 37 | background-color: #E6E6E6; 38 | background-color: #D9D9D9; 39 | outline: 0; 40 | } 41 | 42 | ul.wysihtml5-commands-disabled .dropdown-menu { 43 | display: none !important; 44 | } 45 | 46 | ul.wysihtml5-toolbar div.wysihtml5-colors { 47 | display:block; 48 | width: 50px; 49 | height: 20px; 50 | margin-top: 2px; 51 | margin-left: 5px; 52 | position: absolute; 53 | pointer-events: none; 54 | } 55 | 56 | ul.wysihtml5-toolbar a.wysihtml5-colors-title { 57 | padding-left: 70px; 58 | } 59 | 60 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="black"] { 61 | background: black !important; 62 | } 63 | 64 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="silver"] { 65 | background: silver !important; 66 | } 67 | 68 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="gray"] { 69 | background: gray !important; 70 | } 71 | 72 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="maroon"] { 73 | background: maroon !important; 74 | } 75 | 76 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="red"] { 77 | background: red !important; 78 | } 79 | 80 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="purple"] { 81 | background: purple !important; 82 | } 83 | 84 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="green"] { 85 | background: green !important; 86 | } 87 | 88 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="olive"] { 89 | background: olive !important; 90 | } 91 | 92 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="navy"] { 93 | background: navy !important; 94 | } 95 | 96 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="blue"] { 97 | background: blue !important; 98 | } 99 | 100 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="orange"] { 101 | background: orange !important; 102 | } 103 | -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/wysiwyg-color.css: -------------------------------------------------------------------------------- 1 | .wysiwyg-color-black { 2 | color: black; 3 | } 4 | 5 | .wysiwyg-color-silver { 6 | color: silver; 7 | } 8 | 9 | .wysiwyg-color-gray { 10 | color: gray; 11 | } 12 | 13 | .wysiwyg-color-white { 14 | color: white; 15 | } 16 | 17 | .wysiwyg-color-maroon { 18 | color: maroon; 19 | } 20 | 21 | .wysiwyg-color-red { 22 | color: red; 23 | } 24 | 25 | .wysiwyg-color-purple { 26 | color: purple; 27 | } 28 | 29 | .wysiwyg-color-fuchsia { 30 | color: fuchsia; 31 | } 32 | 33 | .wysiwyg-color-green { 34 | color: green; 35 | } 36 | 37 | .wysiwyg-color-lime { 38 | color: lime; 39 | } 40 | 41 | .wysiwyg-color-olive { 42 | color: olive; 43 | } 44 | 45 | .wysiwyg-color-yellow { 46 | color: yellow; 47 | } 48 | 49 | .wysiwyg-color-navy { 50 | color: navy; 51 | } 52 | 53 | .wysiwyg-color-blue { 54 | color: blue; 55 | } 56 | 57 | .wysiwyg-color-teal { 58 | color: teal; 59 | } 60 | 61 | .wysiwyg-color-aqua { 62 | color: aqua; 63 | } 64 | 65 | .wysiwyg-color-orange { 66 | color: orange; 67 | } -------------------------------------------------------------------------------- /templates/x-editable/inputs-ext/wysihtml5/wysihtml5.js: -------------------------------------------------------------------------------- 1 | /** 2 | Bootstrap wysihtml5 editor. Based on [bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5). 3 | You should include **manually** distributives of `wysihtml5` and `bootstrap-wysihtml5`: 4 | 5 | 6 | 7 | 8 | 9 | And also include `wysihtml5.js` from `inputs-ext` directory of x-editable: 10 | 11 | 12 | 13 | **Note:** It's better to use fresh bootstrap-wysihtml5 from it's [master branch](https://github.com/jhollingworth/bootstrap-wysihtml5/tree/master/src) as there is update for correct image insertion. 14 | 15 | @class wysihtml5 16 | @extends abstractinput 17 | @final 18 | @since 1.4.0 19 | @example 20 |

awesome

comment!
21 | 29 | **/ 30 | (function ($) { 31 | "use strict"; 32 | 33 | var Wysihtml5 = function (options) { 34 | this.init('wysihtml5', options, Wysihtml5.defaults); 35 | 36 | //extend wysihtml5 manually as $.extend not recursive 37 | this.options.wysihtml5 = $.extend({}, Wysihtml5.defaults.wysihtml5, options.wysihtml5); 38 | }; 39 | 40 | $.fn.editableutils.inherit(Wysihtml5, $.fn.editabletypes.abstractinput); 41 | 42 | $.extend(Wysihtml5.prototype, { 43 | render: function () { 44 | var deferred = $.Deferred(), 45 | msieOld; 46 | 47 | //generate unique id as it required for wysihtml5 48 | this.$input.attr('id', 'textarea_'+(new Date()).getTime()); 49 | 50 | this.setClass(); 51 | this.setAttr('placeholder'); 52 | 53 | //resolve deffered when widget loaded 54 | $.extend(this.options.wysihtml5, { 55 | events: { 56 | load: function() { 57 | deferred.resolve(); 58 | } 59 | } 60 | }); 61 | 62 | this.$input.wysihtml5(this.options.wysihtml5); 63 | 64 | /* 65 | In IE8 wysihtml5 iframe stays on the same line with buttons toolbar (inside popover). 66 | The only solution I found is to add
. If you fine better way, please send PR. 67 | */ 68 | msieOld = /msie\s*(8|7|6)/.test(navigator.userAgent.toLowerCase()); 69 | if(msieOld) { 70 | this.$input.before('

'); 71 | } 72 | 73 | return deferred.promise(); 74 | }, 75 | 76 | value2html: function(value, element) { 77 | $(element).html(value); 78 | }, 79 | 80 | html2value: function(html) { 81 | return html; 82 | }, 83 | 84 | value2input: function(value) { 85 | this.$input.data("wysihtml5").editor.setValue(value, true); 86 | }, 87 | 88 | activate: function() { 89 | this.$input.data("wysihtml5").editor.focus(); 90 | }, 91 | 92 | isEmpty: function($element) { 93 | if($.trim($element.html()) === '') { 94 | return true; 95 | } else if($.trim($element.text()) !== '') { 96 | return false; 97 | } else { 98 | //e.g. '', '
', '

' 99 | return !$element.height() || !$element.width(); 100 | } 101 | } 102 | }); 103 | 104 | Wysihtml5.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 105 | /** 106 | @property tpl 107 | @default 108 | **/ 109 | tpl:'', 110 | /** 111 | @property inputclass 112 | @default editable-wysihtml5 113 | **/ 114 | inputclass: 'editable-wysihtml5', 115 | /** 116 | Placeholder attribute of input. Shown when input is empty. 117 | 118 | @property placeholder 119 | @type string 120 | @default null 121 | **/ 122 | placeholder: null, 123 | /** 124 | Wysihtml5 default options. 125 | See https://github.com/jhollingworth/bootstrap-wysihtml5#options 126 | 127 | @property wysihtml5 128 | @type object 129 | @default {stylesheets: false} 130 | **/ 131 | wysihtml5: { 132 | stylesheets: false //see https://github.com/jhollingworth/bootstrap-wysihtml5/issues/183 133 | } 134 | }); 135 | 136 | $.fn.editabletypes.wysihtml5 = Wysihtml5; 137 | 138 | }(window.jQuery)); 139 | -------------------------------------------------------------------------------- /views/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | RewriteRule \.(php)$ - [R=404] -------------------------------------------------------------------------------- /views/access/index.css: -------------------------------------------------------------------------------- 1 | .add_user_form label { 2 | width: 120px; 3 | } 4 | .add_user_form input { 5 | width: 300px; 6 | } 7 | .add_group_form label { 8 | width: 200px; 9 | } 10 | 11 | .permission_checkbox { 12 | max-height: 350px; 13 | overflow-x: hidden; 14 | overflow-y: auto; 15 | } 16 | 17 | .add_group_form.simpleform .form-element { 18 | margin-top: 0px; 19 | margin-bottom: 0px; 20 | } 21 | .add_group_form.simpleform .form-element:nth-child(even) { 22 | background-color: #F0F0F0; 23 | } 24 | 25 | .add_group_form.simpleform .form-element label { 26 | margin: 0px; 27 | } -------------------------------------------------------------------------------- /views/access/index.tpl.php: -------------------------------------------------------------------------------- 1 |

Users/Groups

2 |
3 | 4 |
5 |
Add new user


6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
UsernameOptions
15 |
16 |
17 |
Add new access group


18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
NameOptions
27 |
28 |
29 | -------------------------------------------------------------------------------- /views/access/user_add.tpl.php: -------------------------------------------------------------------------------- 1 | Add a new user 2 | 2 | PHPMiner could not find a group where the same pools are configurated as currently in CGMiner/SGMiner, so you have to create a pool where this match.

3 | You have the following possibilities:
4 | - You can delete a non-active pool from CGMiner/SGMiner
5 | - You can add a pool to CGMiner/SGMiner which is only within the selected group.
6 | - You can delete a pool within the selected group which is not configurated within CGMiner/SGMiner.
7 | - You can add a pool within the selected group which is configurated within CGMiner/SGMiner but no in the group.
8 |
9 |
10 | 11 | The result must be, that in both systems (CGMiner/SGMiner and group) the same pools exist. The order is NOT important.
12 | You can proceed if all pool entries have a green background.
13 |

14 | CGMiner/SGMiner configurated pools: 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | get_variable('cgminer_pools') AS $pool): ?> 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
UrlUsernameoptions
Add to group - Remove from CGMiner/SGMiner
33 |
34 | Group configurated pools: - Search for best match 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
UrlUsernameoptions
You didn't selected a group yet, or this group does not have any pools configurated.
54 | -------------------------------------------------------------------------------- /views/main/init.css: -------------------------------------------------------------------------------- 1 | 2 | table:not(.layout_table).device_list td.enabled { 3 | background: #007E05 linear-gradient(#07A714, #007E05); 4 | 5 | } 6 | 7 | @-moz-keyframes blink { 8 | from { background: #A70707 ; color: #FFF; } 9 | to { background: #F5F5F5 ; color: #3F3F3F; } 10 | } 11 | @-webkit-keyframes blink { 12 | from { background: #A70707 ; color: #FFF; } 13 | to { background: #F5F5F5 ; color: #3F3F3F; } 14 | } 15 | @-o-keyframes blink { 16 | from { background: #A70707 ; color: #FFF; } 17 | to { background: #F5F5F5 ; color: #3F3F3F; } 18 | } 19 | @-ms-keyframes blink { 20 | from { background: #A70707 ; color: #FFF; } 21 | to { background: #F5F5F5 ; color: #3F3F3F; } 22 | } 23 | @keyframes blink { 24 | from { background: #A70707 ; color: #FFF; } 25 | to { background: #F5F5F5 ; color: #3F3F3F; } 26 | } 27 | 28 | table:not(.layout_table).device_list td.disabled { 29 | background: #A70707 linear-gradient(#A70707, #7E0000); 30 | animation: blink 2s step-end infinite; 31 | -moz-animation: blink 2s step-end infinite; 32 | -o-animation: blink 2s step-end infinite; 33 | -webkit-animation: blink 2s infinite; 34 | color: #FFF; 35 | } 36 | 37 | 38 | .device_list td.enabled .icon-check, 39 | .device_list td.disabled .icon-cancel, 40 | .device_list td.invalid .icon-cancel, 41 | .device_list td.invalid .icon-attention, 42 | .device_list td.clickable:hover .icon-check { 43 | color: #FFF; 44 | } 45 | 46 | .device_list .icon-check { 47 | color: #208102; 48 | } 49 | 50 | .device_list .icon-cancel { 51 | color: #DD0000; 52 | } 53 | 54 | .modal .form-element .unit { 55 | margin-left: 10px; 56 | } 57 | 58 | .remove_pool { 59 | margin-left: 10px; 60 | } 61 | 62 | .pool_switching_container { 63 | display: block; 64 | } 65 | 66 | .pool_switching_container.hidden { 67 | display: none; 68 | } 69 | .pool_switching_container label { 70 | margin-top: 3px; 71 | float: right; 72 | margin-left: 10px; 73 | } 74 | .pool_switching_container select { 75 | margin-bottom: 5px; 76 | padding: 2px 5px; 77 | float: right; 78 | } 79 | 80 | select.custom_commands { 81 | margin-bottom: 5px; 82 | padding: 2px 5px; 83 | margin-left: 10px; 84 | } 85 | 86 | 87 | .rig { 88 | padding: 10px; 89 | border: 1px solid #A5A5A5; 90 | box-shadow: 0px 0px 15px 0px #BEBEBE; 91 | border-radius: 5px; 92 | margin-bottom: 20px; 93 | background: #EEE9E2; 94 | } 95 | 96 | .rig_btn { 97 | display: inline-block; 98 | vertical-align: text-bottom; 99 | margin-left: 15px; 100 | cursor: pointer; 101 | } 102 | 103 | .device_list th { 104 | white-space: nowrap; 105 | } 106 | 107 | .rig_hashrate { 108 | margin-left: 30px; 109 | } 110 | 111 | .swap_rig { 112 | cursor: pointer; 113 | } 114 | 115 | div.rig > div.rig_header { 116 | float: left; 117 | } 118 | div.rig > div > h2 { 119 | display: inline; 120 | } -------------------------------------------------------------------------------- /views/main/init.tpl.php: -------------------------------------------------------------------------------- 1 | get_variable('config'); ?> 2 | 3 |
Add a new rig
4 |
5 | 6 | 7 |
12 |
13 | 14 | 15 |
Reset all rig stats
16 |
17 |
18 |
-------------------------------------------------------------------------------- /views/main/settings.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | table.config_table td.key { 4 | padding: 0px 0px 0px 10px; 5 | } 6 | 7 | table.config_table td.value { 8 | padding: 0px; 9 | } 10 | 11 | table.config_table td.value input { 12 | margin: 0px; 13 | width: 100%; 14 | } 15 | 16 | table.config_table td { 17 | vertical-align: middle; 18 | } 19 | 20 | table.config_table td label { 21 | margin-bottom: 0px; 22 | font-weight: normal; 23 | } -------------------------------------------------------------------------------- /views/main/settings.js: -------------------------------------------------------------------------------- 1 | Soopfw.behaviors.main_settings = function() { 2 | if (phpminer.settings.rigs !== undefined) { 3 | $.each(phpminer.settings.rigs, function(rig, rig_data) { 4 | var configs_to_add = $.extend({}, phpminer.settings.possible_configs); 5 | 6 | if (rig_data.cgminer_conf === undefined) { 7 | rig_data.cgminer_conf = {}; 8 | } 9 | 10 | $.each(rig_data.cgminer_conf, function(k, v) { 11 | if (k === 'pools' || phpminer.settings.possible_configs[k] === undefined) { 12 | return; 13 | } 14 | delete configs_to_add[k]; 15 | add_config(rig, k, v); 16 | }); 17 | 18 | $.each(configs_to_add, function(k, v) { 19 | $('.add_config_key[data-rig="' + rig + '"]').append(''); 20 | }); 21 | 22 | $('.add_config_key[data-rig="' + rig + '"]').change(function() { 23 | var key = $(this).val(); 24 | $(this).val(""); 25 | if(phpminer.settings.possible_configs[key] !== undefined) { 26 | add_config(rig, key); 27 | $('option[value="' + key + '"]', this).remove(); 28 | $('*[data-toggle="tooltip"]').tooltip(); 29 | } 30 | 31 | }); 32 | }); 33 | } 34 | $('#save_config').off('click').on('click', function() { 35 | var values = {}; 36 | $('input, select', $('#system_settings')).each(function() { 37 | if ($(this).attr('type') === 'checkbox') { 38 | values[$(this).attr('name')] = ($(this).prop('checked')) ? $(this).val() : '0'; 39 | } 40 | else { 41 | values[$(this).attr('name')] = $(this).val(); 42 | } 43 | }); 44 | ajax_request(murl('main', 'save_settings'), {settings: values}, function(result) { 45 | if (result !== undefined && result !== null && result['url'] !== undefined) { 46 | Soopfw.location(result.url); 47 | } 48 | else { 49 | success_alert('Configuration saved successfully.'); 50 | } 51 | }); 52 | }); 53 | 54 | $('.save_cgminer_config').off('click').on('click', function() { 55 | var values = {}; 56 | $('input', $('#cgminer_settings')).each(function() { 57 | values[$(this).attr('name')] = $(this).val(); 58 | }); 59 | 60 | var values = {}; 61 | $('.rig_data').each(function() { 62 | var rig = $(this).data('tab_title'); 63 | values[rig] = {}; 64 | $('input, select', $('.cgminer_settings[data-rig="' + rig + '"] tbody')).each(function() { 65 | if ($(this).attr('type') === 'checkbox') { 66 | values[rig][$(this).attr('name')] = ($(this).prop('checked')) ? $(this).val() : '0'; 67 | } 68 | else { 69 | values[rig][$(this).attr('name')] = $(this).val(); 70 | } 71 | }); 72 | }); 73 | wait_dialog() 74 | ajax_request(murl('main', 'save_cgminer_settings'), {settings: values}, function() { 75 | success_alert('Configuration saved successfully.'); 76 | }); 77 | }); 78 | 79 | $('.tabs').each(function() { 80 | 81 | var tab_headers = $('